Commit c6a51979 authored by Marco Mariani's avatar Marco Mariani

Merge branch 'master' into zimbra

parents 0bc71b45 453b3265
Changes
=======
0.78.1 (2013-05-31)
-------------------
* Fix slapos.cookbook:request: Add backward compatiblity about getInstanceGuid(). [Cedric de Saint Martin]
* slapos.cookbook:check_* promises: Add timeout to curl that is not otherwise killed by slapos promise subsystem. [Cedric de Saint Martin]
* Add boinc recipe: Allow to deploy an empty BOINC project. [Alain Takoudjou]
* Add boinc.app recipe: Allow to deploy and update a BOINC application into existing BOINC server instance . [Alain Takoudjou]
* Add boinc.client recipe: Allow to deploy a BOINC Client instance on SlapOS. [Alain Takoudjou]
* Add condor recipe: Allow to deploy Condor Manager or Condor worker instance on SlapOS. [Alain Takoudjou]
* Add condor.submit recipe: Allow to deploy or update application into existing Condor Manager instance. [Alain Takoudjou]
* Add redis.server recipe: Allow to deploy Redis server. [Alain Takoudjou]
* Add trac recipe: for deploying Trac and manage project with support of SVN and GIT. [Alain Takoudjou]
* Add bonjourgrid recipe: for deploying BonjourGrid Master and submit BOINC or Condor project. [Alain Takoudjou]
* Add bonjourgrid.client recipe: for deploying BonjourGrid Worker instance and execute BOINC or Condor Jobs. [Alain Takoudjou]
* Cloudooo: Allow any environment variables. [Yusei Tahara]
* ERP5: disable MariaDB query cache completely by 'query_cache_type = 0' for ERP5. [Kazuhiko Shiozaki]
* ERP5: enable haproxy admin socket and install haproxyctl script. [Kazuhiko Shiozaki]
* ERP5: increase the maximum number of open file descriptors before starting mysqld. [Kazuhiko Shiozaki]
0.78.0 (2013-04-28)
-------------------
* LAMP stack: Allow to give application-dependent parameters to application configuration file. [Cedric de Saint Martin]
* zabbix-agent: Allow user to pass zabbix parameter. [Cedric de Saint Martin]
* kvm frontend: listen to ipv6 and ipv4. [Jean-Baptiste Petre]
0.77.1 (2013-04-18)
-------------------
......
[buildout]
extends =
../apache/buildout.cfg
../python-2.7/buildout.cfg
../bzip2/buildout.cfg
../gdbm/buildout.cfg
../gettext/buildout.cfg
../libexpat/buildout.cfg
../ncurses/buildout.cfg
../openssl/buildout.cfg
../readline/buildout.cfg
../sqlite3/buildout.cfg
../zlib/buildout.cfg
../file/buildout.cfg
parts =
apache-wsgi
[python2.7]
configure-options =
--enable-shared
--disable-static
--enable-ipv6
--enable-unicode=ucs4
--with-system-expat
--with-threads
environment =
CPPFLAGS=-I${zlib:location}/include -I${readline:location}/include -I${libexpat:location}/include -I${ncurses:location}/include -I${ncurses:location}/include/ncursesw -I${bzip2:location}/include -I${gdbm:location}/include -I${openssl:location}/include -I${sqlite3:location}/include -I${gettext:location}/include
LDFLAGS=-L${zlib:location}/lib -L${readline:location}/lib -L${libexpat:location}/lib -L${ncurses:location}/lib -L${bzip2:location}/lib -L${gdbm:location}/lib -L${openssl:location}/lib -L${sqlite3:location}/lib -Wl,-rpath=${zlib:location}/lib -Wl,-rpath=${readline:location}/lib -Wl,-rpath=${libexpat:location}/lib -Wl,-rpath=${ncurses:location}/lib -Wl,-rpath=${bzip2:location}/lib -Wl,-rpath=${gdbm:location}/lib -Wl,-rpath=${openssl:location}/lib -Wl,-rpath=${sqlite3:location}/lib -L${gettext:location}/lib -Wl,-rpath=${gettext:location}/lib -Wl,-rpath=${file:location}/lib
LD_RUN_PATH=${buildout:parts-directory}/${:_buildout_section_name_}/lib
[apache-wsgi]
recipe = hexagonit.recipe.cmmi
url = http://modwsgi.googlecode.com/files/mod_wsgi-3.4.tar.gz
md5sum = f42d69190ea0c337ef259cbe8d94d985
configure-options =
--with-apxs=${apache:location}/bin/apxs
--with-python=${python2.7:location}/bin/python2.7
environment =
CPPFLAGS = -I${python2.7:location}/include/python2.7
LDFLAGS = -L${python2.7:location}/lib
......@@ -15,11 +15,18 @@ stop-on-error = yes
[aspell]
recipe = slapos.recipe.cmmi
revision = 1
url = http://ftp.gnu.org/gnu/aspell/aspell-0.60.6.1.tar.gz
md5sum = e66a9c9af6a60dc46134fdacf6ce97d7
environment =
CPPFLAGS=-I${ncurses:location}/include
LDFLAGS=-L${ncurses:location}/lib -Wl,-rpath=${ncurses:location}/lib
[aspell-en-dictionary]
recipe = slapos.recipe.cmmi
url = ftp://ftp.gnu.org/gnu/aspell/dict/en/aspell6-en-7.1-0.tar.bz2
md5sum = beba5e8f3afd3ed1644653bb685b2dfb
configure-command = ./configure --vars ASPELL=${aspell:location}/bin/aspell PREZIP=${aspell:location}/bin/prezip-bin
depends =
${aspell:url}
${aspell:revision}
--- a/client/scripts/Makefile.am 2012-08-24 12:11:10.400291229 +0200
+++ b/client/scripts/Makefile.am 2012-09-10 15:21:01.973773228 +0200
@@ -2,16 +2,16 @@
install-exec-hook:
chmod +x boinc-client
- $(INSTALL) -d $(DESTDIR)/etc/init.d
- $(INSTALL) -b boinc-client $(DESTDIR)/etc/init.d/boinc-client
+ $(INSTALL) -d $(DESTDIR)$(exec_prefix)/etc/init.d
+ $(INSTALL) -b boinc-client $(DESTDIR)$(exec_prefix)/etc/init.d/boinc-client
if [ -d /etc/sysconfig ] ; then \
- $(INSTALL) -d $(DESTDIR)/etc/sysconfig ; \
- $(INSTALL) boinc-client.conf $(DESTDIR)/etc/sysconfig/boinc-client ; \
+ $(INSTALL) -d $(DESTDIR)$(exec_prefix)/etc/sysconfig ; \
+ $(INSTALL) boinc-client.conf $(DESTDIR)$(exec_prefix)/etc/sysconfig/boinc-client ; \
elif [ -d /etc/default ] ; then \
- $(INSTALL) -d $(DESTDIR)/etc/default ; \
- $(INSTALL) boinc-client.conf $(DESTDIR)/etc/default/boinc-client ; \
+ $(INSTALL) -d $(DESTDIR)$(exec_prefix)/etc/default ; \
+ $(INSTALL) boinc-client.conf $(DESTDIR)$(exec_prefix)/etc/default/boinc-client ; \
else \
- $(INSTALL) -d $(DESTDIR)/etc ; \
- $(INSTALL) boinc-client.conf $(DESTDIR)/etc/boinc-client.conf ; \
+ $(INSTALL) -d $(DESTDIR)$(exec_prefix)/etc ; \
+ $(INSTALL) boinc-client.conf $(DESTDIR)$(exec_prefix)/etc/boinc-client.conf ; \
fi
\ No newline at end of file
[buildout]
parts =
boinc
extends =
../curl/buildout.cfg
../openssl/buildout.cfg
../zlib/buildout.cfg
../subversion/buildout.cfg
../m4/buildout.cfg
../automake/buildout.cfg
../libtool/buildout.cfg
../pkgconfig/buildout.cfg
../openldap/buildout.cfg
../gnutls/buildout.cfg
../../stack/slapos.cfg
[download-boinc]
recipe = slapos.recipe.download
url = http://boinc.berkeley.edu/dl/boinc_7.0.28_x86_64-pc-linux-gnu.sh
md5sum = efdfd115ae69227ceb6118ca09777988
location = ${buildout:parts-directory}/${:_buildout_section_name_}
filename = boinc_7.0.28_x86_64-pc-linux-gnu.sh
mode = 0744
[boinc-bin]
recipe = plone.recipe.command
on_install = true
on_update = true
command = cp ${download-boinc:location}/${download-boinc:filename} ${buildout:parts-directory} && \
cd ${buildout:parts-directory} && \
./${download-boinc:filename}
#boinc client is a binary: write LD_LABRARY_PATH
ld_library = ${curl:location}/lib:${openssl:location}/lib:${zlib:location}/lib
location = ${buildout:parts-directory}/BOINC
[boinc-patch]
recipe = slapos.recipe.download
url = ${:_profile_base_location_}/boinc-abs-path.patch
md5sum = 412acedfbcdc8a9a7f196a02465da248
location = ${buildout:parts-directory}/${:_buildout_section_name_}
filename = boinc-abs-path.patch
#checkout boinc package from svn repository
[boinc-package]
recipe = plone.recipe.command
location = ${buildout:parts-directory}/${:_buildout_section_name_}
tarball = ${buildout:parts-directory}/boinc.tar.gz
svnversion = ${subversion:location}/bin/svnversion
command = ${subversion:location}/bin/svn co --revision 26162 http://boinc.berkeley.edu/svn/branches/server_stable ${:location} && \
sed -i 's#/usr/bin/svnversion#${:svnversion}#' ${:location}/tools/make_project && \
cd ${:location} && rm -f ${:tarball} && tar -cvzf ${:tarball} .
update-command =
# Compile now boinc client
[boinc]
recipe = slapos.recipe.cmmi
url = ${boinc-package:tarball}
configure-command =
echo 'AC_PROG_OBJCXX' >> configure.ac
aclocal -I${pkgconfig:location}/share/aclocal -I${libtool:location}/share/aclocal
./_autosetup
./configure
configure-options =
--prefix=${buildout:parts-directory}/${:_buildout_section_name_}
--disable-fcgi
--disable-shared
--enable-static
--with-pic
--disable-manager
--disable-server
--with-pkg-config
--with-ssl=${openssl:location}
--with-libldap=${openldap:location}/lib
--with-libgnutls=${gnutls:location}/lib
--with-libcurl=${curl:location}/lib
--with-x=no
patches =
${boinc-patch:location}/${boinc-patch:filename}
patch-options = -p1
environment =
PATH=${pkgconfig:location}/bin:${automake:location}/bin:${autoconf:location}/bin:${libtool:location}/bin:${subversion:location}/bin:${curl:location}/bin:%(PATH)s
PKG_CONFIG_PATH=${openssl:location}/lib/pkgconfig
M4=${m4:location}/bin/m4
CFLAGS=-fPIC
CPPFLAGS=-I${openssl:location}/include -I${zlib:location}/include
LDFLAGS = -L${openssl:location}/lib -Wl,-rpath=${openssl:location}/lib -L${zlib:location}/lib -Wl,-rpath=${zlib:location}/lib
ACLOCAL_PATH=${pkgconfig:location}/share/aclocal:${libtool:location}/share/aclocal
[buildout]
parts=
mariadb
boinc
extends =
../subversion/buildout.cfg
../m4/buildout.cfg
../automake/buildout.cfg
../libtool/buildout.cfg
../pkgconfig/buildout.cfg
../openssl/buildout.cfg
../cyrus-sasl/buildout.cfg
../openldap/buildout.cfg
../gnutls/buildout.cfg
../mariadb/buildout.cfg
../curl/buildout.cfg
../../stack/slapos.cfg
[mariadb]
# Compile dir is for plugins, not needed in boinc
keep-compile-dir = false
#checkout boinc package from svn repository
[boinc-package]
recipe = plone.recipe.command
location = ${buildout:parts-directory}/${:_buildout_section_name_}
tarball = ${buildout:parts-directory}/boinc.tar.gz
svnversion = ${subversion:location}/bin/svnversion
command = ${subversion:location}/bin/svn co --revision 26162 http://boinc.berkeley.edu/svn/branches/server_stable ${:location} && \
sed -i 's#/usr/bin/svnversion#${:svnversion}#' ${:location}/tools/make_project && \
sed -i "20i\#include <unistd.h>" ${:location}/tools/process_input_template.cpp && \
sed -i "25i\#include <unistd.h>" ${:location}/sched/single_job_assimilator.cpp && \
sed -i "27i\#include <unistd.h>" ${:location}/tools/create_work.cpp && \
sed -i 's#--prefix=$(prefix)#--prefix=/$(prefix)#' ${:location}/py/Makefile.am && \
sed -i 's#parent::base_escape_string#@parent::base_escape_string#' ${:location}/html/inc/boinc_db.inc
cd ${:location} && rm -f ${:tarball} && tar -cvzf ${:tarball} .
update-command =
# Compile now boinc
# When installing boinc python module, path /srv/slapgrid/... is strip to srv/slapgrid... It is why
# we need to set --prefix="/${buildout:parts-directory}/${:_buildout_section_name_}"
[boinc]
recipe = slapos.recipe.cmmi
url = ${boinc-package:tarball}
keep-compile-dir = true
source = ${buildout:parts-directory}/${:_buildout_section_name_}__compile__
configure-command =
echo 'AC_PROG_OBJCXX' >> configure.ac
aclocal -I${pkgconfig:location}/share/aclocal -I${libtool:location}/share/aclocal
./_autosetup
./configure
configure-options =
--prefix="${buildout:parts-directory}/${:_buildout_section_name_}"
--disable-fcgi
--disable-shared
--enable-static
--disable-manager
--disable-client
--with-pkg-config
--with-ssl=${openssl:location}
--with-libsasl2=${cyrus-sasl:location}/lib
--with-libldap=${openldap:location}/lib
--with-libgnutls=${gnutls:location}/lib
--with-libcurl=${curl:location}/lib
--with-x=no
environment =
PATH=${pkgconfig:location}/bin:${automake:location}/bin:${autoconf:location}/bin:${libtool:location}/bin:${subversion:location}/bin:%(PATH)s
PKG_CONFIG_PATH=${openssl:location}/lib/pkgconfig
M4=${m4:location}/bin/m4
CPPFLAGS=-I${openssl:location}/include -I${mariadb:location}/include
LDFLAGS = -L${openssl:location}/lib -Wl,-rpath=${openssl:location}/lib -L${mariadb:location}/lib -Wl,-rpath=${mariadb:location}/lib -L${zlib:location}/lib -Wl,-rpath=${zlib:location}/lib
MYSQL_CONFIG=${mariadb:location}/bin/mysql_config
ACLOCAL_PATH=${pkgconfig:location}/share/aclocal:${libtool:location}/share/aclocal
\ No newline at end of file
[buildout]
extends =
../ncurses/buildout.cfg
parts =
cmake
......@@ -6,3 +9,6 @@ parts =
recipe = slapos.recipe.cmmi
url = http://www.cmake.org/files/v2.8/cmake-2.8.10.2.tar.gz
md5sum = 097278785da7182ec0aea8769d06860c
environment =
CMAKE_INCLUDE_PATH=${ncurses:location}/include
CMAKE_LIBRARY_PATH=${ncurses:location}/lib
[buildout]
parts =
condor
extends =
../libexpat/buildout.cfg
../kerberos/buildout.cfg
../perl/buildout.cfg
../java/buildout.cfg
../openldap/buildout.cfg
../dash/buildout.cfg
../zlib/buildout.cfg
../../stack/slapos.cfg
[condor]
recipe = slapos.recipe.build
slapos_promise =
directory:bin
directory:etc
directory:examples
directory:include
directory:lib
directory:libexec
directory:man
directory:src
directory:sbin
depends =
${libexpat:location}
${kerberos:location}
${perl:location}
${openldap:location}
${java:location}
${dash:location}
${zlib:location}
x86 = http://parrot.cs.wisc.edu//symlink/20130530031504/7/7.9/7.9.5/28b36a94ad1a405bac689a76b6c353a7/condor-7.9.5-x86_Debian6-unstripped.tar.gz 227059bb9bebc9033665bb246d90a7bb
x86-64 = http://parrot.cs.wisc.edu//symlink/20130530031504/7/7.9/7.9.5/7000a12f9a22765b457e2958762871d5/condor-7.9.5-x86_64_Debian6-stripped.tar.gz 30fa4cebabb8ff4971c769f4ef74ba68
script =
if not self.options.get('path'): self.options['url'], self.options['md5sum'] = self.options[guessPlatform()].split(' ')
extract_dir = self.extract(self.download(self.options['url'], self.options.get('md5sum')))
workdir = guessworkdir(extract_dir)
self.copyTree(workdir, "%(location)s")
\ No newline at end of file
......@@ -10,7 +10,7 @@ parts =
curl
[curl]
recipe = hexagonit.recipe.cmmi
recipe = slapos.recipe.cmmi
url = http://curl.haxx.se/download/curl-7.30.0.tar.bz2
md5sum = 0db5ec03a5001b42a2edc03bf63b5ceb
configure-options =
......@@ -27,10 +27,12 @@ configure-options =
--disable-gopher
--enable-ipv6
--disable-sspi
--without-gnutls
--with-ssl=${openssl:location}
--with-zlib=${zlib:location}
--without-nss
--without-libssh2
--without-librtmp
--without-libidn
environment =
......
......@@ -19,18 +19,18 @@ md5sum = 5c781723a0d9ed6188960defba8e91cf
destination = ${fonts:location}/${:_buildout_section_name_}
# IPAex and IPA Font - Japanese fonts provided by IPA
# http://ossipedia.ipa.go.jp/ipafont/index.html
# http://ipafont.ipa.go.jp/
[ipaex-fonts]
recipe = hexagonit.recipe.download
strip-top-level-dir = true
url = http://ossipedia.ipa.go.jp/ipafont/ipaexfont/IPAexfont00201.php
url = http://ipafont.ipa.go.jp/ipaexfont/IPAexfont00201.php
md5sum = 7bf84182a04a9632268dbcb03f100d05
destination = ${fonts:location}/${:_buildout_section_name_}
[ipa-fonts]
recipe = hexagonit.recipe.download
strip-top-level-dir = true
url = http://info.openlab.ipa.go.jp/ipafont/fontdata/IPAfont00303.zip
url = http://ipafont.ipa.go.jp/ipafont/IPAfont00303.php
md5sum = 39a828acf27790adbe4944dfb4d94bb1
destination = ${fonts:location}/${:_buildout_section_name_}
......
......@@ -12,8 +12,8 @@ parts =
[git]
recipe = slapos.recipe.cmmi
url = http://git-core.googlecode.com/files/git-1.7.12.tar.gz
md5sum = ceb1a6b17a3e33bbc70eadf8fce5876c
url = http://git-core.googlecode.com/files/git-1.8.2.3.tar.gz
md5sum = 03ebfd403a8cf355da0e3f15e53b8925
configure-options =
--with-curl=${curl:location}
--with-openssl=${openssl:location}
......
......@@ -11,9 +11,9 @@ extends =
[groonga]
recipe = slapos.recipe.cmmi
version = 3.0.2
version = 3.0.4
url = http://packages.groonga.org/source/groonga/groonga-${:version}.tar.gz
md5sum = b17934ef2589a4e261ed0d99aec713eb
md5sum = d37e6391f9a7346166e0d1301e88dea5
configure-options =
--disable-static
--disable-glibtest
......@@ -27,9 +27,9 @@ environment =
[groonga-normalizer-mysql]
recipe = slapos.recipe.cmmi
version = 1.0.2
version = 1.0.4
url = http://packages.groonga.org/source/groonga-normalizer-mysql/groonga-normalizer-mysql-${:version}.tar.gz
md5sum = 782111599dcba5023beb698dc5ea514a
md5sum = 72c9d9fe5031c2c3af34dbbfcd46a9a9
location = ${groonga:location}
depends =
${groonga:version}
......
# jsl - command line javascript lint
# http://javascriptlint.com/
[buildout]
parts = jsl
[jsl]
recipe = slapos.recipe.build
url = http://www.javascriptlint.com/download/jsl-0.3.0-src.tar.gz
md5sum = 2b94ffa4fab07acabe0c5e73cd49bcdf
script =
location = %(location)r
self.failIfPathExists(location)
import sys
url = self.options['url']
md5sum = self.options['md5sum']
extract_dir = self.extract(self.download(url, md5sum))
workdir = guessworkdir(extract_dir)
os.chdir(os.path.join(workdir, 'src'))
os.system('make -f Makefile.ref -j 1 DIST="%(location)s" all export')
[buildout]
parts =
kerberos
extends =
../../component/bison/buildout.cfg
[kerberos-package]
recipe = hexagonit.recipe.download
url = http://web.mit.edu/kerberos/dist/krb5/1.11/krb5-1.11.1-signed.tar
md5sum = 76c6bed945c5771674357cfd4a08e3f5
[kerberos]
recipe = hexagonit.recipe.cmmi
url = ${kerberos-package:location}/krb5-1.11.1.tar.gz
configure-command = src/configure
configure-options =
--prefix=${buildout:parts-directory}/${:_buildout_section_name_}
environment =
PATH=${bison:location}/bin:%(PATH)s
\ No newline at end of file
......@@ -2,7 +2,19 @@
parts =
libiconv
[libiconv.gets.patch]
recipe = hexagonit.recipe.download
url = ${:_profile_base_location_}/${:filename}
md5sum = 8a20d8afe0617fce56f77537d2b84621
download-only = true
filename = libiconv.gets.patch
[libiconv]
virtual-depends =
${libiconv.gets.patch:md5sum}
patch-options = -p1
patches =
${libiconv.gets.patch:location}/${libiconv.gets.patch:filename}
recipe = slapos.recipe.cmmi
url = http://ftp.gnu.org/pub/gnu/libiconv/libiconv-1.14.tar.gz
md5sum = e34509b1623cec449dfeb73d7ce9c6c6
--- libiconv-1.14.orig/srclib/stdio.in.h 2011-08-07 13:42:06.000000000 +0000
+++ libiconv-1.14/srclib/stdio.in.h 2013-01-09 19:56:21.115819812 +0000
@@ -680,22 +680,7 @@
#endif
#if @GNULIB_GETS@
-# if @REPLACE_STDIO_READ_FUNCS@ && @GNULIB_STDIO_H_NONBLOCKING@
-# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
-# undef gets
-# define gets rpl_gets
-# endif
-_GL_FUNCDECL_RPL (gets, char *, (char *s) _GL_ARG_NONNULL ((1)));
-_GL_CXXALIAS_RPL (gets, char *, (char *s));
-# else
-_GL_CXXALIAS_SYS (gets, char *, (char *s));
-# undef gets
-# endif
-_GL_CXXALIASWARN (gets);
-/* It is very rare that the developer ever has full control of stdin,
- so any use of gets warrants an unconditional warning. Assume it is
- always declared, since it is required by C89. */
-_GL_WARN_ON_USE (gets, "gets is a security hole - use fgets instead");
+#undef gets
#endif
......@@ -8,8 +8,8 @@ parts =
[libxml2]
recipe = slapos.recipe.cmmi
url = ftp://ftp.xmlsoft.org/libxml2/libxml2-2.9.0.tar.gz
md5sum = 5b9bebf4f5d2200ae2c4efe8fa6103f7
url = ftp://ftp.xmlsoft.org/libxml2/libxml2-2.9.1.tar.gz
md5sum = 9c0cfef285d5c4a5c80d00904ddab380
configure-options =
--disable-static
--without-python
......
[buildout]
extends =
../libxml2/buildout.cfg
../pkgconfig/buildout.cfg
../zlib/buildout.cfg
parts =
......@@ -19,7 +18,5 @@ configure-options =
--without-debug
--without-debugger
environment =
PATH=${pkgconfig:location}/bin:%(PATH)s
CPPFLAGS=-I${zlib:location}/include
LDFLAGS=-Wl,-rpath=${zlib:location}/lib
PKG_CONFIG_PATH=${libxml2:location}/lib/pkgconfig:${zlib:location}/lib/pkgconfig
CPPFLAGS=-I${zlib:location}/include -I${libxml2:location}/include
LDFLAGS=-L${libxml2:location}/lib -Wl,-rpath=${libxml2:location}/lib -L${zlib:location}/lib -Wl,-rpath=${zlib:location}/lib
......@@ -25,10 +25,10 @@ download-only = true
[mariadb]
recipe = slapos.recipe.cmmi
version = 5.5.30
version = 5.5.31
revision = 1
url = http://downloads.askmonty.org/f/mariadb-${:version}/kvm-tarbake-jaunty-x86/mariadb-${:version}.tar.gz/from/http://ftp.osuosl.org/pub/mariadb
md5sum = 39d4da4dabc8bda012517b3587dee6f8
md5sum = 3fe756bc76f0e7a3af2757e48ce0f3f4
# compile directory is required to build mysql plugins.
keep-compile-dir = true
patch-options = -p0
......@@ -62,8 +62,8 @@ environment =
# mroonga - a storage engine for MySQL. It provides fast fulltext search feature to all MySQL users.
# http://mroonga.github.com/
recipe = slapos.recipe.cmmi
url = http://packages.groonga.org/source/mroonga/mroonga-3.02.tar.gz
md5sum = b2d1a4abc12030fdbd9064bbb6175366
url = http://packages.groonga.org/source/mroonga/mroonga-3.04.tar.gz
md5sum = 790d239c5bf5b98a760a78fdfcbe6803
configure-options =
--with-mysql-source=${mariadb:location}__compile__/mariadb-${mariadb:version}
--with-mysql-config=${mariadb:location}/bin/mysql_config
......
......@@ -13,8 +13,8 @@ extends =
[poppler]
recipe = slapos.recipe.cmmi
md5sum = 3939740201c59c470bc7198003450a20
url = http://poppler.freedesktop.org/poppler-0.22.2.tar.gz
md5sum = be915388eaad6865cee5a156c8119ec1
url = http://poppler.freedesktop.org/poppler-0.22.3.tar.gz
depends =
${libtiff:version}
configure-options =
......
[buildout]
parts =
redis
extends = ../tcl/buildout.cfg
[redis]
recipe = hexagonit.recipe.cmmi
url = https://github.com/geoffgarside/redis/archive/ipv6.tar.gz
md5sum = 0eb594bd4e8ee746a0e2ef67b28cb5d8
configure-command = true
prefix =
make-options =
PREFIX=${buildout:parts-directory}/${:_buildout_section_name_}
V=1
make-targets =
install
test
environment =
PATH=${tcl:location}/bin:%(PATH)s
\ No newline at end of file
......@@ -5,8 +5,8 @@ parts =
[sqlite3]
recipe = slapos.recipe.cmmi
url = http://www.sqlite.org/2013/sqlite-autoconf-3071601.tar.gz
md5sum = 8860d1a1ed26d40f07e3c7ae035b644a
url = http://www.sqlite.org/2013/sqlite-autoconf-3071700.tar.gz
md5sum = 18c285053e9562b848209cb0ee16d4ab
configure-options =
--disable-static
--enable-readline
......
......@@ -10,6 +10,7 @@ extends =
../pkgconfig/buildout.cfg
../sqlite3/buildout.cfg
../zlib/buildout.cfg
../swig/buildout.cfg
parts =
subversion
......@@ -59,3 +60,45 @@ environment =
PKG_CONFIG_PATH=${apache:location}/lib/pkgconfig:${sqlite3:location}/lib/pkgconfig:${openssl:location}/lib/pkgconfig:${neon:location}/lib/pkgconfig
CPPFLAGS=-I${libexpat:location}/include -I${libuuid:location}/include
LDFLAGS=-L${libexpat:location}/lib -Wl,-rpath=${zlib:location}/lib -Wl,-rpath=${sqlite3:location}/lib -Wl,-rpath=${neon:location}/lib -Wl,-rpath=${apache:location}/lib -L${libuuid:location}/lib -Wl,-rpath=${libuuid:location}/lib
[subversion-1.9]
recipe = hexagonit.recipe.cmmi
url = http://www.apache.org/dist/subversion/subversion-1.7.9.tar.gz
md5sum = dfb083e8bfac88aa28d606168b08e4ff
configure-options =
--disable-static
--with-apr=${apache:location}/bin/apr-1-config
--with-apr-util=${apache:location}/bin/apu-1-config
--with-apxs=${apache:location}/bin/apxs
--with-zlib=${zlib:location}
--with-sqlite=${sqlite3:location}
--with-neon=${neon:location}
--with-swig=${swig:location}/bin/swig
--without-berkeley-db
--without-sasl
--without-apr_memcache
--without-gnome-keyring
--without-kwallet
--without-jdk
--without-jikes
--without-junit
--without-ctypesgen
--without-ruby-sitedir
--without-ruby-test-verbose
--disable-nls
# it seems that parallel build sometimes fails.
make-options =
-j1
make-targets =
install
swig-py
install-swig-py
environment =
PATH=${pkgconfig:location}/bin:${neon:location}/bin:%(PATH)s
PKG_CONFIG_PATH=${apache:location}/lib/pkgconfig:${sqlite3:location}/lib/pkgconfig:${openssl:location}/lib/pkgconfig:${neon:location}/lib/pkgconfig
CPPFLAGS=-I${libexpat:location}/include -I${libuuid:location}/include
LDFLAGS=-L${libexpat:location}/lib -Wl,-rpath=${zlib:location}/lib -Wl,-rpath=${sqlite3:location}/lib -Wl,-rpath=${neon:location}/lib -Wl,-rpath=${apache:location}/lib -L${libuuid:location}/lib -Wl,-rpath=${libuuid:location}/lib
[buildout]
parts = tcl
[tcl-package]
recipe = hexagonit.recipe.download
url = http://prdownloads.sourceforge.net/tcl/tcl8.5.13-src.tar.gz
md5sum = fa3a9bf9b2d6ed2431f1baa46f4058b8
strip-top-level-dir = true
[tcl]
recipe = plone.recipe.command
location = ${buildout:parts-directory}/${:_buildout_section_name_}
command = cd ${tcl-package:location}/unix &&
./configure --prefix=${:location} &&
make &&
make test &&
make install
\ No newline at end of file
......@@ -4,5 +4,5 @@ parts =
[zlib]
recipe = slapos.recipe.cmmi
url = http://prdownloads.sourceforge.net/libpng/zlib-1.2.6.tar.bz2?download
md5sum = dc2cfa0d2313ca77224b4d932b2911e9
url = http://downloads.sourceforge.net/project/libpng/zlib/1.2.8/zlib-1.2.8.tar.gz
md5sum = 44d667c142d7cda120332623eab69f40
......@@ -28,7 +28,7 @@ from setuptools import setup, find_packages
import glob
import os
version = '0.77.2.dev'
version = '0.78.2.dev'
name = 'slapos.cookbook'
long_description = open("README.txt").read() + "\n" + \
open("CHANGES.txt").read() + "\n"
......@@ -57,6 +57,7 @@ setup(name=name,
'netaddr', # to manipulate on IP addresses
'setuptools', # namespaces
'inotifyx', # to watch filesystem changes (used in lockfile)
'lock_file', #another lockfile implementation for multiprocess
'slapos.core', # uses internally
# 'slapos.toolbox', # needed for libcloud, cloudmgr, disabled for now
'xml_marshaller', # need to communication with slapgrid
......@@ -75,6 +76,11 @@ setup(name=name,
'apachephp = slapos.recipe.apachephp:Recipe',
'apachephpconfigure = slapos.recipe.apachephpconfigure:Recipe',
'apacheproxy = slapos.recipe.apacheproxy:Recipe',
'boinc = slapos.recipe.boinc:Recipe',
'boinc.app = slapos.recipe.boinc:App',
'boinc.client = slapos.recipe.boinc:Client',
'bonjourgrid = slapos.recipe.bonjourgrid:Recipe',
'bonjourgrid.client = slapos.recipe.bonjourgrid:Client',
'certificate_authority = slapos.recipe.certificate_authority:Recipe',
'certificate_authority.request = slapos.recipe.certificate_authority:Request',
'check_page_content = slapos.recipe.check_page_content:Recipe',
......@@ -82,6 +88,8 @@ setup(name=name,
'check_url_available = slapos.recipe.check_url_available:Recipe',
'cloud9 = slapos.recipe.cloud9:Recipe',
'cloudooo.test = slapos.recipe.erp5_test:CloudoooRecipe',
'condor = slapos.recipe.condor:Recipe',
'condor.submit = slapos.recipe.condor:AppSubmit',
'configurationfile = slapos.recipe.configurationfile:Recipe',
'cron = slapos.recipe.dcron:Recipe',
'cron.d = slapos.recipe.dcron:Part',
......@@ -159,6 +167,7 @@ setup(name=name,
'publishurl = slapos.recipe.publishurl:Recipe',
'pwgen = slapos.recipe.pwgen:Recipe',
'pwgen.stable = slapos.recipe.pwgen:StablePasswordGeneratorRecipe',
'redis.server = slapos.recipe.redis:Recipe',
'request = slapos.recipe.request:Recipe',
'request.serialised = slapos.recipe.request:Serialised',
'request.edge = slapos.recipe.request:RequestEdge',
......@@ -186,6 +195,7 @@ setup(name=name,
'stunnel = slapos.recipe.stunnel:Recipe',
'symbolic.link = slapos.recipe.symbolic_link:Recipe',
'tidstorage = slapos.recipe.tidstorage:Recipe',
'trac = slapos.recipe.trac:Recipe',
'urlparse = slapos.recipe._urlparse:Recipe',
'uuid = slapos.recipe._uuid:Recipe',
'vifib = slapos.recipe.vifib:Recipe',
......@@ -203,3 +213,4 @@ setup(name=name,
],
},
)
......@@ -33,6 +33,27 @@ from slapos.recipe.librecipe import GenericBaseRecipe
class Recipe(GenericBaseRecipe):
def __init__(self, buildout, name, options):
self.environ = {}
environment_section = options.get('environment-section', '').strip()
if environment_section and environment_section in buildout:
# Use environment variables from the designated config section.
self.environ.update(buildout[environment_section])
for variable in options.get('environment', '').splitlines():
if variable.strip():
try:
key, value = variable.split('=', 1)
self.environ[key.strip()] = value
except ValueError:
raise zc.buildout.UserError('Invalid environment variable definition: %s', variable)
# Extrapolate the environment variables using values from the current
# environment.
for key in self.environ:
self.environ[key] = self.environ[key] % os.environ
return GenericBaseRecipe.__init__(self, buildout, name, options)
def install(self):
path_list = []
......@@ -54,6 +75,7 @@ class Recipe(GenericBaseRecipe):
path_list.append(php_ini)
# Install apache
if self.optionIsTrue('default-conf', True):
apache_config = dict(
pid_file=self.options['pid-file'],
lock_file=self.options['lock-file'],
......@@ -76,7 +98,8 @@ class Recipe(GenericBaseRecipe):
'-f',
self.options['httpd-conf'],
'-DFOREGROUND'
])
],
environment=self.environ)
path_list.append(wrapper)
secret_key_filename = os.path.join(self.buildout['buildout']['directory'],
......@@ -105,6 +128,11 @@ class Recipe(GenericBaseRecipe):
port=self.options['port'],
# XXX-Cedric: add frontend url.
)
# Allow to give custom parameters to template
application_parameter_prefix = 'application-'
for key in self.options.keys():
if key.startswith(application_parameter_prefix):
application_conf[key.lstrip(application_parameter_prefix)] = self.options[key]
directory, file_ = os.path.split(self.options['configuration'])
......
##############################################################################
#
# Copyright (c) 2010 Vifib SARL and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from slapos.recipe.librecipe import GenericBaseRecipe
import os
import subprocess
import pwd
import json
import signal
import zc.buildout
class Recipe(GenericBaseRecipe):
"""Deploy a fully operational boinc architecture."""
def __init__(self, buildout, name, options):
#get current slapuser name
stat_info = os.stat(options['home'].strip())
options['user'] = pwd.getpwuid(stat_info.st_uid)[0]
url_base = options['url-base']
project = options['project'].strip()
root = options['installroot'].strip()
options['home_page'] = url_base + "/" + project
options['admin_page'] = url_base + "/" + project + "_ops/"
options['result_page'] = url_base + "/" + project + "_result/"
options['cronjob'] = os.path.join(root, project+'.cronjob')
return GenericBaseRecipe.__init__(self, buildout, name, options)
def _options(self, options):
#Path of boinc compiled package
self.package = options['boinc'].strip()
self.sourcedir = options['source'].strip()
self.home = options['home'].strip()
self.project = options['project'].strip()
self.fullname = options['fullname'].strip()
self.copyright = options['copyright'].strip()
self.installroot = options['installroot'].strip()
self.boinc_egg = os.path.join(self.package, 'lib/python2.7/site-packages')
self.developegg = options['develop-egg'].strip()
self.wrapperdir = options['wrapper-dir'].strip()
self.passwd = options['passwd'].strip()
#Get binary path
self.svn = options['svn-binary'].strip()
self.perl = options['perl-binary'].strip()
self.pythonbin = options['python-binary'].strip()
#Apache php informations
self.url_base =options['url-base'].strip()
self.htpasswd = options['htpasswd'].strip()
self.phpini = options['php-ini'].strip()
self.phpbin = options['php-bin'].strip()
#get Mysql parameters
self.username = options['mysql-username'].strip()
self.password = options['mysql-password'].strip()
self.database = options['mysql-database'].strip()
self.mysqlhost = options['mysql-host'].strip()
self.mysqlport = options['mysql-port'].strip()
def haschanges(self):
config_file = os.path.join(self.home, '.config')
current = [self.fullname, self.copyright,
self.password, self.mysqlhost, self.installroot,
self.project, self.passwd, self.url_base]
previous = []
result = False
if os.path.exists(config_file):
previous = open(config_file, 'r').read().split('#')
#Check if config has changed
if len(current) != len(set(current).intersection(set(previous))) or \
not os.path.exists(self.installroot) or \
not os.path.exists(os.path.join(self.home, '.start_service')):
result = True
open(config_file, 'w').write('#'.join(current))
return result
def install(self):
path_list = []
make_project = os.path.join(self.package, 'bin/make_project')
niceprojectname = self.project + "@Home"
slapuser = self.options['user']
#Check if given URL is not empty (case of URL request with frontend)
if not self.url_base:
raise Exception("URL_BASE is still empty. Can not use it")
#Define environment variable here
python = os.path.join(self.home, 'bin/python')
python_path = self.boinc_egg
if not os.path.exists(python):
os.symlink(self.pythonbin, python)
for f in os.listdir(self.developegg):
dir = os.path.join(self.developegg, f)
if os.path.isdir(dir):
python_path += ":" + dir
bin_dir = os.path.join(self.home, 'bin')
environment = dict(
PATH=os.pathsep.join([self.svn, bin_dir, self.perl, os.environ['PATH']]),
PYTHONPATH=os.pathsep.join([python_path, os.environ['PYTHONPATH']]),
)
#Generate wrapper for php
wrapperphp = os.path.join(self.home, 'bin/php')
php_wrapper = self.createPythonScript(wrapperphp,
'slapos.recipe.librecipe.execute.executee',
([self.phpbin, '-c', self.phpini], os.environ)
)
path_list.append(php_wrapper)
#Generate python script for MySQL database test (starting)
file_status = os.path.join(self.home, '.boinc_config')
if os.path.exists(file_status):
os.unlink(file_status)
mysql_wrapper = self.createPythonScript(
os.path.join(self.wrapperdir, 'start_config'),
'%s.configure.checkMysql' % __name__,
dict(mysql_port=self.mysqlport, mysql_host=self.mysqlhost,
mysql_user=self.username, mysql_password=self.password,
database=self.database,
file_status=file_status, environment=environment
)
)
# Generate make project wrapper file
readme_file = os.path.join(self.installroot, self.project+'.readme')
launch_args = [make_project, '--url_base', self.url_base, "--db_name",
self.database, "--db_user", self.username, "--db_passwd",
self.password, "--project_root", self.installroot, "--db_host",
self.mysqlhost, "--user_name", slapuser, "--srcdir",
self.sourcedir, "--no_query"]
drop_install = self.haschanges()
request_make_boinc = os.path.join(self.home, '.make_project')
if drop_install:
#Allow to restart Boinc installation from the begining
launch_args += ["--delete_prev_inst", "--drop_db_first"]
open(request_make_boinc, 'w').write('Make Requested')
if os.path.exists(readme_file):
os.unlink(readme_file)
launch_args += [self.project, niceprojectname]
install_wrapper = self.createPythonScript(
os.path.join(self.wrapperdir, 'make_project'),
'%s.configure.makeProject' % __name__,
dict(launch_args=launch_args, request_file=request_make_boinc,
make_sig=file_status, env=environment)
)
path_list.append(install_wrapper)
#generate sh script for project configuration
bash = os.path.join(self.home, 'bin', 'project_config.sh')
sh_script = self.createFile(bash,
self.substituteTemplate(self.getTemplateFilename('project_config.in'),
dict(dash=self.options['dash'].strip(),
uldl_pid=self.options['apache-pid'].strip(),
user=slapuser, fullname=self.fullname,
copyright=self.copyright, installroot=self.installroot))
)
path_list.append(sh_script)
os.chmod(bash , 0700)
#After make_project run configure_script to perform and restart apache php services
service_status = os.path.join(self.home, '.start_service')
parameter = dict(
readme=readme_file,
htpasswd=self.htpasswd,
installroot=self.installroot,
username=slapuser,
passwd=self.passwd,
xadd=os.path.join(self.installroot, 'bin/xadd'),
environment=environment,
service_status=service_status,
drop_install=drop_install,
sedconfig=bash
)
start_service = self.createPythonScript(
os.path.join(self.wrapperdir, 'config_project'),
'%s.configure.services' % __name__, parameter
)
path_list.append(start_service)
#Generate Boinc start project wrapper
start_args = [os.path.join(self.installroot, 'bin/start')]
start_boinc = os.path.join(self.home, '.start_boinc')
if os.path.exists(start_boinc):
os.unlink(start_boinc)
boinc_parameter = dict(service_status=service_status,
installroot=self.installroot, drop_install=drop_install,
mysql_port=self.mysqlport, mysql_host=self.mysqlhost,
mysql_user=self.username, mysql_password=self.password,
database=self.database, environment=environment,
start_boinc=start_boinc)
start_wrapper = self.createPythonScript(os.path.join(self.wrapperdir,
'start_boinc'),
'%s.configure.restart_boinc' % __name__,
boinc_parameter
)
path_list.append(start_wrapper)
return path_list
update = install
class App(GenericBaseRecipe):
"""This recipe allow to deploy an scientific applications using boinc
Note that recipe use depend on boinc-server parameter"""
def downloadFiles(self, app):
"""This is used to download app files if necessary and update options values"""
for key in ('input-file', 'template-result', 'template-wu', 'binary'):
param = app[key]
if param and (param.startswith('http') or param.startswith('ftp')):
#download the specified file
cache = os.path.join(self.options['home'].strip(), 'tmp')
downloader = zc.buildout.download.Download(self.buildout['buildout'],
hash_name=True, cache=cache)
path, _ = downloader(param, md5sum=None)
mode = 0600
if key == 'binary':
mode = 0700
os.chmod(path, mode)
app[key] = path
def getAppList(self):
"""Load parameters,
check if parameter send is valid to install or update application"""
app_list = json.loads(self.options['boinc-app-list'])
if not app_list:
return None
default_template_result = self.options.get('default-template-result', '').strip()
default_template_wu = self.options.get('default-template-wu', '').strip()
default_extension = self.options.get('default-extension', '').strip()
default_platform = self.options.get('default-platform', '').strip()
for app in app_list:
for version in app_list[app]:
current_app = app_list[app][version]
#Use default value if empty and Use_default is True
#Initialize all values to empty if not define by the user
if current_app['use_default']:
current_app['template-result'] = current_app.get('template-result',
default_template_result).strip()
current_app['template-wu'] = current_app.get('template-wu',
default_template_wu).strip()
current_app['extension'] = current_app.get('extension',
default_extension).strip()
current_app['platform'] = current_app.get('platform',
default_platform).strip()
else:
current_app['template-result'] = current_app.get('template-result', '').strip()
current_app['template-wu'] = current_app.get('template-wu', '').strip()
current_app['extension'] = current_app.get('extension', '').strip()
current_app['platform'] = current_app.get('platform', '').strip()
current_app['input-file'] = current_app.get('input-file', '').strip()
current_app['wu-number'] = current_app.get('wu-number', 1)
#for new application, check if parameter is complete
appdir = os.path.join(self.options['installroot'].strip(), 'apps',
app, version)
if not os.path.exists(appdir):
if not current_app['template-result'] or not current_app['binary'] \
or not current_app['input-file'] or not current_app['template-wu'] \
or not current_app['platform']:
print "BOINC-APP: ERROR - Invalid argements values for % ...operation cancelled" % app
app_list[app][version] = None
continue
#write application to install
request_file = os.path.join(self.options['home'].strip(),
'.install_' + app + version)
toInstall = open(request_file, 'w')
toInstall.write('install or update')
toInstall.close()
return app_list
def install(self):
app_list = self.getAppList()
path_list = []
package = self.options['boinc'].strip()
#Define environment variable here
developegg = self.options['develop-egg'].strip()
python_path = os.path.join(package, 'lib/python2.7/site-packages')
home = self.options['home'].strip()
user = pwd.getpwuid(os.stat(home).st_uid)[0]
perl = self.options['perl-binary'].strip()
svn = self.options['svn-binary'].strip()
for f in os.listdir(developegg):
dir = os.path.join(developegg, f)
if os.path.isdir(dir):
python_path += ":" + dir
bin_dir = os.path.join(home, 'bin')
environment = dict(
PATH=os.pathsep.join([svn, bin_dir, perl, os.environ['PATH']]),
PYTHONPATH=os.pathsep.join([python_path, os.environ['PYTHONPATH']]),
)
#generate project.xml and config.xml script updater
bash = os.path.join(home, 'bin', 'update_config.sh')
sh_script = self.createFile(bash,
self.substituteTemplate(self.getTemplateFilename('sed_update.in'),
dict(dash=self.options['dash'].strip()))
)
path_list.append(sh_script)
os.chmod(bash , 0700)
#If useful, download necessary files and update options path
start_boinc = os.path.join(home, '.start_boinc')
installroot = self.options['installroot'].strip()
apps_dir = os.path.join(installroot, 'apps')
wrapperdir = self.options['wrapper-dir'].strip()
project = self.options['project'].strip()
lockfile = os.path.join(self.options['home'].strip(), 'app_install.lock')
fd = os.open(lockfile, os.O_RDWR|os.O_CREAT)
os.close( fd )
for appname in app_list:
for version in app_list[appname]:
if not app_list[appname][version]:
continue
self.downloadFiles(app_list[appname][version])
platform = app_list[appname][version]['platform']
application = os.path.join(apps_dir, appname, version, platform)
if app_list[appname][version]['binary'] and not platform:
print "BOINC-APP: WARNING - Cannot specify binary without giving platform value"
app_list[appname][version]['binary'] = '' #Binary will not be updated
parameter = dict(installroot=installroot,
appname=appname, project=project,
version=version, platform=platform,
application=application, environment=environment,
start_boinc=start_boinc,
wu_number=app_list[appname][version]['wu-number'],
t_result=app_list[appname][version]['template-result'],
t_wu=app_list[appname][version]['template-wu'],
t_input=app_list[appname][version]['input-file'],
binary=app_list[appname][version]['binary'],
extension=app_list[appname][version]['extension'],
bash=bash, home_dir=home,
lockfile=lockfile,
)
deploy_app = self.createPythonScript(
os.path.join(wrapperdir, 'boinc_%s' % appname),
'%s.configure.deployApp' % __name__, parameter
)
path_list.append(deploy_app)
return path_list
update = install
class Client(GenericBaseRecipe):
"""Deploy a fully fonctionnal boinc client connected to a boinc server instance"""
def __init__(self, buildout, name, options):
#get current uig to create a unique rpc-port for this client
stat_info = os.stat(options['home'].strip())
options['rpc-port'] = pwd.getpwuid(stat_info.st_uid)[2] + 5000
return GenericBaseRecipe.__init__(self, buildout, name, options)
def install(self):
path_list = []
boincbin = self.options['boinc-bin'].strip()
cmdbin = self.options['cmd-bin'].strip()
installdir = self.options['install-dir'].strip()
url = self.options['server-url'].strip()
key = self.options['key'].strip()
boinc_wrapper = self.options['client-wrapper'].strip()
cmd_wrapper = self.options['cmd-wrapper'].strip()
remote_host = os.path.join(installdir, 'remote_hosts.cfg')
open(remote_host, 'w').write(self.options['ip'].strip())
#Generate wrapper for boinc cmd
base_cmd = [cmdbin, '--host', str(self.options['rpc-port']),
'--passwd', self.options['passwd'].strip()]
cc_cmd = ''
if self.options['cconfig'].strip() != '':
config_dest = os.path.join(installdir, 'cc_config.xml')
file = open(config_dest, 'w')
file.write(open(self.options['cconfig'].strip(), 'r').read())
file.close()
cc_cmd = '--read_cc_config'
cmd = self.createPythonScript(cmd_wrapper,
'%s.configure.runCmd' % __name__,
dict(base_cmd=base_cmd, cc_cmd=cc_cmd, installdir=installdir,
project_url=url, key=key)
)
path_list.append(cmd)
#Generate BOINC client wrapper
boinc = self.createPythonScript(boinc_wrapper,
'slapos.recipe.librecipe.execute.execute',
[boincbin, '--allow_multiple_clients', '--gui_rpc_port',
str(self.options['rpc-port']), '--allow_remote_gui_rpc',
'--dir', installdir, '--redirectio', '--check_all_logins']
)
path_list.append(boinc)
return path_list
##############################################################################
#
# Copyright (c) 2010 Vifib SARL and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import os
import sys
import subprocess
import time
import shutil
import re
import filecmp
from lock_file import LockFile
def checkMysql(args):
sys.path += args['environment']['PYTHONPATH'].split(':')
import MySQLdb
#Sleep until mysql server becomes available
while True:
try:
conn = MySQLdb.connect(host = args['mysql_host'],
user = args['mysql_user'],
port = int(args['mysql_port']),
passwd = args['mysql_password'],
db = args['database'])
conn.close()
print "Successfully connect to MySQL database... "
if args.has_key('file_status'):
writeFile(args['file_status'], "starting")
break
except Exception, ex:
print "The result is: \n" + ex.message
print "Could not connect to MySQL database... sleep for 2 secondes"
time.sleep(2)
def checkFile(file, stime):
"""Loop until 'file' is created (exist)"""
while True:
print "Search for file %s..." % file
if not os.path.exists(file):
print "File not found... sleep for %s secondes" % stime
time.sleep(stime)
else:
break
def restart_boinc(args):
"""Stop (if currently is running state) and start all Boinc service"""
if args['drop_install']:
checkFile(args['service_status'], 3)
else:
checkMysql(args)
print "Restart Boinc..."
env = os.environ
env['PATH'] = args['environment']['PATH']
env['PYTHONPATH'] = args['environment']['PYTHONPATH']
binstart = os.path.join(args['installroot'], 'bin/start')
binstop = os.path.join(args['installroot'], 'bin/stop')
os.system(binstop)
os.system(binstart)
writeFile(args['start_boinc'], "started")
print "Done."
def check_installRequest(args):
print "Cheking if needed to install %s..." % args['appname']
install_request_file = os.path.join(args['home_dir'],
'.install_' + args['appname'] + args['version'])
if not os.path.exists(install_request_file):
print "No install or update request for %s version %s..." % (
args['appname'], args['version'])
return False
os.unlink(install_request_file)
return True
def copy_file(source, dest):
""""Copy file with source to dest with auto replace
return True if file has been copied and dest ha been replaced
"""
result = False
if source and os.path.exists(source):
if os.path.exists(dest):
if filecmp.cmp(dest, source):
return False
os.unlink(dest)
result = True
shutil.copy(source, dest)
return result
def startProcess(launch_args, env=None, cwd=None, stdout=subprocess.PIPE):
process = subprocess.Popen(launch_args, stdout=stdout,
stderr=subprocess.STDOUT, env=env,
cwd=cwd)
result = process.communicate()[0]
if process.returncode is None or process.returncode != 0:
print "Failed to execute executable.\nThe error was: %s" % result
return False
return True
def makeProject(args):
"""Run BOINC make_project script but once only"""
#Wait for DateBase initialization...
checkFile(args['make_sig'], 3)
print "Cheking if needed to run BOINC make_project..."
if os.path.exists(args['request_file']):
env = os.environ
env['PATH'] = args['env']['PATH']
env['PYTHONPATH'] = args['env']['PYTHONPATH']
if startProcess(args['launch_args'], env=env):
os.unlink(args['request_file'])
print "Finished running BOINC make_projet...Ending"
else:
print "No new request for make_project. Exiting..."
def services(args):
"""This function configure a new installed boinc project instance"""
print "Checking if needed to install or reinstall Boinc-server..."
if not args['drop_install']:
print "Not need to install Boinc-server...skipped"
return
#Sleep until file 'boinc_project'.readme exist
checkFile(args['readme'], 3)
topath = os.path.join(args['installroot'], 'html/ops/.htpasswd')
print "Generating .htpasswd file... File=%s" % topath
passwd = open(args['passwd'], 'r').read()
htpwd_args = [args['htpasswd'], '-b', '-c', topath, args['username'], passwd]
if not startProcess(htpwd_args):
return
print "execute script xadd..."
env = os.environ
env['PATH'] = args['environment']['PATH']
env['PYTHONPATH'] = args['environment']['PYTHONPATH']
if not startProcess([os.path.join(args['installroot'], 'bin/xadd')], env):
return
print "Update files and directories permissions..."
upload = os.path.join(args['installroot'], 'upload')
inc = os.path.join(args['installroot'], 'html/inc')
languages = os.path.join(args['installroot'], 'html/languages')
compiled = os.path.join(args['installroot'], 'html/languages/compiled')
user_profile = os.path.join(args['installroot'], 'html/user_profile')
forum_file = os.path.join(args['installroot'], 'html/ops/create_forums.php')
project_inc = os.path.join(args['installroot'], 'html/project/project.inc')
cmd = "chmod 02700 -R %s %s, %s %s %s" % (upload, inc,
languages, compiled, user_profile)
os.system("chmod g+w -R " + args['installroot'])
os.system(cmd)
os.system("chmod 700 %s" % os.path.join(args['installroot'], 'keys'))
os.system("chmod o+x " + inc)
os.system("chmod -R o+r " + inc)
os.system("chmod o+x " + languages)
os.system("chmod o+x " + compiled)
sed_args = [args['sedconfig']]
startProcess(sed_args)
#Execute php create_forum.php...
print "Boinc Forum: Execute php create_forum.php..."
cwd = os.path.join(args['installroot'], 'html/ops')
if not startProcess(["php", forum_file], env, cwd):
return
writeFile(args['service_status'], "started")
def deployApp(args):
"""Deploy Boinc App with lock"""
print "Asking to enter in execution with lock mode..."
with LockFile(args['lockfile'], wait=True):
print "acquire the lock file..."
deployManagement(args)
print "Exit execution with lock..."
def deployManagement(args):
"""Fully deploy or redeploy or update a BOINC application using existing BOINC instance"""
if not check_installRequest(args):
return
token = os.path.join(args['installroot'], "." + args['appname'] + args['version'])
newInstall = False
if os.path.exists(token):
args['previous_wu'] = int(open(token, 'r').read().strip())
if args['previous_wu'] < args['wu_number']:
print args['appname'] + " Work units will be updated from %s to %s" % (
args['previous_wu'], args['wu_number'])
else:
args['previous_wu'] = 0
newInstall = True
#Sleep until file .start_boinc exist (File indicate that BOINC has been started)
checkFile(args['start_boinc'], 3)
env = os.environ
env['PATH'] = args['environment']['PATH']
env['PYTHONPATH'] = args['environment']['PYTHONPATH']
print "setup directories..."
numversion = args['version'].replace('.', '')
args['inputfile'] = os.path.join(args['installroot'], 'download',
args['appname'] + numversion + '_input')
base_app = os.path.join(args['installroot'], 'apps', args['appname'])
base_app_version = os.path.join(base_app, args['version'])
args['templates'] = os.path.join(args['installroot'], 'templates')
t_result = os.path.join(args['templates'],
args['appname'] + numversion + '_result')
t_wu = os.path.join(args['templates'],
args['appname'] + numversion + '_wu')
binary_name = args['appname'] +"_"+ args['version'] +"_"+ \
args['platform'] + args['extension']
binary = os.path.join(args['application'], binary_name)
signBin = False
if not os.path.exists(base_app):
os.mkdir(base_app)
if newInstall:
if os.path.exists(base_app_version):
shutil.rmtree(base_app_version)
os.mkdir(base_app_version)
os.mkdir(args['application'])
if not os.path.exists(args['templates']):
os.mkdir(args['templates'])
copy_file(args['t_result'], t_result)
copy_file(args['t_wu'], t_wu)
signBin = copy_file(args['binary'], binary)
if args['t_input']:
if os.path.exists(args['inputfile']):
os.unlink(args['inputfile'])
os.symlink(args['t_input'], args['inputfile'])
project_xml = os.path.join(args['installroot'], 'project.xml')
findapp = re.search("<name>(%s)</name>" % args['appname'],
open(project_xml, 'r').read())
if not findapp:
print "Adding '" + args['appname'] + "' to project.xml..."
print "Adding deamon for application to config.xml..."
sed_args = [args['bash'], args['appname'], args['installroot']]
startProcess(sed_args)
if signBin:
print "Sign the application binary..."
sign = os.path.join(args['installroot'], 'bin/sign_executable')
privateKeyFile = os.path.join(args['installroot'], 'keys/code_sign_private')
output = open(binary + '.sig', 'w')
p_sign = subprocess.Popen([sign, binary, privateKeyFile], stdout=output,
stderr=subprocess.STDOUT)
result = p_sign.communicate()[0]
if p_sign.returncode is None or p_sign.returncode != 0:
print "Failed to execute bin/sign_executable.\nThe error was: %s" % result
return
output.close()
print "execute script xadd..."
if not startProcess([os.path.join(args['installroot'], 'bin/xadd')], env):
return
print "Running script bin/update_versions..."
updt_version = os.path.join(args['installroot'], 'bin/update_versions')
p_version = subprocess.Popen([updt_version], stdout=subprocess.PIPE,
stderr=subprocess.STDOUT, stdin=subprocess.PIPE, env=env,
cwd=args['installroot'])
p_version.stdin.write('y\ny\n')
result = p_version.communicate()[0]
p_version.stdin.close()
if p_version.returncode is None or p_version.returncode != 0:
print "Failed to execute bin/update_versions.\nThe error was: %s" % result
return
print "Fill the database... calling bin/create_work..."
create_wu(args, env)
print "Restart Boinc..."
binstart = os.path.join(args['installroot'], 'bin/start')
binstop = os.path.join(args['installroot'], 'bin/stop')
os.system(binstop)
os.system(binstart)
print "Boinc Application deployment is done... writing end signal file..."
writeFile(token, str(args['wu_number']))
def create_wu(args, env):
"""Create or update number of work unit for an existing boinc application"""
numversion = args['version'].replace('.', '')
t_result = "templates/" + args['appname'] + numversion + '_result'
t_wu = "templates/" + args['appname'] + numversion + '_wu'
launch_args = [os.path.join(args['installroot'], 'bin/create_work'),
'--appname', args['appname'], '--wu_name', '',
'--wu_template', t_wu, '--result_template', t_result,
'--min_quorum', '1', '--target_nresults', '1',
args['appname'] + numversion + '_input']
for i in range(args['previous_wu'], args['wu_number']):
print "Creating project wroker %s..." % str(i+1)
launch_args[4] = args['appname'] + str(i+1) + numversion + '_nodelete'
startProcess(launch_args, env, args['installroot'])
def runCmd(args):
"""Wait for Boinc Client started and run boinc cmd"""
client_config = os.path.join(args['installdir'], 'client_state.xml')
checkFile(client_config, 5)
time.sleep(10)
#Scan client state xml to find client ipv4 adress
host = re.search("<ip_addr>([\w\d\.:]+)</ip_addr>",
open(client_config, 'r').read()).group(1)
args['base_cmd'][2] = host + ':' + args['base_cmd'][2]
print "Run boinccmd with host at %s " % args['base_cmd'][2]
project_args = args['base_cmd'] + ['--project_attach', args['project_url'],
args['key']]
startProcess(project_args, cwd=args['installdir'])
if args['cc_cmd'] != '':
#Load or reload cc_config file
startProcess(args['base_cmd'] + [args['cc_cmd']], cwd=args['installdir'])
def writeFile(file, content):
f = open(file, 'w')
f.write(content)
f.close()
#!%(dash)s
sed -i "/remove the die/d" %(installroot)s/html/ops/create_forums.php
sed -i "s#REPLACE WITH PROJECT NAME#%(fullname)s#" %(installroot)s/html/project/project.inc
sed -i "s#REPLACE WITH COPYRIGHT HOLDER#%(copyright)s#" %(installroot)s/html/project/project.inc
sed -i.old -e "/<\/config>/i\<uldl_pid>%(uldl_pid)s</uldl_pid>" %(installroot)s/config.xml
sed -i.old -e "/<\/config>/i\<httpd_user>%(user)s</httpd_user>" %(installroot)s/config.xml
#!%(dash)s
if [ $# -ne 2 ]
then
echo not enough argument.
echo ARGS: appname installroot
else
sed -i.old -e "/<\/boinc>/i\<app>\n<name>$1</name>\n<user_friendly_name>$1</user_friendly_name>\n</app>" $2/project.xml
sed -i.old -e "/<\/daemons>/i\<daemon>\n<cmd>\nsample_bitwise_validator -d 3 -app $1\n</cmd>\n</daemon>" $2/config.xml
sed -i.old -e "/<\/daemons>/i\<daemon>\n<cmd>\nsample_assimilator -d 3 -app $1\n</cmd>\n</daemon>" $2/config.xml
fi
\ No newline at end of file
##############################################################################
#
# Copyright (c) 2010 Vifib SARL and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from slapos.recipe.librecipe import GenericBaseRecipe
import os
import subprocess
import pwd
import signal
import zc.buildout
class Recipe(GenericBaseRecipe):
"""Deploy a fully operational BonjourGrid Master architecture."""
def install(self):
path_list = []
condor_wrapper = self.options['condor-wrapper'].strip()
boinc_wrapper = self.options['boinc-wrapper'].strip()
startCondor = startBoinc = False
condor_wrapper_list = []
boinc_wrapper_list = []
for file in os.listdir(condor_wrapper):
condor_wrapper_list.append(os.path.join(condor_wrapper, file))
for file in os.listdir(boinc_wrapper):
boinc_wrapper_list.append(os.path.join(boinc_wrapper, file))
type = self.options['type'].strip()
if type == "condor":
startCondor = True
project = self.options['condor_host'].strip()
if type == "boinc":
project = self.options['url-boinc'].strip()
startBoinc = True
#Generate BOINC/Condor launcher script
grid_wrapper = self.options['boinc_condor_wrapper'].strip()
parameters = dict(startCondor=startCondor, startBoinc=startBoinc,
bg_base=self.options['work_dir'].strip(),
condor_wrapper_list=condor_wrapper_list,
boinc_wrapper_list=boinc_wrapper_list)
bonjourGrid_wrapper = self.createPythonScript(grid_wrapper,
'%s.configure.launchScript' % __name__,
parameters
)
path_list.append(bonjourGrid_wrapper)
#Generate wrapper for BonjourGrid Master
bonjourgrid_master = self.options['master_script'].strip()
python = self.options['python-bin'].strip()
bg_wrapper = self.options['wrapper'].strip()
log = self.options['log_file'].strip()
pid_file = self.options['pid_file'].strip()
wrapper = self.createPythonScript(bg_wrapper,
'slapos.recipe.librecipe.execute.execute',
([python, bonjourgrid_master, '--log_file', log,
'--pid_file', pid_file,
'--master_wrapper', grid_wrapper,
'--directory', self.options['work_dir'].strip(),
'--server', self.options['redis-url'].strip(),
'--port', self.options['redis-port'].strip(),
'--num_workers', self.options['nworkers'].strip(),
])
)
path_list.append(wrapper)
#generate Computer information file
config_info_file = os.path.join(self.options['work_dir'].strip(),
'machineinfo.sh')
config_info = self.createFile(config_info_file,
self.substituteTemplate(self.getTemplateFilename('machineinfo.sh.in'),
dict(ip_address=self.options['ipv6'].strip(),
project=project,
middleware=type)))
os.chmod(config_info_file, 0744)
path_list.append(config_info)
update = install
class Client(GenericBaseRecipe):
def install(self):
path_list = []
boinc_script = self.options['boinc_script'].strip()
condor_script = self.options['condor_script'].strip()
#Generate wrapper for BonjourGrid Worker
bonjourgrid_client = self.options['client_script'].strip()
python = self.options['python-bin'].strip()
bg_wrapper = self.options['wrapper'].strip()
log = self.options['log_file'].strip()
pid_file = self.options['pid_file'].strip()
wrapper = self.createPythonScript(bg_wrapper,
'slapos.recipe.librecipe.execute.execute',
([python, bonjourgrid_client, '--log_file', log,
'--pid_file', pid_file,
'--boinc_wrapper', boinc_script,
'--condor_wrapper', condor_script,
'--directory', self.options['work_dir'].strip(),
'--install_directory', self.options['install_dir'].strip(),
'--server', self.options['redis-url'].strip(),
'--port', self.options['redis-port'].strip(),
])
)
path_list.append(wrapper)
#generate BOINC and Condor configure script for bonjourgrid
boinc_wrapper = self.createPythonScript(boinc_script,
'%s.boinc.runBoinc' % __name__,
dict(ipv6=self.options['ipv6'].strip(),
email=self.options['email'].strip(),
boinc_wrapper=self.options['boinc_wrapper'].strip(),
boinc_cmd=self.options['boinc_cmd'].strip(),
boinc_rpc_port=self.options['boinc_rpc_port'],
boinc_install_dir=self.options['boinc_install_dir'].strip(),
boinc_passwd=self.options['boinc_passwd'].strip(),
account_name=self.options['account_name'].strip(),
account_passwd=self.options['account_passwd'].strip(),
)
)
path_list.append(boinc_wrapper)
condor_wrapper = self.createPythonScript(condor_script,
'%s.condor.runCondor' % __name__,
dict(ipv6=self.options['ipv6'].strip(),
condor_bin=self.options['condor_bin'].strip(),
condor_sbin=self.options['condor_sbin'].strip(),
condor_wrapper=self.options['condor_wrapper'].strip(),
condor_config=self.options['condor_config'].strip(),
condor_config_local=self.options['condor_config_local'].strip(),
)
)
path_list.append(condor_wrapper)
# -*- coding: utf-8 -*-
import os
import sys
import re
import subprocess
import time
import signal
def startProcess(launch_args, env=None, cwd=None, stdout=subprocess.PIPE):
process = subprocess.Popen(launch_args, stdout=stdout,
stderr=subprocess.STDOUT, env=env,
cwd=cwd)
result = process.communicate()[0]
if process.returncode is None or process.returncode != 0:
raise NameError("Failed to execute executable.\nThe error was: %s" % result)
def joinProject(args, base_cmd):
"""Finish BOINC Client configuration with create account and attach project"""
project_args = base_cmd + ['--project_attach', args['project_url'],
args['key']]
startProcess(project_args, cwd=args['boinc_install_dir'])
def createAccount(config, base_cmd):
"""Connect to BOINC Master and create an account
"""
account_args = base_cmd + ['--create_account', config['project_url'],
config['email'], config['account_passwd'],
config['account_name']]
startProcess(account_args, cwd=config['boinc_install_dir'])
account_file = os.path.join(config['boinc_install_dir'], 'create_account.xml')
key = re.search("<authenticator>([\w\d\._]+)</authenticator>",
open(account_file, 'r').read()).group(1)
return key
def runBoinc(config):
if len(sys.argv) < 2:
print "Argument Error: uses %s project_url" % sys.argv[0]
exit(1)
if type(config) == type(""):
print "Error: bonjourgrid.xml parsing error, file not exist or corrupted"
exit(1)
#XXX Using define values here for Boinc Master URL
config['project_url'] = sys.argv[1]
#launch Boinc Client
boinc = subprocess.Popen([config['boinc_wrapper']],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
#Retrieve ipv4 using by Boinc-client in client-configuration
client_config = os.path.join(config['boinc_install_dir'], 'client_state.xml')
while not os.path.exists(client_config):
time.sleep(5)
print "Search for file '%r'..." % client_config
time.sleep(10)
try:
#Scan client state xml to find client ipv4 adress
host = re.search("<ip_addr>([\w\d\.:]+)</ip_addr>",
open(client_config, 'r').read()).group(1)
base_cmd = [config['boinc_cmd'], '--host',
host + ":" + str(config['boinc_rpc_port']),
'--passwd', config['boinc_passwd']]
#Create Account for current instance on BOINC master
print "Create account for current client..."
key = createAccount(config, base_cmd)
config['key'] = key
print "Done. The account key is %s" % key
#Attach project to Boinc Master
print "Attach client to Boinc Master at %s " % config['project_url']
try:
joinProject(config, base_cmd)
except Exception, e:
print e
print "Done! Waiting for Boinc Client now..."
except Exception, e:
#An error occure!!!
os.kill(boinc.pid, signal.SIGTERM)
print e
#wait for Boinc client execution
boinc.wait()
# -*- coding: utf-8 -*-
import os
import sys
import re
import subprocess
import time
def writeFile(file, content):
f = open(file, 'w')
f.write(content)
f.close()
def updateCondorConfig(path, path_local, hostname, ipv6):
"""Replace Static information into condor_config and condor_config.local files"""
#replace condor host into condor_config
text = open(path, 'r').read()
text = re.sub(r'\[%s\]' % ipv6, hostname, text, flags=re.IGNORECASE)
writeFile(path, text)
#replace condor host into condor_config.local
text = open(path_local, 'r').read()
text = re.sub(r'\[%s\]' % ipv6, hostname, text, flags=re.IGNORECASE)
writeFile(path_local, text)
def updateCondorWrapper(folder, hostname, ipv6):
"""Replace slapos generated value by the true value"""
for file in os.listdir(folder):
path = os.path.join(folder, file)
if os.path.exists(path) and not os.path.isdir(path):
text = re.sub(r'\[%s\]' % ipv6, hostname, open(path, 'r').read(),
flags=re.IGNORECASE)
writeFile(path, text)
def runCondor(config):
if len(sys.argv) < 2:
print "Argument Error: uses %s hostname" % sys.argv[0]
exit(1)
hostname = sys.argv[1]
updateCondorConfig(config['condor_config'], config['condor_config_local'],
hostname, config['ipv6'])
updateCondorWrapper(config['condor_bin'], hostname, config['ipv6'])
updateCondorWrapper(config['condor_sbin'], hostname, config['ipv6'])
#launch Boinc Client
condor = subprocess.Popen([config['condor_wrapper']],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
condor.wait()
##############################################################################
#
# Copyright (c) 2010 Vifib SARL and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import os
import subprocess
import time
def runProcess(args, file):
filename = file.split('/')[-1:][0]
stdout_file = open(os.path.join(args['bg_log'], filename + ".log"), 'w')
process = subprocess.Popen(file, stdout=stdout_file,
stderr=subprocess.STDOUT)
fp = open(os.path.join(args['bg_pid'], filename + '.pid'), 'w')
fp.write(str(process.pid))
fp.close()
return process.pid
def launchScript(args):
print "Sleep for a few second..."
time.sleep(10)
pid_list = []
bg_pid = os.path.join(args['bg_base'], 'pid')
bg_log = os.path.join(args['bg_base'], 'log')
args['bg_pid'] = bg_pid
args['bg_log'] = bg_log
if not os.path.exists(bg_pid):
os.mkdir(bg_pid)
if not os.path.exists(bg_log):
os.mkdir(bg_log)
#launch all Condor wrapper
if args['startCondor']:
for file in args['condor_wrapper_list']:
pid_list.append(runProcess(args, file))
#Launch all BOINC wrapper
if args['startBoinc']:
for file in args['boinc_wrapper_list']:
pid_list.append(runProcess(args, file))
for pid in pid_list:
print "Parent waiting for process child: %s " % pid
result = os.waitpid(pid, 0)
print "Done...", result
# This script generates a file (with the name `hostname`) of the characteristics of the machine
Mhz=`grep -i Mhz /proc/cpuinfo | cut -d : -f2 | head -1 | cut -f2 -d " "`
mem=`grep -i MemTotal /proc/meminfo | cut -f2 -d :`
Ram=`echo $mem | cut -f1 -d " "`
Cpu=`uname -a | cut -f3 -d " "`
H=`hostname`
Nbproc=`grep processor /proc/cpuinfo |wc -l`
Ip=%(ip_address)s
status="in execution"
secours="host1"
middleware="%(middleware)s"
project="%(project)s"
c="{'"MHZ"':\"$Mhz\",'"Ram"':\"$Ram\",'"Cpu"':\"$Cpu\",'"HOST"':\"$H\",'"IP"':\"$Ip\",'"STATUS"':\"$status\",'"SECOURS"':\"$secours\",'"MIDDLEWARE"':\"$middleware\",'"PROJECT"':\"$project\",}"
filename=`hostname`
echo $c > $filename
......@@ -34,11 +34,12 @@ class Recipe(GenericBaseRecipe):
"""
def install(self):
url = self.options['url'].strip()
config = {
'url': self.options['url'],
'url': url,
'shell_path': self.options['dash_path'],
'curl_path': self.options['curl_path'],
'match': self.options.get('match', self.options['url'])
'match': self.options.get('match', url)
}
# XXX-Cedric in this script, curl won't check certificate
......
......@@ -10,7 +10,7 @@ if [ -z $URL ]; then
exit 3
fi
%(curl_path)s -k -sL $URL | grep "$MATCH" > /dev/null
%(curl_path)s -k -sL $URL --max-time 10 | grep "$MATCH" > /dev/null
if [ $? != 0 ]; then
echo "Content at $URL seems to be corrupted" >&2
......
......@@ -9,7 +9,7 @@ if [ -z $URL ]; then
exit 3
fi
CODE=$(%(curl_path)s -g -k -sL $URL -w %%{http_code} -o /dev/null)
CODE=$(%(curl_path)s -g -k -sL $URL -w %%{http_code} --max-time 10 -o /dev/null)
if [ $? -eq 3 ]; then
echo "URL malformed: $URL." >&2
......
##############################################################################
#
# Copyright (c) 2010 Vifib SARL and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from slapos.recipe.librecipe import GenericBaseRecipe
import os
import subprocess
import zc.buildout
import filecmp
import urlparse
import shutil
import re
import json
class Recipe(GenericBaseRecipe):
"""Deploy a fully operational condor architecture."""
def __init__(self, buildout, name, options):
self.environ = {}
self.role = ''
environment_section = options.get('environment-section', '').strip()
if environment_section and environment_section in buildout:
# Use environment variables from the designated config section.
self.environ.update(buildout[environment_section])
for variable in options.get('environment', '').splitlines():
if variable.strip():
try:
key, value = variable.split('=', 1)
self.environ[key.strip()] = value
except ValueError:
raise zc.buildout.UserError('Invalid environment variable definition: %s', variable)
# Extrapolate the environment variables using values from the current
# environment.
for key in self.environ:
self.environ[key] = self.environ[key] % os.environ
return GenericBaseRecipe.__init__(self, buildout, name, options)
def _options(self, options):
#Path of condor compiled package
self.package = options['package'].strip()
self.rootdir = options['rootdirectory'].strip()
#Other condor dependances
self.javabin = options['java-bin'].strip()
self.dash = options['dash'].strip()
#Directory to deploy condor
self.prefix = options['rootdirectory'].strip()
self.localdir = options['local-dir'].strip()
self.wrapperdir = options['wrapper-dir'].strip()
self.wrapper_bin = options['bin'].strip()
self.wrapper_sbin = options['sbin'].strip()
self.diskspace = options['disk-space'].strip()
self.ipv6 = options['ip'].strip()
self.condor_host = options['condor_host'].strip()
self.collector_name = options['collector_name'].strip()
self.host_list = self.options.get('allowed-write', '*')
self.email = self.options.get('admin-email', "root@$(FULL_HOSTNAME)")
def install(self):
path_list = []
#get UID and GID for current slapuser
stat_info = os.stat(self.rootdir)
slapuser = str(stat_info.st_uid)+"."+str(stat_info.st_gid)
domain_name = 'slapos%s.com' % stat_info.st_uid
#Configure condor
configure_script = os.path.join(self.package, 'condor_configure')
install_args = [configure_script, '--install='+self.package,
'--prefix='+self.prefix, '--overwrite', '--verbose',
'--local-dir='+self.localdir] #--ignore-missing-libs
if self.options['machine-role'].strip() == "manager":
self.role = "manager,submit"
elif self.options['machine-role'].strip() == "worker":
self.role = "execute"
install_args += ['--central-manager='+self.condor_host]
install_args += ['--type='+self.role]
configure = subprocess.Popen(install_args, env=self.environ,
stdout=subprocess.PIPE)
configure.communicate()[0]
if configure.returncode is None or configure.returncode != 0:
return path_list
#Generate condor_configure file
condor_config = os.path.join(self.rootdir, 'etc/condor_config')
config_local = os.path.join(self.localdir, 'condor_config.local')
condor_configure = dict(condor_host=self.condor_host, releasedir=self.prefix,
localdir=self.localdir, config_local=config_local,
slapuser=slapuser, ipv6=self.ipv6,
diskspace=self.diskspace, javabin=self.javabin,
host_list=self.host_list, collector_name=self.collector_name,
email=self.email, domain_name=domain_name)
destination = os.path.join(condor_config)
config = self.createFile(destination,
self.substituteTemplate(self.getTemplateFilename('condor_config.generic'),
condor_configure))
path_list.append(config)
#Search if is needed to update condor_config.local file
find = re.search('NETWORK_INTERFACE[\s]*=[\s]*(%s)' % self.ipv6,
open(config_local, 'r').read())
if not find:
#update condor_config.local
with open(config_local, 'a') as f:
if self.role == "execute":
f.write("\nSTART = TRUE")
f.write("\nCOLLECTOR_NAME = %s\n \nNETWORK_INTERFACE=%s" %
(self.collector_name, self.ipv6))
#create condor binary launcher for slapos
if not os.path.exists(self.wrapper_bin):
os.makedirs(self.wrapper_bin, int('0744', 8))
if not os.path.exists(self.wrapper_sbin):
os.makedirs(self.wrapper_sbin, int('0744', 8))
#generate script for each file in prefix/bin
for binary in os.listdir(self.prefix+'/bin'):
wrapper_location = os.path.join(self.wrapper_bin, binary)
current_exe = os.path.join(self.prefix, 'bin', binary)
wrapper = open(wrapper_location, 'w')
content = """#!%s
export LD_LIBRARY_PATH=%s
export PATH=%s
export CONDOR_CONFIG=%s
export CONDOR_LOCATION=%s
export CONDOR_IDS=%s
export HOME=%s
export HOSTNAME=%s
exec %s $*""" % (self.dash,
self.environ['LD_LIBRARY_PATH'], self.environ['PATH'],
condor_config, self.prefix, slapuser, self.environ['HOME'],
self.environ['HOSTNAME'], current_exe)
wrapper.write(content)
wrapper.close()
path_list.append(wrapper_location)
os.chmod(wrapper_location, 0744)
#generate script for each file in prefix/sbin
for binary in os.listdir(self.prefix+'/sbin'):
wrapper_location = os.path.join(self.wrapper_sbin, binary)
current_exe = os.path.join(self.prefix, 'sbin', binary)
wrapper = open(wrapper_location, 'w')
content = """#!%s
export LD_LIBRARY_PATH=%s
export PATH=%s
export CONDOR_CONFIG=%s
export CONDOR_LOCATION=%s
export CONDOR_IDS=%s
export HOME=%s
export HOSTNAME=%s
exec %s $*""" % (self.dash,
self.environ['LD_LIBRARY_PATH'], self.environ['PATH'],
condor_config, self.prefix, slapuser, self.environ['HOME'],
self.environ['HOSTNAME'], current_exe)
wrapper.write(content)
wrapper.close()
path_list.append(wrapper_location)
os.chmod(wrapper_location, 0744)
#generate script for start condor
start_condor = os.path.join(self.wrapperdir, 'start_condor')
start_bin = os.path.join(self.wrapper_sbin, 'condor_master')
condor_reconfig = os.path.join(self.wrapper_sbin, 'condor_reconfig')
wrapper = self.createPythonScript(start_condor,
'%s.configure.condorStart' % __name__,
dict(start_bin=start_bin, condor_reconfig=condor_reconfig)
)
path_list.append(wrapper)
return path_list
class AppSubmit(GenericBaseRecipe):
"""Submit a condor job into an existing Condor master instance"""
def download(self, url, filename=None, md5sum=None):
cache = os.path.join(self.options['rootdirectory'].strip(), 'tmp')
if not os.path.exists(cache):
os.mkdir(cache)
downloader = zc.buildout.download.Download(self.buildout['buildout'],
hash_name=True, cache=cache)
path, _ = downloader(url, md5sum)
if filename:
name = os.path.join(cache, filename)
os.rename(path, name)
return name
return path
def copy_file(self, source, dest):
""""Copy file with source to dest with auto replace
return True if file has been copied and dest ha been replaced
"""
result = False
if source and os.path.exists(source):
if os.path.exists(dest):
if filecmp.cmp(dest, source):
return False
os.unlink(dest)
result = True
shutil.copy(source, dest)
return result
def getFiles(self):
"""This is used to download app files if necessary and update options values"""
app_list = json.loads(self.options['condor-app-list'])
if not app_list:
return None
for app in app_list:
if app_list[app].get('files', None):
file_list = app_list[app]['files']
for file in file_list:
if file and (file.startswith('http') or file.startswith('ftp')):
file_list[file] = self.download(file_list[file])
os.chmod(file_list[file], 0600)
else:
app_list[app]['files'] = {}
executable = app_list[app].get('executable', '')
if executable and (executable.startswith('http') or executable.startswith('ftp')):
app_list[app]['executable'] = self.download(executable,
app_list[app]['executable-name'])
os.chmod(app_list[app]['executable-name'], 0700)
submit_file = app_list[app].get('description-file', '')
if submit_file and (submit_file.startswith('http') or submit_file.startswith('ftp')):
app_list[app]['description-file'] = self.download(submit_file, 'submit')
os.chmod(app_list[app]['description-file'], 0600)
return app_list
def install(self):
path_list = []
#check if curent condor instance is an condor master
if self.options['machine-role'].strip() != "manager":
raise Exception("Cannot submit a job to Condor worker instance")
#Setup directory
jobdir = self.options['job-dir'].strip()
if not os.path.exists(jobdir):
os.mkdir(jobdir)
app_list = self.getFiles()
for appname in app_list:
appdir = os.path.join(jobdir, appname)
if not os.path.exists(appdir):
os.mkdir(appdir)
submitfile = os.path.join(appdir, 'submit')
self.copy_file(app_list[appname]['executable'],
os.path.join(appdir, app_list[appname]['executable-name'])
)
install = self.copy_file(app_list[appname]['description-file'], submitfile)
sig_install = os.path.join(appdir, '.install')
if install:
with open(sig_install, 'w') as f:
f.write('to_install')
for file in app_list[appname]['files']:
destination = os.path.join(appdir, file)
if os.path.exists(destination):
os.unlink(destination)
os.symlink(app_list[appname]['files'][file], destination)
#generate wrapper for submitting job
condor_submit = os.path.join(self.options['bin'].strip(), 'condor_submit')
parameter = dict(submit=condor_submit, sig_install=sig_install,
submit_file='submit',
appname=appname, appdir=appdir)
submit_job = self.createPythonScript(
os.path.join(self.options['wrapper-dir'].strip(), appname),
'%s.configure.submitJob' % __name__, parameter
)
path_list.append(submit_job)
return path_list
\ No newline at end of file
##############################################################################
#
# Copyright (c) 2010 Vifib SARL and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import os
import subprocess
import time
def submitJob(args):
"""Run condor_submit (if needed) for job deployment"""
time.sleep(10)
print "Check if needed to submit %s job's" % args['appname']
if not os.path.exists(args['sig_install']):
print "Nothing for install or update...Exited"
return
# '-a', "log = out.log", '-a', "error = error.log",
launch_args = [args['submit'], '-verbose', args['submit_file']]
process = subprocess.Popen(launch_args, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT, cwd=args['appdir'])
result = process.communicate()[0]
if process.returncode is None or process.returncode != 0:
print "Failed to execute condor_submit.\nThe error was: %s" % result
else:
os.unlink(args['sig_install'])
def condorStart(args):
"""Start Condor if deamons is currently stopped"""
result = os.system(args['condor_reconfig'])
if result != 0:
#process failled to reconfig condor that mean that condor deamons is not curently started
os.system(args['start_bin'])
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
## Pathnames:
## Where have you installed the bin, sbin and lib condor directories?
RELEASE_DIR = %(releasedir)s
## Where is the local condor directory for each host?
## This is where the local config file(s), logs and
## spool/execute directories are located
LOCAL_DIR = %(localdir)s
## Mail parameters:
## When something goes wrong with condor at your site, who should get
## the email?
CONDOR_ADMIN =
## The user/group ID <uid>.<gid> of the "Condor" user.
## (this can also be specified in the environment)
## Note: the CONDOR_IDS setting is ignored on Win32 platforms
CONDOR_IDS = %(slapuser)s
## Condor needs to create a few lock files to synchronize access to
## various log files. Because of problems we've had with network
## filesystems and file locking over the years, we HIGHLY recommend
## that you put these lock files on a local partition on each
## machine. If you don't have your LOCAL_DIR on a local partition,
## be sure to change this entry. Whatever user (or group) condor is
## running as needs to have write access to this directory. If
## you're not running as root, this is whatever user you started up
## the condor_master as. If you are running as root, and there's a
## condor account, it's probably condor. Otherwise, it's whatever
## you've set in the CONDOR_IDS environment variable. See the Admin
## manual for details on this.
LOCK = /tmp/condor-lock.$(HOSTNAME)0.829500835462571
DAEMON_LIST = MASTER, SCHEDD, STARTD
## Java parameters:
## If you would like this machine to be able to run Java jobs,
## then set JAVA to the path of your JVM binary. If you are not
## interested in Java, there is no harm in leaving this entry
## empty or incorrect.
JAVA = %(java-bin)s
JAVA_MAXHEAP_ARGUMENT = -Xmx1024m
......@@ -38,16 +38,20 @@ class Recipe(GenericBaseRecipe):
port=int(self.options['port']),
openoffice_port=int(self.options['openoffice-port']),
)
environment_variable_list = []
for env_line in self.options['environment'].splitlines():
env_line = env_line.strip()
if not env_line:
continue
if '=' in env_line:
env_key, env_value = env_line.split('=')
conversion_server_dict[env_key.strip()] = env_value.strip()
environment_variable_list.append((env_key.strip(), env_value.strip()))
else:
raise zc.buildout.UserError('Line %r in environment parameter is '
'incorrect' % env_line)
conversion_server_dict['ENVIRONMENT_VARIABLE_LIST'] = '\n'.join(
['env-%s = %s' % (key, value) for key, value in environment_variable_list]
)
config_file = self.createFile(self.options['configuration-file'],
self.substituteTemplate(self.getTemplateFilename('cloudooo.cfg.in'),
conversion_server_dict))
......
......@@ -33,9 +33,9 @@ application_hostname = %(ip)s
# OpenOffice Port
openoffice_port = %(openoffice_port)s
# LD_LIBRARY_PATH passed to OpenOffice
env-LD_LIBRARY_PATH = %(LD_LIBRARY_PATH)s
env-FONTCONFIG_FILE = %(FONTCONFIG_FILE)s
# LD_LIBRARY_PATH and other environment variables
# passed to OpenOffice
%(ENVIRONMENT_VARIABLE_LIST)s
#
# Mimetype Registry
......
......@@ -34,6 +34,22 @@ def runMysql(args):
print "Starting %r" % mysqld_wrapper_list[0]
sys.stdout.flush()
sys.stderr.flush()
# try to increase the maximum number of open file descriptors.
# it seems that mysqld requires (max_connections + 810) file descriptors.
# to make it possible, you need to set the hard limit of nofile in
# /etc/security/limits.conf like the following :
# @slapsoft hard nofile 2048
try:
import resource
required_nofile = 2048 # XXX hardcoded value more than 1000 + 810
nofile_limit_list = [max(x, required_nofile) for x in resource.getrlimit(resource.RLIMIT_NOFILE)]
resource.setrlimit(resource.RLIMIT_NOFILE, nofile_limit_list)
except ImportError:
# resource library is only available on Unix platform.
pass
except ValueError:
# 'ValueError: not allowed to raise maximum limit'
pass
os.execl(mysqld_wrapper_list[0], *mysqld_wrapper_list)
......
......@@ -23,6 +23,7 @@ slow_query_log_file = %(slow_query_log)s
long_query_time = 1
max_allowed_packet = 128M
query_cache_size = 0
query_cache_type = 0
plugin-load = ha_mroonga.so;handlersocket.so
......
......@@ -36,8 +36,12 @@ class Recipe(GenericBaseRecipe):
binary-path -- location of the haproxy command
ctl-path -- location of the haproxy control script
conf-path -- location of the configuration file
socket-path -- location of the socket file for administration
ip -- ip of the haproxy server
port -- port of the haproxy server
......@@ -108,6 +112,7 @@ class Recipe(GenericBaseRecipe):
self.options['conf-path'],
self.substituteTemplate(
self.getTemplateFilename('haproxy.cfg.in'),
{'socket_path': self.options['socket-path']},
{'server_text': server_snippet},
)
)
......@@ -115,4 +120,8 @@ class Recipe(GenericBaseRecipe):
self.options['wrapper-path'],
'slapos.recipe.librecipe.execute.execute',
arguments=[self.options['binary-path'].strip(), '-f', configuration_path],)
return [configuration_path, wrapper_path]
ctl_path = self.createPythonScript(
self.options['ctl-path'],
'%s.haproxy.haproxyctl' % __name__,
{'socket_path':self.options['socket-path']})
return [configuration_path, wrapper_path, ctl_path]
import socket
try:
import readline
except ImportError:
pass
def haproxyctl(conf):
while True:
try:
l = raw_input('> ')
except EOFError:
print
break
if l == 'quit':
break
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
s.connect(conf['socket_path'])
s.send('%s\n' % l)
while True:
r = s.recv(1024)
if not r:
break
print r
s.close()
global
maxconn 4096
stats socket %(socket_path)s level admin
defaults
log global
......
......@@ -128,7 +128,8 @@ class GenericBaseRecipe(object):
path, arguments=arguments)[0]
return script
def createWrapper(self, name, command, parameters, comments=[], parameters_extra=False):
def createWrapper(self, name, command, parameters, comments=[],
parameters_extra=False, environment=None):
"""
Creates a very simple (one command) shell script for process replacement.
Takes care of quoting.
......@@ -139,6 +140,10 @@ class GenericBaseRecipe(object):
for comment in comments:
lines.append('# %s' % comment)
if environment:
for key in environment:
lines.append('export %s=%s' % (key, environment[key]))
lines.append('exec %s' % shlex.quote(command))
for param in parameters:
......
from __future__ import with_statement
"Core exceptions raised by the Redis client"
class RedisError(Exception):
pass
class AuthenticationError(RedisError):
pass
class ConnectionError(RedisError):
pass
class ResponseError(RedisError):
pass
class InvalidResponse(RedisError):
pass
class DataError(RedisError):
pass
class PubSubError(RedisError):
pass
class WatchError(RedisError):
pass
import socket
from itertools import chain, imap
#from redis.exceptions import ConnectionError, ResponseError, InvalidResponse
try:
from cStringIO import StringIO
except ImportError:
from StringIO import StringIO
class PythonParser(object):
"Plain Python parsing class"
MAX_READ_LENGTH = 1000000
def __init__(self):
self._fp = None
def __del__(self):
try:
self.on_disconnect()
except:
pass
def on_connect(self, connection):
"Called when the socket connects"
self._fp = connection._sock.makefile('r')
def on_disconnect(self):
"Called when the socket disconnects"
if self._fp is not None:
self._fp.close()
self._fp = None
def read(self, length=None):
"""
Read a line from the socket is no length is specified,
otherwise read ``length`` bytes. Always strip away the newlines.
"""
try:
if length is not None:
bytes_left = length + 2 # read the line ending
if length > self.MAX_READ_LENGTH:
# apparently reading more than 1MB or so from a windows
# socket can cause MemoryErrors. See:
# https://github.com/andymccurdy/redis-py/issues/205
# read smaller chunks at a time to work around this
try:
buf = StringIO()
while bytes_left > 0:
read_len = min(bytes_left, self.MAX_READ_LENGTH)
buf.write(self._fp.read(read_len))
bytes_left -= read_len
buf.seek(0)
return buf.read(length)
finally:
buf.close()
return self._fp.read(bytes_left)[:-2]
# no length, read a full line
return self._fp.readline()[:-2]
except (socket.error, socket.timeout), e:
raise ConnectionError("Error while reading from socket: %s" % \
(e.args,))
def read_response(self):
response = self.read()
if not response:
raise ConnectionError("Socket closed on remote end")
byte, response = response[0], response[1:]
# server returned an error
if byte == '-':
if response.startswith('ERR '):
response = response[4:]
return ResponseError(response)
if response.startswith('LOADING '):
# If we're loading the dataset into memory, kill the socket
# so we re-initialize (and re-SELECT) next time.
raise ConnectionError("Redis is loading data into memory")
# single value
elif byte == '+':
return response
# int value
elif byte == ':':
return long(response)
# bulk response
elif byte == '$':
length = int(response)
if length == -1:
return None
response = self.read(length)
return response
# multi-bulk response
elif byte == '*':
length = int(response)
if length == -1:
return None
return [self.read_response() for i in xrange(length)]
raise InvalidResponse("Protocol Error")
class HiredisParser(object):
"Parser class for connections using Hiredis"
def __del__(self):
try:
self.on_disconnect()
except:
pass
def on_connect(self, connection):
self._sock = connection._sock
self._reader = hiredis.Reader(
protocolError=InvalidResponse,
replyError=ResponseError)
def on_disconnect(self):
self._sock = None
self._reader = None
def read_response(self):
if not self._reader:
raise ConnectionError("Socket closed on remote end")
response = self._reader.gets()
while response is False:
try:
buffer = self._sock.recv(4096)
except (socket.error, socket.timeout), e:
raise ConnectionError("Error while reading from socket: %s" % \
(e.args,))
if not buffer:
raise ConnectionError("Socket closed on remote end")
self._reader.feed(buffer)
# proactively, but not conclusively, check if more data is in the
# buffer. if the data received doesn't end with \n, there's more.
if not buffer.endswith('\n'):
continue
response = self._reader.gets()
return response
try:
import hiredis
DefaultParser = HiredisParser
except ImportError:
DefaultParser = PythonParser
class Connection(object):
"Manages TCP communication to and from a Redis server"
def __init__(self, host='localhost', port=6379, db=0, password=None,
socket_timeout=None, encoding='utf-8',
encoding_errors='strict', parser_class=DefaultParser):
self.host = host
self.port = port
self.db = db
self.password = password
self.socket_timeout = socket_timeout
self.encoding = encoding
self.encoding_errors = encoding_errors
self._sock = None
self._parser = parser_class()
def __del__(self):
try:
self.disconnect()
except:
pass
def connect(self):
"Connects to the Redis server if not already connected"
if self._sock:
return
try:
sock = self._connect()
except socket.error, e:
raise ConnectionError(self._error_message(e))
self._sock = sock
self.on_connect()
def _connect(self):
"Create a TCP socket connection"
sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
sock.settimeout(self.socket_timeout)
sock.connect((self.host, self.port))
return sock
def _error_message(self, exception):
# args for socket.error can either be (errno, "message")
# or just "message"
if len(exception.args) == 1:
return "Error connecting to %s:%s. %s." % \
(self.host, self.port, exception.args[0])
else:
return "Error %s connecting %s:%s. %s." % \
(exception.args[0], self.host, self.port, exception.args[1])
def on_connect(self):
"Initialize the connection, authenticate and select a database"
self._parser.on_connect(self)
# if a password is specified, authenticate
if self.password:
self.send_command('AUTH', self.password)
if self.read_response() != 'OK':
raise ConnectionError('Invalid Password')
# if a database is specified, switch to it
if self.db:
self.send_command('SELECT', self.db)
if self.read_response() != 'OK':
raise ConnectionError('Invalid Database')
def disconnect(self):
"Disconnects from the Redis server"
self._parser.on_disconnect()
if self._sock is None:
return
try:
self._sock.close()
except socket.error:
pass
self._sock = None
def send_packed_command(self, command):
"Send an already packed command to the Redis server"
if not self._sock:
self.connect()
try:
self._sock.sendall(command)
except socket.error, e:
self.disconnect()
if len(e.args) == 1:
_errno, errmsg = 'UNKNOWN', e.args[0]
else:
_errno, errmsg = e.args
raise ConnectionError("Error %s while writing to socket. %s." % \
(_errno, errmsg))
except:
self.disconnect()
raise
def send_command(self, *args):
"Pack and send a command to the Redis server"
self.send_packed_command(self.pack_command(*args))
def read_response(self):
"Read the response from a previously sent command"
try:
response = self._parser.read_response()
except:
self.disconnect()
raise
if response.__class__ == ResponseError:
raise response
return response
def encode(self, value):
"Return a bytestring representation of the value"
if isinstance(value, unicode):
return value.encode(self.encoding, self.encoding_errors)
return str(value)
def pack_command(self, *args):
"Pack a series of arguments into a value Redis command"
command = ['$%s\r\n%s\r\n' % (len(enc_value), enc_value)
for enc_value in imap(self.encode, args)]
return '*%s\r\n%s' % (len(command), ''.join(command))
class UnixDomainSocketConnection(Connection):
def __init__(self, path='', db=0, password=None,
socket_timeout=None, encoding='utf-8',
encoding_errors='strict', parser_class=DefaultParser):
self.path = path
self.db = db
self.password = password
self.socket_timeout = socket_timeout
self.encoding = encoding
self.encoding_errors = encoding_errors
self._sock = None
self._parser = parser_class()
def _connect(self):
"Create a Unix domain socket connection"
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock.settimeout(self.socket_timeout)
sock.connect(self.path)
return sock
def _error_message(self, exception):
# args for socket.error can either be (errno, "message")
# or just "message"
if len(exception.args) == 1:
return "Error connecting to unix socket: %s. %s." % \
(self.path, exception.args[0])
else:
return "Error %s connecting to unix socket: %s. %s." % \
(exception.args[0], self.path, exception.args[1])
# TODO: add ability to block waiting on a connection to be released
class ConnectionPool(object):
"Generic connection pool"
def __init__(self, connection_class=Connection, max_connections=None,
**connection_kwargs):
self.connection_class = connection_class
self.connection_kwargs = connection_kwargs
self.max_connections = max_connections or 2**31
self._created_connections = 0
self._available_connections = []
self._in_use_connections = set()
def get_connection(self, command_name, *keys, **options):
"Get a connection from the pool"
try:
connection = self._available_connections.pop()
except IndexError:
connection = self.make_connection()
self._in_use_connections.add(connection)
return connection
def make_connection(self):
"Create a new connection"
if self._created_connections >= self.max_connections:
raise ConnectionError("Too many connections")
self._created_connections += 1
return self.connection_class(**self.connection_kwargs)
def release(self, connection):
"Releases the connection back to the pool"
self._in_use_connections.remove(connection)
self._available_connections.append(connection)
def disconnect(self):
"Disconnects all connections in the pool"
all_conns = chain(self._available_connections, self._in_use_connections)
for connection in all_conns:
connection.disconnect()
import datetime
import time
import warnings
from itertools import imap, izip, starmap
#from redis.connection import ConnectionPool, UnixDomainSocketConnection
#from redis.exceptions import (
# ConnectionError,
# DataError,
# RedisError,
# ResponseError,
# WatchError,
#)
def list_or_args(keys, args):
# returns a single list combining keys and args
try:
i = iter(keys)
# a string can be iterated, but indicates
# keys wasn't passed as a list
if isinstance(keys, basestring):
keys = [keys]
except TypeError:
keys = [keys]
if args:
keys.extend(args)
return keys
def timestamp_to_datetime(response):
"Converts a unix timestamp to a Python datetime object"
if not response:
return None
try:
response = int(response)
except ValueError:
return None
return datetime.datetime.fromtimestamp(response)
def string_keys_to_dict(key_string, callback):
return dict.fromkeys(key_string.split(), callback)
def dict_merge(*dicts):
merged = {}
[merged.update(d) for d in dicts]
return merged
def parse_debug_object(response):
"Parse the results of Redis's DEBUG OBJECT command into a Python dict"
# The 'type' of the object is the first item in the response, but isn't
# prefixed with a name
response = 'type:' + response
response = dict([kv.split(':') for kv in response.split()])
# parse some expected int values from the string response
# note: this cmd isn't spec'd so these may not appear in all redis versions
int_fields = ('refcount', 'serializedlength', 'lru', 'lru_seconds_idle')
for field in int_fields:
if field in response:
response[field] = int(response[field])
return response
def parse_object(response, infotype):
"Parse the results of an OBJECT command"
if infotype in ('idletime', 'refcount'):
return int(response)
return response
def parse_info(response):
"Parse the result of Redis's INFO command into a Python dict"
info = {}
def get_value(value):
if ',' not in value:
return value
sub_dict = {}
for item in value.split(','):
k, v = item.rsplit('=', 1)
try:
sub_dict[k] = int(v)
except ValueError:
sub_dict[k] = v
return sub_dict
for line in response.splitlines():
if line and not line.startswith('#'):
key, value = line.split(':')
try:
if '.' in value:
info[key] = float(value)
else:
info[key] = int(value)
except ValueError:
info[key] = get_value(value)
return info
def pairs_to_dict(response):
"Create a dict given a list of key/value pairs"
it = iter(response)
return dict(izip(it, it))
def zset_score_pairs(response, **options):
"""
If ``withscores`` is specified in the options, return the response as
a list of (value, score) pairs
"""
if not response or not options['withscores']:
return response
score_cast_func = options.get('score_cast_func', float)
it = iter(response)
return zip(it, imap(score_cast_func, it))
def int_or_none(response):
if response is None:
return None
return int(response)
def float_or_none(response):
if response is None:
return None
return float(response)
def parse_config(response, **options):
# this is stupid, but don't have a better option right now
if options['parse'] == 'GET':
return response and pairs_to_dict(response) or {}
return response == 'OK'
class StrictRedis(object):
"""
Implementation of the Redis protocol.
This abstract class provides a Python interface to all Redis commands
and an implementation of the Redis protocol.
Connection and Pipeline derive from this, implementing how
the commands are sent and received to the Redis server
"""
RESPONSE_CALLBACKS = dict_merge(
string_keys_to_dict(
'AUTH DEL EXISTS EXPIRE EXPIREAT HDEL HEXISTS HMSET MOVE MSETNX '
'PERSIST RENAMENX SISMEMBER SMOVE SETEX SETNX SREM ZREM',
bool
),
string_keys_to_dict(
'DECRBY GETBIT HLEN INCRBY LINSERT LLEN LPUSHX RPUSHX SADD SCARD '
'SDIFFSTORE SETBIT SETRANGE SINTERSTORE STRLEN SUNIONSTORE ZADD '
'ZCARD ZREMRANGEBYRANK ZREMRANGEBYSCORE',
int
),
string_keys_to_dict(
# these return OK, or int if redis-server is >=1.3.4
'LPUSH RPUSH',
lambda r: isinstance(r, long) and r or r == 'OK'
),
string_keys_to_dict('ZSCORE ZINCRBY', float_or_none),
string_keys_to_dict(
'FLUSHALL FLUSHDB LSET LTRIM MSET RENAME '
'SAVE SELECT SET SHUTDOWN SLAVEOF WATCH UNWATCH',
lambda r: r == 'OK'
),
string_keys_to_dict('BLPOP BRPOP', lambda r: r and tuple(r) or None),
string_keys_to_dict('SDIFF SINTER SMEMBERS SUNION',
lambda r: r and set(r) or set()
),
string_keys_to_dict('ZRANGE ZRANGEBYSCORE ZREVRANGE ZREVRANGEBYSCORE',
zset_score_pairs
),
string_keys_to_dict('ZRANK ZREVRANK', int_or_none),
{
'BGREWRITEAOF': lambda r: \
r == 'Background rewriting of AOF file started',
'BGSAVE': lambda r: r == 'Background saving started',
'BRPOPLPUSH': lambda r: r and r or None,
'CONFIG': parse_config,
'DEBUG': parse_debug_object,
'HGETALL': lambda r: r and pairs_to_dict(r) or {},
'INFO': parse_info,
'LASTSAVE': timestamp_to_datetime,
'OBJECT': parse_object,
'PING': lambda r: r == 'PONG',
'RANDOMKEY': lambda r: r and r or None,
}
)
def __init__(self, host='localhost', port=6379,
db=0, password=None, socket_timeout=None,
connection_pool=None,
charset='utf-8', errors='strict', unix_socket_path=None):
if not connection_pool:
kwargs = {
'db': db,
'password': password,
'socket_timeout': socket_timeout,
'encoding': charset,
'encoding_errors': errors
}
# based on input, setup appropriate connection args
if unix_socket_path:
kwargs.update({
'path': unix_socket_path,
'connection_class': UnixDomainSocketConnection
})
else:
kwargs.update({
'host': host,
'port': port
})
connection_pool = ConnectionPool(**kwargs)
self.connection_pool = connection_pool
self.response_callbacks = self.__class__.RESPONSE_CALLBACKS.copy()
def set_response_callback(self, command, callback):
"Set a custom Response Callback"
self.response_callbacks[command] = callback
def pipeline(self, transaction=True, shard_hint=None):
"""
Return a new pipeline object that can queue multiple commands for
later execution. ``transaction`` indicates whether all commands
should be executed atomically. Apart from making a group of operations
atomic, pipelines are useful for reducing the back-and-forth overhead
between the client and server.
"""
return StrictPipeline(
self.connection_pool,
self.response_callbacks,
transaction,
shard_hint)
def transaction(self, func, *watches, **kwargs):
"""
Convenience method for executing the callable `func` as a transaction
while watching all keys specified in `watches`. The 'func' callable
should expect a single arguement which is a Pipeline object.
"""
shard_hint = kwargs.pop('shard_hint', None)
with self.pipeline(True, shard_hint) as pipe:
while 1:
try:
pipe.watch(*watches)
func(pipe)
return pipe.execute()
except WatchError:
continue
def lock(self, name, timeout=None, sleep=0.1):
"""
Return a new Lock object using key ``name`` that mimics
the behavior of threading.Lock.
If specified, ``timeout`` indicates a maximum life for the lock.
By default, it will remain locked until release() is called.
``sleep`` indicates the amount of time to sleep per loop iteration
when the lock is in blocking mode and another client is currently
holding the lock.
"""
return Lock(self, name, timeout=timeout, sleep=sleep)
def pubsub(self, shard_hint=None):
"""
Return a Publish/Subscribe object. With this object, you can
subscribe to channels and listen for messages that get published to
them.
"""
return PubSub(self.connection_pool, shard_hint)
#### COMMAND EXECUTION AND PROTOCOL PARSING ####
def execute_command(self, *args, **options):
"Execute a command and return a parsed response"
pool = self.connection_pool
command_name = args[0]
connection = pool.get_connection(command_name, **options)
try:
connection.send_command(*args)
return self.parse_response(connection, command_name, **options)
except ConnectionError:
connection.disconnect()
connection.send_command(*args)
return self.parse_response(connection, command_name, **options)
finally:
pool.release(connection)
def parse_response(self, connection, command_name, **options):
"Parses a response from the Redis server"
response = connection.read_response()
if command_name in self.response_callbacks:
return self.response_callbacks[command_name](response, **options)
return response
#### SERVER INFORMATION ####
def bgrewriteaof(self):
"Tell the Redis server to rewrite the AOF file from data in memory."
return self.execute_command('BGREWRITEAOF')
def bgsave(self):
"""
Tell the Redis server to save its data to disk. Unlike save(),
this method is asynchronous and returns immediately.
"""
return self.execute_command('BGSAVE')
def config_get(self, pattern="*"):
"Return a dictionary of configuration based on the ``pattern``"
return self.execute_command('CONFIG', 'GET', pattern, parse='GET')
def config_set(self, name, value):
"Set config item ``name`` with ``value``"
return self.execute_command('CONFIG', 'SET', name, value, parse='SET')
def dbsize(self):
"Returns the number of keys in the current database"
return self.execute_command('DBSIZE')
def debug_object(self, key):
"Returns version specific metainformation about a give key"
return self.execute_command('DEBUG', 'OBJECT', key)
def delete(self, *names):
"Delete one or more keys specified by ``names``"
return self.execute_command('DEL', *names)
__delitem__ = delete
def echo(self, value):
"Echo the string back from the server"
return self.execute_command('ECHO', value)
def flushall(self):
"Delete all keys in all databases on the current host"
return self.execute_command('FLUSHALL')
def flushdb(self):
"Delete all keys in the current database"
return self.execute_command('FLUSHDB')
def info(self):
"Returns a dictionary containing information about the Redis server"
return self.execute_command('INFO')
def lastsave(self):
"""
Return a Python datetime object representing the last time the
Redis database was saved to disk
"""
return self.execute_command('LASTSAVE')
def object(self, infotype, key):
"Return the encoding, idletime, or refcount about the key"
return self.execute_command('OBJECT', infotype, key, infotype=infotype)
def ping(self):
"Ping the Redis server"
return self.execute_command('PING')
def save(self):
"""
Tell the Redis server to save its data to disk,
blocking until the save is complete
"""
return self.execute_command('SAVE')
def shutdown(self):
"Shutdown the server"
try:
self.execute_command('SHUTDOWN')
except ConnectionError:
# a ConnectionError here is expected
return
raise RedisError("SHUTDOWN seems to have failed.")
def slaveof(self, host=None, port=None):
"""
Set the server to be a replicated slave of the instance identified
by the ``host`` and ``port``. If called without arguements, the
instance is promoted to a master instead.
"""
if host is None and port is None:
return self.execute_command("SLAVEOF", "NO", "ONE")
return self.execute_command("SLAVEOF", host, port)
#### BASIC KEY COMMANDS ####
def append(self, key, value):
"""
Appends the string ``value`` to the value at ``key``. If ``key``
doesn't already exist, create it with a value of ``value``.
Returns the new length of the value at ``key``.
"""
return self.execute_command('APPEND', key, value)
def decr(self, name, amount=1):
"""
Decrements the value of ``key`` by ``amount``. If no key exists,
the value will be initialized as 0 - ``amount``
"""
return self.execute_command('DECRBY', name, amount)
def exists(self, name):
"Returns a boolean indicating whether key ``name`` exists"
return self.execute_command('EXISTS', name)
__contains__ = exists
def expire(self, name, time):
"Set an expire flag on key ``name`` for ``time`` seconds"
return self.execute_command('EXPIRE', name, time)
def expireat(self, name, when):
"""
Set an expire flag on key ``name``. ``when`` can be represented
as an integer indicating unix time or a Python datetime object.
"""
if isinstance(when, datetime.datetime):
when = int(time.mktime(when.timetuple()))
return self.execute_command('EXPIREAT', name, when)
def get(self, name):
"""
Return the value at key ``name``, or None if the key doesn't exist
"""
return self.execute_command('GET', name)
def __getitem__(self, name):
"""
Return the value at key ``name``, raises a KeyError if the key
doesn't exist.
"""
value = self.get(name)
if value:
return value
raise KeyError(name)
def getbit(self, name, offset):
"Returns a boolean indicating the value of ``offset`` in ``name``"
return self.execute_command('GETBIT', name, offset)
def getset(self, name, value):
"""
Set the value at key ``name`` to ``value`` if key doesn't exist
Return the value at key ``name`` atomically
"""
return self.execute_command('GETSET', name, value)
def incr(self, name, amount=1):
"""
Increments the value of ``key`` by ``amount``. If no key exists,
the value will be initialized as ``amount``
"""
return self.execute_command('INCRBY', name, amount)
def keys(self, pattern='*'):
"Returns a list of keys matching ``pattern``"
return self.execute_command('KEYS', pattern)
def mget(self, keys, *args):
"""
Returns a list of values ordered identically to ``keys``
"""
keys = list_or_args(keys, args)
return self.execute_command('MGET', *keys)
def mset(self, mapping):
"Sets each key in the ``mapping`` dict to its corresponding value"
items = []
for pair in mapping.iteritems():
items.extend(pair)
return self.execute_command('MSET', *items)
def msetnx(self, mapping):
"""
Sets each key in the ``mapping`` dict to its corresponding value if
none of the keys are already set
"""
items = []
for pair in mapping.iteritems():
items.extend(pair)
return self.execute_command('MSETNX', *items)
def move(self, name, db):
"Moves the key ``name`` to a different Redis database ``db``"
return self.execute_command('MOVE', name, db)
def persist(self, name):
"Removes an expiration on ``name``"
return self.execute_command('PERSIST', name)
def randomkey(self):
"Returns the name of a random key"
return self.execute_command('RANDOMKEY')
def rename(self, src, dst):
"""
Rename key ``src`` to ``dst``
"""
return self.execute_command('RENAME', src, dst)
def renamenx(self, src, dst):
"Rename key ``src`` to ``dst`` if ``dst`` doesn't already exist"
return self.execute_command('RENAMENX', src, dst)
def set(self, name, value):
"Set the value at key ``name`` to ``value``"
return self.execute_command('SET', name, value)
__setitem__ = set
def setbit(self, name, offset, value):
"""
Flag the ``offset`` in ``name`` as ``value``. Returns a boolean
indicating the previous value of ``offset``.
"""
value = value and 1 or 0
return self.execute_command('SETBIT', name, offset, value)
def setex(self, name, time, value):
"""
Set the value of key ``name`` to ``value``
that expires in ``time`` seconds
"""
return self.execute_command('SETEX', name, time, value)
def setnx(self, name, value):
"Set the value of key ``name`` to ``value`` if key doesn't exist"
return self.execute_command('SETNX', name, value)
def setrange(self, name, offset, value):
"""
Overwrite bytes in the value of ``name`` starting at ``offset`` with
``value``. If ``offset`` plus the length of ``value`` exceeds the
length of the original value, the new value will be larger than before.
If ``offset`` exceeds the length of the original value, null bytes
will be used to pad between the end of the previous value and the start
of what's being injected.
Returns the length of the new string.
"""
return self.execute_command('SETRANGE', name, offset, value)
def strlen(self, name):
"Return the number of bytes stored in the value of ``name``"
return self.execute_command('STRLEN', name)
def substr(self, name, start, end=-1):
"""
Return a substring of the string at key ``name``. ``start`` and ``end``
are 0-based integers specifying the portion of the string to return.
"""
return self.execute_command('SUBSTR', name, start, end)
def ttl(self, name):
"Returns the number of seconds until the key ``name`` will expire"
return self.execute_command('TTL', name)
def type(self, name):
"Returns the type of key ``name``"
return self.execute_command('TYPE', name)
def watch(self, *names):
"""
Watches the values at keys ``names``, or None if the key doesn't exist
"""
warnings.warn(DeprecationWarning('Call WATCH from a Pipeline object'))
def unwatch(self):
"""
Unwatches the value at key ``name``, or None of the key doesn't exist
"""
warnings.warn(DeprecationWarning('Call UNWATCH from a Pipeline object'))
#### LIST COMMANDS ####
def blpop(self, keys, timeout=0):
"""
LPOP a value off of the first non-empty list
named in the ``keys`` list.
If none of the lists in ``keys`` has a value to LPOP, then block
for ``timeout`` seconds, or until a value gets pushed on to one
of the lists.
If timeout is 0, then block indefinitely.
"""
if timeout is None:
timeout = 0
if isinstance(keys, basestring):
keys = [keys]
else:
keys = list(keys)
keys.append(timeout)
return self.execute_command('BLPOP', *keys)
def brpop(self, keys, timeout=0):
"""
RPOP a value off of the first non-empty list
named in the ``keys`` list.
If none of the lists in ``keys`` has a value to LPOP, then block
for ``timeout`` seconds, or until a value gets pushed on to one
of the lists.
If timeout is 0, then block indefinitely.
"""
if timeout is None:
timeout = 0
if isinstance(keys, basestring):
keys = [keys]
else:
keys = list(keys)
keys.append(timeout)
return self.execute_command('BRPOP', *keys)
def brpoplpush(self, src, dst, timeout=0):
"""
Pop a value off the tail of ``src``, push it on the head of ``dst``
and then return it.
This command blocks until a value is in ``src`` or until ``timeout``
seconds elapse, whichever is first. A ``timeout`` value of 0 blocks
forever.
"""
if timeout is None:
timeout = 0
return self.execute_command('BRPOPLPUSH', src, dst, timeout)
def lindex(self, name, index):
"""
Return the item from list ``name`` at position ``index``
Negative indexes are supported and will return an item at the
end of the list
"""
return self.execute_command('LINDEX', name, index)
def linsert(self, name, where, refvalue, value):
"""
Insert ``value`` in list ``name`` either immediately before or after
[``where``] ``refvalue``
Returns the new length of the list on success or -1 if ``refvalue``
is not in the list.
"""
return self.execute_command('LINSERT', name, where, refvalue, value)
def llen(self, name):
"Return the length of the list ``name``"
return self.execute_command('LLEN', name)
def lpop(self, name):
"Remove and return the first item of the list ``name``"
return self.execute_command('LPOP', name)
def lpush(self, name, *values):
"Push ``values`` onto the head of the list ``name``"
return self.execute_command('LPUSH', name, *values)
def lpushx(self, name, value):
"Push ``value`` onto the head of the list ``name`` if ``name`` exists"
return self.execute_command('LPUSHX', name, value)
def lrange(self, name, start, end):
"""
Return a slice of the list ``name`` between
position ``start`` and ``end``
``start`` and ``end`` can be negative numbers just like
Python slicing notation
"""
return self.execute_command('LRANGE', name, start, end)
def lrem(self, name, count, value):
"""
Remove the first ``count`` occurrences of elements equal to ``value``
from the list stored at ``name``.
The count argument influences the operation in the following ways:
count > 0: Remove elements equal to value moving from head to tail.
count < 0: Remove elements equal to value moving from tail to head.
count = 0: Remove all elements equal to value.
"""
return self.execute_command('LREM', name, count, value)
def lset(self, name, index, value):
"Set ``position`` of list ``name`` to ``value``"
return self.execute_command('LSET', name, index, value)
def ltrim(self, name, start, end):
"""
Trim the list ``name``, removing all values not within the slice
between ``start`` and ``end``
``start`` and ``end`` can be negative numbers just like
Python slicing notation
"""
return self.execute_command('LTRIM', name, start, end)
def rpop(self, name):
"Remove and return the last item of the list ``name``"
return self.execute_command('RPOP', name)
def rpoplpush(self, src, dst):
"""
RPOP a value off of the ``src`` list and atomically LPUSH it
on to the ``dst`` list. Returns the value.
"""
return self.execute_command('RPOPLPUSH', src, dst)
def rpush(self, name, *values):
"Push ``values`` onto the tail of the list ``name``"
return self.execute_command('RPUSH', name, *values)
def rpushx(self, name, value):
"Push ``value`` onto the tail of the list ``name`` if ``name`` exists"
return self.execute_command('RPUSHX', name, value)
def sort(self, name, start=None, num=None, by=None, get=None,
desc=False, alpha=False, store=None):
"""
Sort and return the list, set or sorted set at ``name``.
``start`` and ``num`` allow for paging through the sorted data
``by`` allows using an external key to weight and sort the items.
Use an "*" to indicate where in the key the item value is located
``get`` allows for returning items from external keys rather than the
sorted data itself. Use an "*" to indicate where int he key
the item value is located
``desc`` allows for reversing the sort
``alpha`` allows for sorting lexicographically rather than numerically
``store`` allows for storing the result of the sort into
the key ``store``
"""
if (start is not None and num is None) or \
(num is not None and start is None):
raise RedisError("``start`` and ``num`` must both be specified")
pieces = [name]
if by is not None:
pieces.append('BY')
pieces.append(by)
if start is not None and num is not None:
pieces.append('LIMIT')
pieces.append(start)
pieces.append(num)
if get is not None:
# If get is a string assume we want to get a single value.
# Otherwise assume it's an interable and we want to get multiple
# values. We can't just iterate blindly because strings are
# iterable.
if isinstance(get, basestring):
pieces.append('GET')
pieces.append(get)
else:
for g in get:
pieces.append('GET')
pieces.append(g)
if desc:
pieces.append('DESC')
if alpha:
pieces.append('ALPHA')
if store is not None:
pieces.append('STORE')
pieces.append(store)
return self.execute_command('SORT', *pieces)
#### SET COMMANDS ####
def sadd(self, name, *values):
"Add ``value(s)`` to set ``name``"
return self.execute_command('SADD', name, *values)
def scard(self, name):
"Return the number of elements in set ``name``"
return self.execute_command('SCARD', name)
def sdiff(self, keys, *args):
"Return the difference of sets specified by ``keys``"
keys = list_or_args(keys, args)
return self.execute_command('SDIFF', *keys)
def sdiffstore(self, dest, keys, *args):
"""
Store the difference of sets specified by ``keys`` into a new
set named ``dest``. Returns the number of keys in the new set.
"""
keys = list_or_args(keys, args)
return self.execute_command('SDIFFSTORE', dest, *keys)
def sinter(self, keys, *args):
"Return the intersection of sets specified by ``keys``"
keys = list_or_args(keys, args)
return self.execute_command('SINTER', *keys)
def sinterstore(self, dest, keys, *args):
"""
Store the intersection of sets specified by ``keys`` into a new
set named ``dest``. Returns the number of keys in the new set.
"""
keys = list_or_args(keys, args)
return self.execute_command('SINTERSTORE', dest, *keys)
def sismember(self, name, value):
"Return a boolean indicating if ``value`` is a member of set ``name``"
return self.execute_command('SISMEMBER', name, value)
def smembers(self, name):
"Return all members of the set ``name``"
return self.execute_command('SMEMBERS', name)
def smove(self, src, dst, value):
"Move ``value`` from set ``src`` to set ``dst`` atomically"
return self.execute_command('SMOVE', src, dst, value)
def spop(self, name):
"Remove and return a random member of set ``name``"
return self.execute_command('SPOP', name)
def srandmember(self, name):
"Return a random member of set ``name``"
return self.execute_command('SRANDMEMBER', name)
def srem(self, name, *values):
"Remove ``values`` from set ``name``"
return self.execute_command('SREM', name, *values)
def sunion(self, keys, *args):
"Return the union of sets specifiued by ``keys``"
keys = list_or_args(keys, args)
return self.execute_command('SUNION', *keys)
def sunionstore(self, dest, keys, *args):
"""
Store the union of sets specified by ``keys`` into a new
set named ``dest``. Returns the number of keys in the new set.
"""
keys = list_or_args(keys, args)
return self.execute_command('SUNIONSTORE', dest, *keys)
#### SORTED SET COMMANDS ####
def zadd(self, name, *args, **kwargs):
"""
Set any number of score, element-name pairs to the key ``name``. Pairs
can be specified in two ways:
As *args, in the form of: score1, name1, score2, name2, ...
or as **kwargs, in the form of: name1=score1, name2=score2, ...
The following example would add four values to the 'my-key' key:
redis.zadd('my-key', 1.1, 'name1', 2.2, 'name2', name3=3.3, name4=4.4)
"""
pieces = []
if args:
if len(args) % 2 != 0:
raise RedisError("ZADD requires an equal number of "
"values and scores")
pieces.extend(args)
for pair in kwargs.iteritems():
pieces.append(pair[1])
pieces.append(pair[0])
return self.execute_command('ZADD', name, *pieces)
def zcard(self, name):
"Return the number of elements in the sorted set ``name``"
return self.execute_command('ZCARD', name)
def zcount(self, name, min, max):
return self.execute_command('ZCOUNT', name, min, max)
def zincrby(self, name, value, amount=1):
"Increment the score of ``value`` in sorted set ``name`` by ``amount``"
return self.execute_command('ZINCRBY', name, amount, value)
def zinterstore(self, dest, keys, aggregate=None):
"""
Intersect multiple sorted sets specified by ``keys`` into
a new sorted set, ``dest``. Scores in the destination will be
aggregated based on the ``aggregate``, or SUM if none is provided.
"""
return self._zaggregate('ZINTERSTORE', dest, keys, aggregate)
def zrange(self, name, start, end, desc=False, withscores=False,
score_cast_func=float):
"""
Return a range of values from sorted set ``name`` between
``start`` and ``end`` sorted in ascending order.
``start`` and ``end`` can be negative, indicating the end of the range.
``desc`` a boolean indicating whether to sort the results descendingly
``withscores`` indicates to return the scores along with the values.
The return type is a list of (value, score) pairs
``score_cast_func`` a callable used to cast the score return value
"""
if desc:
return self.zrevrange(name, start, end, withscores)
pieces = ['ZRANGE', name, start, end]
if withscores:
pieces.append('withscores')
options = {'withscores': withscores, 'score_cast_func': score_cast_func}
return self.execute_command(*pieces, **options)
def zrangebyscore(self, name, min, max,
start=None, num=None, withscores=False, score_cast_func=float):
"""
Return a range of values from the sorted set ``name`` with scores
between ``min`` and ``max``.
If ``start`` and ``num`` are specified, then return a slice
of the range.
``withscores`` indicates to return the scores along with the values.
The return type is a list of (value, score) pairs
`score_cast_func`` a callable used to cast the score return value
"""
if (start is not None and num is None) or \
(num is not None and start is None):
raise RedisError("``start`` and ``num`` must both be specified")
pieces = ['ZRANGEBYSCORE', name, min, max]
if start is not None and num is not None:
pieces.extend(['LIMIT', start, num])
if withscores:
pieces.append('withscores')
options = {'withscores': withscores, 'score_cast_func': score_cast_func}
return self.execute_command(*pieces, **options)
def zrank(self, name, value):
"""
Returns a 0-based value indicating the rank of ``value`` in sorted set
``name``
"""
return self.execute_command('ZRANK', name, value)
def zrem(self, name, *values):
"Remove member ``values`` from sorted set ``name``"
return self.execute_command('ZREM', name, *values)
def zremrangebyrank(self, name, min, max):
"""
Remove all elements in the sorted set ``name`` with ranks between
``min`` and ``max``. Values are 0-based, ordered from smallest score
to largest. Values can be negative indicating the highest scores.
Returns the number of elements removed
"""
return self.execute_command('ZREMRANGEBYRANK', name, min, max)
def zremrangebyscore(self, name, min, max):
"""
Remove all elements in the sorted set ``name`` with scores
between ``min`` and ``max``. Returns the number of elements removed.
"""
return self.execute_command('ZREMRANGEBYSCORE', name, min, max)
def zrevrange(self, name, start, num, withscores=False,
score_cast_func=float):
"""
Return a range of values from sorted set ``name`` between
``start`` and ``num`` sorted in descending order.
``start`` and ``num`` can be negative, indicating the end of the range.
``withscores`` indicates to return the scores along with the values
The return type is a list of (value, score) pairs
``score_cast_func`` a callable used to cast the score return value
"""
pieces = ['ZREVRANGE', name, start, num]
if withscores:
pieces.append('withscores')
options = {'withscores': withscores, 'score_cast_func': score_cast_func}
return self.execute_command(*pieces, **options)
def zrevrangebyscore(self, name, max, min,
start=None, num=None, withscores=False, score_cast_func=float):
"""
Return a range of values from the sorted set ``name`` with scores
between ``min`` and ``max`` in descending order.
If ``start`` and ``num`` are specified, then return a slice
of the range.
``withscores`` indicates to return the scores along with the values.
The return type is a list of (value, score) pairs
``score_cast_func`` a callable used to cast the score return value
"""
if (start is not None and num is None) or \
(num is not None and start is None):
raise RedisError("``start`` and ``num`` must both be specified")
pieces = ['ZREVRANGEBYSCORE', name, max, min]
if start is not None and num is not None:
pieces.extend(['LIMIT', start, num])
if withscores:
pieces.append('withscores')
options = {'withscores': withscores, 'score_cast_func': score_cast_func}
return self.execute_command(*pieces, **options)
def zrevrank(self, name, value):
"""
Returns a 0-based value indicating the descending rank of
``value`` in sorted set ``name``
"""
return self.execute_command('ZREVRANK', name, value)
def zscore(self, name, value):
"Return the score of element ``value`` in sorted set ``name``"
return self.execute_command('ZSCORE', name, value)
def zunionstore(self, dest, keys, aggregate=None):
"""
Union multiple sorted sets specified by ``keys`` into
a new sorted set, ``dest``. Scores in the destination will be
aggregated based on the ``aggregate``, or SUM if none is provided.
"""
return self._zaggregate('ZUNIONSTORE', dest, keys, aggregate)
def _zaggregate(self, command, dest, keys, aggregate=None):
pieces = [command, dest, len(keys)]
if isinstance(keys, dict):
keys, weights = keys.keys(), keys.values()
else:
weights = None
pieces.extend(keys)
if weights:
pieces.append('WEIGHTS')
pieces.extend(weights)
if aggregate:
pieces.append('AGGREGATE')
pieces.append(aggregate)
return self.execute_command(*pieces)
#### HASH COMMANDS ####
def hdel(self, name, *keys):
"Delete ``keys`` from hash ``name``"
return self.execute_command('HDEL', name, *keys)
def hexists(self, name, key):
"Returns a boolean indicating if ``key`` exists within hash ``name``"
return self.execute_command('HEXISTS', name, key)
def hget(self, name, key):
"Return the value of ``key`` within the hash ``name``"
return self.execute_command('HGET', name, key)
def hgetall(self, name):
"Return a Python dict of the hash's name/value pairs"
return self.execute_command('HGETALL', name)
def hincrby(self, name, key, amount=1):
"Increment the value of ``key`` in hash ``name`` by ``amount``"
return self.execute_command('HINCRBY', name, key, amount)
def hkeys(self, name):
"Return the list of keys within hash ``name``"
return self.execute_command('HKEYS', name)
def hlen(self, name):
"Return the number of elements in hash ``name``"
return self.execute_command('HLEN', name)
def hset(self, name, key, value):
"""
Set ``key`` to ``value`` within hash ``name``
Returns 1 if HSET created a new field, otherwise 0
"""
return self.execute_command('HSET', name, key, value)
def hsetnx(self, name, key, value):
"""
Set ``key`` to ``value`` within hash ``name`` if ``key`` does not
exist. Returns 1 if HSETNX created a field, otherwise 0.
"""
return self.execute_command("HSETNX", name, key, value)
def hmset(self, name, mapping):
"""
Sets each key in the ``mapping`` dict to its corresponding value
in the hash ``name``
"""
if not mapping:
raise DataError("'hmset' with 'mapping' of length 0")
items = []
for pair in mapping.iteritems():
items.extend(pair)
return self.execute_command('HMSET', name, *items)
def hmget(self, name, keys):
"Returns a list of values ordered identically to ``keys``"
return self.execute_command('HMGET', name, *keys)
def hvals(self, name):
"Return the list of values within hash ``name``"
return self.execute_command('HVALS', name)
def publish(self, channel, message):
"""
Publish ``message`` on ``channel``.
Returns the number of subscribers the message was delivered to.
"""
return self.execute_command('PUBLISH', channel, message)
class Redis(StrictRedis):
"""
Provides backwards compatibility with older versions of redis-py that
changed arguments to some commands to be more Pythonic, sane, or by
accident.
"""
# Overridden callbacks
RESPONSE_CALLBACKS = dict_merge(
StrictRedis.RESPONSE_CALLBACKS,
{
'TTL': lambda r: r != -1 and r or None,
}
)
def pipeline(self, transaction=True, shard_hint=None):
"""
Return a new pipeline object that can queue multiple commands for
later execution. ``transaction`` indicates whether all commands
should be executed atomically. Apart from making a group of operations
atomic, pipelines are useful for reducing the back-and-forth overhead
between the client and server.
"""
return Pipeline(
self.connection_pool,
self.response_callbacks,
transaction,
shard_hint)
def setex(self, name, value, time):
"""
Set the value of key ``name`` to ``value``
that expires in ``time`` seconds
"""
return self.execute_command('SETEX', name, time, value)
def lrem(self, name, value, num=0):
"""
Remove the first ``num`` occurrences of elements equal to ``value``
from the list stored at ``name``.
The ``num`` argument influences the operation in the following ways:
num > 0: Remove elements equal to value moving from head to tail.
num < 0: Remove elements equal to value moving from tail to head.
num = 0: Remove all elements equal to value.
"""
return self.execute_command('LREM', name, num, value)
def zadd(self, name, *args, **kwargs):
"""
NOTE: The order of arguments differs from that of the official ZADD
command. For backwards compatability, this method accepts arguments
in the form of name1, score1, name2, score2, while the official Redis
documents expects score1, name1, score2, name2.
If you're looking to use the standard syntax, consider using the
StrictRedis class. See the API Reference section of the docs for more
information.
Set any number of element-name, score pairs to the key ``name``. Pairs
can be specified in two ways:
As *args, in the form of: name1, score1, name2, score2, ...
or as **kwargs, in the form of: name1=score1, name2=score2, ...
The following example would add four values to the 'my-key' key:
redis.zadd('my-key', 'name1', 1.1, 'name2', 2.2, name3=3.3, name4=4.4)
"""
pieces = []
if args:
if len(args) % 2 != 0:
raise RedisError("ZADD requires an equal number of "
"values and scores")
pieces.extend(reversed(args))
for pair in kwargs.iteritems():
pieces.append(pair[1])
pieces.append(pair[0])
return self.execute_command('ZADD', name, *pieces)
class PubSub(object):
"""
PubSub provides publish, subscribe and listen support to Redis channels.
After subscribing to one or more channels, the listen() method will block
until a message arrives on one of the subscribed channels. That message
will be returned and it's safe to start listening again.
"""
def __init__(self, connection_pool, shard_hint=None):
self.connection_pool = connection_pool
self.shard_hint = shard_hint
self.connection = None
self.channels = set()
self.patterns = set()
self.subscription_count = 0
self.subscribe_commands = set(
('subscribe', 'psubscribe', 'unsubscribe', 'punsubscribe')
)
def __del__(self):
try:
# if this object went out of scope prior to shutting down
# subscriptions, close the connection manually before
# returning it to the connection pool
if self.connection and (self.channels or self.patterns):
self.connection.disconnect()
self.reset()
except:
pass
def reset(self):
if self.connection:
self.connection_pool.release(self.connection)
self.connection = None
def execute_command(self, *args, **kwargs):
"Execute a publish/subscribe command"
if self.connection is None:
self.connection = self.connection_pool.get_connection(
'pubsub',
self.shard_hint
)
connection = self.connection
try:
connection.send_command(*args)
return self.parse_response()
except ConnectionError:
connection.disconnect()
# Connect manually here. If the Redis server is down, this will
# fail and raise a ConnectionError as desired.
connection.connect()
# resubscribe to all channels and patterns before
# resending the current command
for channel in self.channels:
self.subscribe(channel)
for pattern in self.patterns:
self.psubscribe(pattern)
connection.send_command(*args)
return self.parse_response()
def parse_response(self):
"Parse the response from a publish/subscribe command"
response = self.connection.read_response()
if response[0] in self.subscribe_commands:
self.subscription_count = response[2]
# if we've just unsubscribed from the remaining channels,
# release the connection back to the pool
if not self.subscription_count:
self.reset()
return response
def psubscribe(self, patterns):
"Subscribe to all channels matching any pattern in ``patterns``"
if isinstance(patterns, basestring):
patterns = [patterns]
for pattern in patterns:
self.patterns.add(pattern)
return self.execute_command('PSUBSCRIBE', *patterns)
def punsubscribe(self, patterns=[]):
"""
Unsubscribe from any channel matching any pattern in ``patterns``.
If empty, unsubscribe from all channels.
"""
if isinstance(patterns, basestring):
patterns = [patterns]
for pattern in patterns:
try:
self.patterns.remove(pattern)
except KeyError:
pass
return self.execute_command('PUNSUBSCRIBE', *patterns)
def subscribe(self, channels):
"Subscribe to ``channels``, waiting for messages to be published"
if isinstance(channels, basestring):
channels = [channels]
for channel in channels:
self.channels.add(channel)
return self.execute_command('SUBSCRIBE', *channels)
def unsubscribe(self, channels=[]):
"""
Unsubscribe from ``channels``. If empty, unsubscribe
from all channels
"""
if isinstance(channels, basestring):
channels = [channels]
for channel in channels:
try:
self.channels.remove(channel)
except KeyError:
pass
return self.execute_command('UNSUBSCRIBE', *channels)
def listen(self):
"Listen for messages on channels this client has been subscribed to"
while self.subscription_count:
r = self.parse_response()
if r[0] == 'pmessage':
msg = {
'type': r[0],
'pattern': r[1],
'channel': r[2],
'data': r[3]
}
else:
msg = {
'type': r[0],
'pattern': None,
'channel': r[1],
'data': r[2]
}
yield msg
class BasePipeline(object):
"""
Pipelines provide a way to transmit multiple commands to the Redis server
in one transmission. This is convenient for batch processing, such as
saving all the values in a list to Redis.
All commands executed within a pipeline are wrapped with MULTI and EXEC
calls. This guarantees all commands executed in the pipeline will be
executed atomically.
Any command raising an exception does *not* halt the execution of
subsequent commands in the pipeline. Instead, the exception is caught
and its instance is placed into the response list returned by execute().
Code iterating over the response list should be able to deal with an
instance of an exception as a potential value. In general, these will be
ResponseError exceptions, such as those raised when issuing a command
on a key of a different datatype.
"""
UNWATCH_COMMANDS = set(('DISCARD', 'EXEC', 'UNWATCH'))
def __init__(self, connection_pool, response_callbacks, transaction,
shard_hint):
self.connection_pool = connection_pool
self.connection = None
self.response_callbacks = response_callbacks
self.transaction = transaction
self.shard_hint = shard_hint
self.watching = False
self.reset()
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
self.reset()
def __del__(self):
try:
self.reset()
except:
pass
def reset(self):
self.command_stack = []
# make sure to reset the connection state in the event that we were
# watching something
if self.watching and self.connection:
try:
# call this manually since our unwatch or
# immediate_execute_command methods can call reset()
self.connection.send_command('UNWATCH')
self.connection.read_response()
except ConnectionError:
# disconnect will also remove any previous WATCHes
self.connection.disconnect()
# clean up the other instance attributes
self.watching = False
self.explicit_transaction = False
# we can safely return the connection to the pool here since we're
# sure we're no longer WATCHing anything
if self.connection:
self.connection_pool.release(self.connection)
self.connection = None
def multi(self):
"""
Start a transactional block of the pipeline after WATCH commands
are issued. End the transactional block with `execute`.
"""
if self.explicit_transaction:
raise RedisError('Cannot issue nested calls to MULTI')
if self.command_stack:
raise RedisError('Commands without an initial WATCH have already '
'been issued')
self.explicit_transaction = True
def execute_command(self, *args, **kwargs):
if (self.watching or args[0] == 'WATCH') and \
not self.explicit_transaction:
return self.immediate_execute_command(*args, **kwargs)
return self.pipeline_execute_command(*args, **kwargs)
def immediate_execute_command(self, *args, **options):
"""
Execute a command immediately, but don't auto-retry on a
ConnectionError if we're already WATCHing a variable. Used when
issuing WATCH or subsequent commands retrieving their values but before
MULTI is called.
"""
command_name = args[0]
conn = self.connection
# if this is the first call, we need a connection
if not conn:
conn = self.connection_pool.get_connection(command_name,
self.shard_hint)
self.connection = conn
try:
conn.send_command(*args)
return self.parse_response(conn, command_name, **options)
except ConnectionError:
conn.disconnect()
# if we're not already watching, we can safely retry the command
# assuming it was a connection timeout
if not self.watching:
conn.send_command(*args)
return self.parse_response(conn, command_name, **options)
self.reset()
raise
def pipeline_execute_command(self, *args, **options):
"""
Stage a command to be executed when execute() is next called
Returns the current Pipeline object back so commands can be
chained together, such as:
pipe = pipe.set('foo', 'bar').incr('baz').decr('bang')
At some other point, you can then run: pipe.execute(),
which will execute all commands queued in the pipe.
"""
self.command_stack.append((args, options))
return self
def _execute_transaction(self, connection, commands):
all_cmds = ''.join(starmap(connection.pack_command,
[args for args, options in commands]))
connection.send_packed_command(all_cmds)
# we don't care about the multi/exec any longer
commands = commands[1:-1]
# parse off the response for MULTI and all commands prior to EXEC.
# the only data we care about is the response the EXEC
# which is the last command
for i in range(len(commands)+1):
self.parse_response(connection, '_')
# parse the EXEC.
response = self.parse_response(connection, '_')
if response is None:
raise WatchError("Watched variable changed.")
if len(response) != len(commands):
raise ResponseError("Wrong number of response items from "
"pipeline execution")
# We have to run response callbacks manually
data = []
for r, cmd in izip(response, commands):
if not isinstance(r, Exception):
args, options = cmd
command_name = args[0]
if command_name in self.response_callbacks:
r = self.response_callbacks[command_name](r, **options)
data.append(r)
return data
def _execute_pipeline(self, connection, commands):
# build up all commands into a single request to increase network perf
all_cmds = ''.join(starmap(connection.pack_command,
[args for args, options in commands]))
connection.send_packed_command(all_cmds)
return [self.parse_response(connection, args[0], **options)
for args, options in commands]
def parse_response(self, connection, command_name, **options):
result = StrictRedis.parse_response(
self, connection, command_name, **options)
if command_name in self.UNWATCH_COMMANDS:
self.watching = False
elif command_name == 'WATCH':
self.watching = True
return result
def execute(self):
"Execute all the commands in the current pipeline"
stack = self.command_stack
if self.transaction or self.explicit_transaction:
stack = [(('MULTI', ), {})] + stack + [(('EXEC', ), {})]
execute = self._execute_transaction
else:
execute = self._execute_pipeline
conn = self.connection
if not conn:
conn = self.connection_pool.get_connection('MULTI', self.shard_hint)
# assign to self.connection so reset() releases the connection
# back to the pool after we're done
self.connection = conn
try:
return execute(conn, stack)
except ConnectionError:
conn.disconnect()
# if we were watching a variable, the watch is no longer valid since
# this connection has died. raise a WatchError, which indicates
# the user should retry his transaction. If this is more than a
# temporary failure, the WATCH that the user next issue will fail,
# propegating the real ConnectionError
if self.watching:
raise WatchError("A ConnectionError occured on while watching "
"one or more keys")
# otherwise, it's safe to retry since the transaction isn't
# predicated on any state
return execute(conn, stack)
finally:
self.reset()
def watch(self, *names):
"""
Watches the values at keys ``names``
"""
if self.explicit_transaction:
raise RedisError('Cannot issue a WATCH after a MULTI')
return self.execute_command('WATCH', *names)
def unwatch(self):
"""
Unwatches all previously specified keys
"""
return self.watching and self.execute_command('UNWATCH') or True
class StrictPipeline(BasePipeline, StrictRedis):
"Pipeline for the StrictRedis class"
pass
class Pipeline(BasePipeline, Redis):
"Pipeline for the Redis class"
pass
class LockError(RedisError):
"Errors thrown from the Lock"
pass
class Lock(object):
"""
A shared, distributed Lock. Using Redis for locking allows the Lock
to be shared across processes and/or machines.
It's left to the user to resolve deadlock issues and make sure
multiple clients play nicely together.
"""
LOCK_FOREVER = float(2**31+1) # 1 past max unix time
def __init__(self, redis, name, timeout=None, sleep=0.1):
"""
Create a new Lock instnace named ``name`` using the Redis client
supplied by ``redis``.
``timeout`` indicates a maximum life for the lock.
By default, it will remain locked until release() is called.
``sleep`` indicates the amount of time to sleep per loop iteration
when the lock is in blocking mode and another client is currently
holding the lock.
Note: If using ``timeout``, you should make sure all the hosts
that are running clients have their time synchronized with a network time
service like ntp.
"""
self.redis = redis
self.name = name
self.acquired_until = None
self.timeout = timeout
self.sleep = sleep
if self.timeout and self.sleep > self.timeout:
raise LockError("'sleep' must be less than 'timeout'")
def __enter__(self):
return self.acquire()
def __exit__(self, exc_type, exc_value, traceback):
self.release()
def acquire(self, blocking=True):
"""
Use Redis to hold a shared, distributed lock named ``name``.
Returns True once the lock is acquired.
If ``blocking`` is False, always return immediately. If the lock
was acquired, return True, otherwise return False.
"""
sleep = self.sleep
timeout = self.timeout
while 1:
unixtime = int(time.time())
if timeout:
timeout_at = unixtime + timeout
else:
timeout_at = Lock.LOCK_FOREVER
timeout_at = float(timeout_at)
if self.redis.setnx(self.name, timeout_at):
self.acquired_until = timeout_at
return True
# We want blocking, but didn't acquire the lock
# check to see if the current lock is expired
existing = float(self.redis.get(self.name) or 1)
if existing < unixtime:
# the previous lock is expired, attempt to overwrite it
existing = float(self.redis.getset(self.name, timeout_at) or 1)
if existing < unixtime:
# we successfully acquired the lock
self.acquired_until = timeout_at
return True
if not blocking:
return False
time.sleep(sleep)
def release(self):
"Releases the already acquired lock"
if self.acquired_until is None:
raise ValueError("Cannot release an unlocked lock")
existing = float(self.redis.get(self.name) or 1)
# if the lock time is in the future, delete the lock
if existing >= self.acquired_until:
self.redis.delete(self.name)
self.acquired_until = None
#print "TOTOTOTOTOTO"
##############################################################################
#
# Copyright (c) 2010 Vifib SARL and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import os
from slapos.recipe.librecipe import GenericBaseRecipe
class Recipe(GenericBaseRecipe):
def install(self):
path_list = []
if not self.optionIsTrue('use_passwd', False):
master_passwd = "# masterauth <master-password>"
else:
master_passwd = "masterauth %s" % self.options['passwd']
config_file = self.options['config_file'].strip()
configuration = dict(pid_file=self.options['pid_file'],
port=self.options['port'],
ipv6=self.options['ipv6'],
server_dir=self.options['server_dir'],
log_file=self.options['log_file'],
master_passwd=master_passwd
)
config = self.createFile(config_file,
self.substituteTemplate(self.getTemplateFilename('redis.conf.in'),
configuration))
path_list.append(config)
redis = self.createPythonScript(
self.options['wrapper'],
'slapos.recipe.librecipe.execute.execute',
[self.options['server_bin'], config_file]
)
path_list.append(redis)
promise_script = self.options.get('promise_wrapper', '').strip()
if promise_script:
promise = self.createPythonScript(
promise_script,
'%s.promise.main' % __name__,
dict(host=self.options['ipv6'], port=self.options['port'])
)
path_list.append(promise)
return path_list
#! /usr/bin/env python
# -*- coding: utf-8 -*-
import slapos.recipe.redis.MyRedis2410 as redis
import sys
def main(args):
host = args['host']
port = int(args['port'])
try:
pool = redis.ConnectionPool(host=host, port=port, db=0)
r = redis.Redis(connection_pool=pool)
r.publish("Promise-Service","SlapOS Promise")
pool.disconnect()
sys.exit(0)
except Exception, e:
print str(e)
sys.exit(1)
\ No newline at end of file
# Redis configuration file example
# Note on units: when memory size is needed, it is possible to specify
# it in the usual form of 1k 5GB 4M and so forth:
#
# 1k => 1000 bytes
# 1kb => 1024 bytes
# 1m => 1000000 bytes
# 1mb => 1024*1024 bytes
# 1g => 1000000000 bytes
# 1gb => 1024*1024*1024 bytes
#
# units are case insensitive so 1GB 1Gb 1gB are all the same.
# By default Redis does not run as a daemon. Use 'yes' if you need it.
# Note that Redis will write a pid file in /var/run/redis.pid when daemonized.
daemonize no
# When running daemonized, Redis writes a pid file in /var/run/redis.pid by
# default. You can specify a custom pid file location here.
pidfile %(pid_file)s
# Accept connections on the specified port, default is 6379.
# If port 0 is specified Redis will not listen on a TCP socket.
port6 %(port)s
port 0
# If you want you can bind a single interface, if the bind option is not
# specified all the interfaces will listen for incoming connections.
# Bind can also be an IPv6 address
# bind 127.0.0.1
# bind ::1
bind6 %(ipv6)s
# Specify the path for the unix socket that will be used to listen for
# incoming connections. There is no default, so Redis will not listen
# on a unix socket when not specified.
#
# unixsocket /tmp/redis.sock
# unixsocketperm 755
# Close the connection after a client is idle for N seconds (0 to disable)
timeout 0
# Set server verbosity to 'debug'
# it can be one of:
# debug (a lot of information, useful for development/testing)
# verbose (many rarely useful info, but not a mess like the debug level)
# notice (moderately verbose, what you want in production probably)
# warning (only very important / critical messages are logged)
loglevel notice
# Specify the log file name. Also 'stdout' can be used to force
# Redis to log on the standard output. Note that if you use standard
# output for logging but daemonize, logs will be sent to /dev/null
logfile %(log_file)s
# To enable logging to the system logger, just set 'syslog-enabled' to yes,
# and optionally update the other syslog parameters to suit your needs.
# syslog-enabled no
# Specify the syslog identity.
# syslog-ident redis
# Specify the syslog facility. Must be USER or between LOCAL0-LOCAL7.
# syslog-facility local0
# Set the number of databases. The default database is DB 0, you can select
# a different one on a per-connection basis using SELECT <dbid> where
# dbid is a number between 0 and 'databases'-1
databases 16
################################ SNAPSHOTTING #################################
#
# Save the DB on disk:
#
# save <seconds> <changes>
#
# Will save the DB if both the given number of seconds and the given
# number of write operations against the DB occurred.
#
# In the example below the behaviour will be to save:
# after 900 sec (15 min) if at least 1 key changed
# after 300 sec (5 min) if at least 10 keys changed
# after 60 sec if at least 10000 keys changed
#
# Note: you can disable saving at all commenting all the "save" lines.
#
# It is also possible to remove all the previously configured save
# points by adding a save directive with a single empty string argument
# like in the following example:
#
# save ""
save 900 1
save 300 10
save 60 10000
# By default Redis will stop accepting writes if RDB snapshots are enabled
# (at least one save point) and the latest background save failed.
# This will make the user aware (in an hard way) that data is not persisting
# on disk properly, otherwise chances are that no one will notice and some
# distater will happen.
#
# If the background saving process will start working again Redis will
# automatically allow writes again.
#
# However if you have setup your proper monitoring of the Redis server
# and persistence, you may want to disable this feature so that Redis will
# continue to work as usually even if there are problems with disk,
# permissions, and so forth.
stop-writes-on-bgsave-error yes
# Compress string objects using LZF when dump .rdb databases?
# For default that's set to 'yes' as it's almost always a win.
# If you want to save some CPU in the saving child set it to 'no' but
# the dataset will likely be bigger if you have compressible values or keys.
rdbcompression yes
# Since verison 5 of RDB a CRC64 checksum is placed at the end of the file.
# This makes the format more resistant to corruption but there is a performance
# hit to pay (around 10%%) when saving and loading RDB files, so you can disable it
# for maximum performances.
#
# RDB files created with checksum disabled have a checksum of zero that will
# tell the loading code to skip the check.
rdbchecksum yes
# The filename where to dump the DB
dbfilename dump.rdb
# The working directory.
#
# The DB will be written inside this directory, with the filename specified
# above using the 'dbfilename' configuration directive.
#
# Also the Append Only File will be created inside this directory.
#
# Note that you must specify a directory here, not a file name.
dir %(server_dir)s
################################# REPLICATION #################################
# Master-Slave replication. Use slaveof to make a Redis instance a copy of
# another Redis server. Note that the configuration is local to the slave
# so for example it is possible to configure the slave to save the DB with a
# different interval, or to listen to another port, and so on.
#
# slaveof <masterip> <masterport>
# If the master is password protected (using the "requirepass" configuration
# directive below) it is possible to tell the slave to authenticate before
# starting the replication synchronization process, otherwise the master will
# refuse the slave request.
#
%(master_passwd)s
# When a slave lost the connection with the master, or when the replication
# is still in progress, the slave can act in two different ways:
#
# 1) if slave-serve-stale-data is set to 'yes' (the default) the slave will
# still reply to client requests, possibly with out of date data, or the
# data set may just be empty if this is the first synchronization.
#
# 2) if slave-serve-stale data is set to 'no' the slave will reply with
# an error "SYNC with master in progress" to all the kind of commands
# but to INFO and SLAVEOF.
#
slave-serve-stale-data yes
# You can configure a slave instance to accept writes or not. Writing against
# a slave instance may be useful to store some ephemeral data (because data
# written on a slave will be easily deleted after resync with the master) but
# may also cause problems if clients are writing to it because of a
# misconfiguration.
#
# Since Redis 2.6 by default slaves are read-only.
#
# Note: read only slaves are not designed to be exposed to untrusted clients
# on the internet. It's just a protection layer against misuse of the instance.
# Still a read only slave exports by default all the administrative commands
# such as CONFIG, DEBUG, and so forth. To a limited extend you can improve
# security of read only slaves using 'rename-command' to shadow all the
# administrative / dangerous commands.
slave-read-only yes
# Slaves send PINGs to server in a predefined interval. It's possible to change
# this interval with the repl_ping_slave_period option. The default value is 10
# seconds.
#
# repl-ping-slave-period 10
# The following option sets a timeout for both Bulk transfer I/O timeout and
# master data or ping response timeout. The default value is 60 seconds.
#
# It is important to make sure that this value is greater than the value
# specified for repl-ping-slave-period otherwise a timeout will be detected
# every time there is low traffic between the master and the slave.
#
# repl-timeout 60
################################## SECURITY ###################################
# Require clients to issue AUTH <PASSWORD> before processing any other
# commands. This might be useful in environments in which you do not trust
# others with access to the host running redis-server.
#
# This should stay commented out for backward compatibility and because most
# people do not need auth (e.g. they run their own servers).
#
# Warning: since Redis is pretty fast an outside user can try up to
# 150k passwords per second against a good box. This means that you should
# use a very strong password otherwise it will be very easy to break.
#
# requirepass foobared
# Command renaming.
#
# It is possible to change the name of dangerous commands in a shared
# environment. For instance the CONFIG command may be renamed into something
# of hard to guess so that it will be still available for internal-use
# tools but not available for general clients.
#
# Example:
#
# rename-command CONFIG b840fc02d524045429941cc15f59e41cb7be6c52
#
# It is also possible to completely kill a command renaming it into
# an empty string:
#
# rename-command CONFIG ""
################################### LIMITS ####################################
# Set the max number of connected clients at the same time. By default
# this limit is set to 10000 clients, however if the Redis server is not
# able ot configure the process file limit to allow for the specified limit
# the max number of allowed clients is set to the current file limit
# minus 32 (as Redis reserves a few file descriptors for internal uses).
#
# Once the limit is reached Redis will close all the new connections sending
# an error 'max number of clients reached'.
#
# maxclients 10000
# Don't use more memory than the specified amount of bytes.
# When the memory limit is reached Redis will try to remove keys
# accordingly to the eviction policy selected (see maxmemmory-policy).
#
# If Redis can't remove keys according to the policy, or if the policy is
# set to 'noeviction', Redis will start to reply with errors to commands
# that would use more memory, like SET, LPUSH, and so on, and will continue
# to reply to read-only commands like GET.
#
# This option is usually useful when using Redis as an LRU cache, or to set
# an hard memory limit for an instance (using the 'noeviction' policy).
#
# WARNING: If you have slaves attached to an instance with maxmemory on,
# the size of the output buffers needed to feed the slaves are subtracted
# from the used memory count, so that network problems / resyncs will
# not trigger a loop where keys are evicted, and in turn the output
# buffer of slaves is full with DELs of keys evicted triggering the deletion
# of more keys, and so forth until the database is completely emptied.
#
# In short... if you have slaves attached it is suggested that you set a lower
# limit for maxmemory so that there is some free RAM on the system for slave
# output buffers (but this is not needed if the policy is 'noeviction').
#
# maxmemory <bytes>
# MAXMEMORY POLICY: how Redis will select what to remove when maxmemory
# is reached? You can select among five behavior:
#
# volatile-lru -> remove the key with an expire set using an LRU algorithm
# allkeys-lru -> remove any key accordingly to the LRU algorithm
# volatile-random -> remove a random key with an expire set
# allkeys-random -> remove a random key, any key
# volatile-ttl -> remove the key with the nearest expire time (minor TTL)
# noeviction -> don't expire at all, just return an error on write operations
#
# Note: with all the kind of policies, Redis will return an error on write
# operations, when there are not suitable keys for eviction.
#
# At the date of writing this commands are: set setnx setex append
# incr decr rpush lpush rpushx lpushx linsert lset rpoplpush sadd
# sinter sinterstore sunion sunionstore sdiff sdiffstore zadd zincrby
# zunionstore zinterstore hset hsetnx hmset hincrby incrby decrby
# getset mset msetnx exec sort
#
# The default is:
#
# maxmemory-policy volatile-lru
# LRU and minimal TTL algorithms are not precise algorithms but approximated
# algorithms (in order to save memory), so you can select as well the sample
# size to check. For instance for default Redis will check three keys and
# pick the one that was used less recently, you can change the sample size
# using the following configuration directive.
#
# maxmemory-samples 3
############################## APPEND ONLY MODE ###############################
# By default Redis asynchronously dumps the dataset on disk. This mode is
# good enough in many applications, but an issue with the Redis process or
# a power outage may result into a few minutes of writes lost (depending on
# the configured save points).
#
# The Append Only File is an alternative persistence mode that provides
# much better durability. For instance using the default data fsync policy
# (see later in the config file) Redis can lose just one second of writes in a
# dramatic event like a server power outage, or a single write if something
# wrong with the Redis process itself happens, but the operating system is
# still running correctly.
#
# AOF and RDB persistence can be enabled at the same time without problems.
# If the AOF is enabled on startup Redis will load the AOF, that is the file
# with the better durability guarantees.
#
# Please check http://redis.io/topics/persistence for more information.
appendonly no
# The name of the append only file (default: "appendonly.aof")
# appendfilename appendonly.aof
# The fsync() call tells the Operating System to actually write data on disk
# instead to wait for more data in the output buffer. Some OS will really flush
# data on disk, some other OS will just try to do it ASAP.
#
# Redis supports three different modes:
#
# no: don't fsync, just let the OS flush the data when it wants. Faster.
# always: fsync after every write to the append only log . Slow, Safest.
# everysec: fsync only one time every second. Compromise.
#
# The default is "everysec" that's usually the right compromise between
# speed and data safety. It's up to you to understand if you can relax this to
# "no" that will let the operating system flush the output buffer when
# it wants, for better performances (but if you can live with the idea of
# some data loss consider the default persistence mode that's snapshotting),
# or on the contrary, use "always" that's very slow but a bit safer than
# everysec.
#
# More details please check the following article:
# http://antirez.com/post/redis-persistence-demystified.html
#
# If unsure, use "everysec".
# appendfsync always
appendfsync everysec
# appendfsync no
# When the AOF fsync policy is set to always or everysec, and a background
# saving process (a background save or AOF log background rewriting) is
# performing a lot of I/O against the disk, in some Linux configurations
# Redis may block too long on the fsync() call. Note that there is no fix for
# this currently, as even performing fsync in a different thread will block
# our synchronous write(2) call.
#
# In order to mitigate this problem it's possible to use the following option
# that will prevent fsync() from being called in the main process while a
# BGSAVE or BGREWRITEAOF is in progress.
#
# This means that while another child is saving the durability of Redis is
# the same as "appendfsync none", that in practical terms means that it is
# possible to lost up to 30 seconds of log in the worst scenario (with the
# default Linux settings).
#
# If you have latency problems turn this to "yes". Otherwise leave it as
# "no" that is the safest pick from the point of view of durability.
no-appendfsync-on-rewrite no
# Automatic rewrite of the append only file.
# Redis is able to automatically rewrite the log file implicitly calling
# BGREWRITEAOF when the AOF log size will growth by the specified percentage.
#
# This is how it works: Redis remembers the size of the AOF file after the
# latest rewrite (or if no rewrite happened since the restart, the size of
# the AOF at startup is used).
#
# This base size is compared to the current size. If the current size is
# bigger than the specified percentage, the rewrite is triggered. Also
# you need to specify a minimal size for the AOF file to be rewritten, this
# is useful to avoid rewriting the AOF file even if the percentage increase
# is reached but it is still pretty small.
#
# Specify a percentage of zero in order to disable the automatic AOF
# rewrite feature.
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
################################ LUA SCRIPTING ###############################
# Max execution time of a Lua script in milliseconds.
#
# If the maximum execution time is reached Redis will log that a script is
# still in execution after the maximum allowed time and will start to
# reply to queries with an error.
#
# When a long running script exceed the maximum execution time only the
# SCRIPT KILL and SHUTDOWN NOSAVE commands are available. The first can be
# used to stop a script that did not yet called write commands. The second
# is the only way to shut down the server in the case a write commands was
# already issue by the script but the user don't want to wait for the natural
# termination of the script.
#
# Set it to 0 or a negative value for unlimited execution without warnings.
lua-time-limit 5000
################################ REDIS CLUSTER ###############################
#
# Normal Redis instances can't be part of a Redis Cluster, only nodes that are
# started as cluster nodes can. In order to start a Redis instance as a
# cluster node enable the cluster support uncommenting the following:
#
# cluster-enabled yes
# Every cluster node has a cluster configuration file. This file is not
# intended to be edited by hand. It is created and updated by Redis nodes.
# Every Redis Cluster node requires a different cluster configuration file.
# Make sure that instances running in the same system does not have
# overlapping cluster configuration file names.
#
# cluster-config-file nodes-6379.conf
# In order to setup your cluster make sure to read the documentation
# available at http://redis.io web site.
################################## SLOW LOG ###################################
# The Redis Slow Log is a system to log queries that exceeded a specified
# execution time. The execution time does not include the I/O operations
# like talking with the client, sending the reply and so forth,
# but just the time needed to actually execute the command (this is the only
# stage of command execution where the thread is blocked and can not serve
# other requests in the meantime).
#
# You can configure the slow log with two parameters: one tells Redis
# what is the execution time, in microseconds, to exceed in order for the
# command to get logged, and the other parameter is the length of the
# slow log. When a new command is logged the oldest one is removed from the
# queue of logged commands.
# The following time is expressed in microseconds, so 1000000 is equivalent
# to one second. Note that a negative number disables the slow log, while
# a value of zero forces the logging of every command.
slowlog-log-slower-than 10000
# There is no limit to this length. Just be aware that it will consume memory.
# You can reclaim memory used by the slow log with SLOWLOG RESET.
slowlog-max-len 128
############################### ADVANCED CONFIG ###############################
# Hashes are encoded using a memory efficient data structure when they have a
# small number of entries, and the biggest entry does not exceed a given
# threshold. These thresholds can be configured using the following directives.
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
# Similarly to hashes, small lists are also encoded in a special way in order
# to save a lot of space. The special representation is only used when
# you are under the following limits:
list-max-ziplist-entries 512
list-max-ziplist-value 64
# Sets have a special encoding in just one case: when a set is composed
# of just strings that happens to be integers in radix 10 in the range
# of 64 bit signed integers.
# The following configuration setting sets the limit in the size of the
# set in order to use this special memory saving encoding.
set-max-intset-entries 512
# Similarly to hashes and lists, sorted sets are also specially encoded in
# order to save a lot of space. This encoding is only used when the length and
# elements of a sorted set are below the following limits:
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
# Active rehashing uses 1 millisecond every 100 milliseconds of CPU time in
# order to help rehashing the main Redis hash table (the one mapping top-level
# keys to values). The hash table implementation Redis uses (see dict.c)
# performs a lazy rehashing: the more operation you run into an hash table
# that is rehashing, the more rehashing "steps" are performed, so if the
# server is idle the rehashing is never complete and some more memory is used
# by the hash table.
#
# The default is to use this millisecond 10 times every second in order to
# active rehashing the main dictionaries, freeing memory when possible.
#
# If unsure:
# use "activerehashing no" if you have hard latency requirements and it is
# not a good thing in your environment that Redis can reply form time to time
# to queries with 2 milliseconds delay.
#
# use "activerehashing yes" if you don't have such hard requirements but
# want to free memory asap when possible.
activerehashing yes
# The client output buffer limits can be used to force disconnection of clients
# that are not reading data from the server fast enough for some reason (a
# common reason is that a Pub/Sub client can't consume messages as fast as the
# publisher can produce them).
#
# The limit can be set differently for the three different classes of clients:
#
# normal -> normal clients
# slave -> slave clients and MONITOR clients
# pubsub -> clients subcribed to at least one pubsub channel or pattern
#
# The syntax of every client-output-buffer-limit directive is the following:
#
# client-output-buffer-limit <class> <hard limit> <soft limit> <soft seconds>
#
# A client is immediately disconnected once the hard limit is reached, or if
# the soft limit is reached and remains reached for the specified number of
# seconds (continuously).
# So for instance if the hard limit is 32 megabytes and the soft limit is
# 16 megabytes / 10 seconds, the client will get disconnected immediately
# if the size of the output buffers reach 32 megabytes, but will also get
# disconnected if the client reaches 16 megabytes and continuously overcomes
# the limit for 10 seconds.
#
# By default normal clients are not limited because they don't receive data
# without asking (in a push way), but just after a request, so only
# asynchronous clients may create a scenario where data is requested faster
# than it can read.
#
# Instead there is a default limit for pubsub and slave clients, since
# subscribers and slaves receive data in a push fashion.
#
# Both the hard or the soft limit can be disabled just setting it to zero.
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit slave 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
################################## INCLUDES ###################################
# Include one or more other config files here. This is useful if you
# have a standard template that goes to all Redis server but also need
# to customize a few per-server settings. Include files can include
# other files, so use this wisely.
#
# include /path/to/local.conf
# include /path/to/other.conf
\ No newline at end of file
......@@ -131,8 +131,8 @@ class Recipe(object):
options['instance-guid'] = self.instance.getInstanceGuid()
# XXX: deprecated, to be removed
options['instance_guid'] = self.instance.getInstanceGuid()
except slapmodule.ResourceNotReady:
# Backward compatibility. Old SlapOS masters don't know this.
except (slapmodule.ResourceNotReady, AttributeError):
# Backward compatibility. Old SlapOS master and core don't know this.
self.logger.warning("Impossible to fetch instance GUID.")
except (slapmodule.NotFoundError, slapmodule.ServerError, slapmodule.ResourceNotReady) as exc:
self._raise_request_exception = exc
......
......@@ -38,7 +38,7 @@ class Recipe(GenericBaseRecipe):
self.software_directory = options['software-directory'].strip()
self.instance_directory = options['instance-directory'].strip()
self.partition_amount = options['partition-amount'].strip()
self.cloud9_url = options['cloud9-url'].strip()
self.cloud9_url = options.get('cloud9-url', '').strip()
self.log_file = os.path.join(options['log_dir'].strip(), 'slaprunner.log')
# Set slaprunner access URL
options['access-url'] = 'http://[%s]:%s' % (self.ipv6, self.runner_port)
......@@ -109,7 +109,7 @@ class Test(GenericBaseRecipe):
self.software_directory = options['software-directory'].strip()
self.instance_directory = options['instance-directory'].strip()
self.partition_amount = options['partition-amount'].strip()
self.cloud9_url = options['cloud9-url'].strip()
self.cloud9_url = options.get('cloud9-url', '').strip()
# Set slaprunner access URL
options['access-url'] = 'http://[%s]:%s' % (self.ipv6, self.runner_port)
......
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2010 Vifib SARL and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import os
import sys
import subprocess
import shutil
import json
from slapos.recipe.librecipe import GenericBaseRecipe
class Recipe(GenericBaseRecipe):
def __init__(self, buildout, name, options):
pythonPath = ""
for eggs in options['eggs-dirs'].splitlines():
if eggs:
for item in os.listdir(eggs):
path = os.path.join(eggs, item)
pythonPath = path + ":" + pythonPath
options['python_path'] = pythonPath
options['wsgi-dir'] = os.path.join(options['site-dir'].strip(), 'apache')
options['git-dir'] = os.path.join(options['site-dir'].strip(), 'git')
options['svn-dir'] = os.path.join(options['site-dir'].strip(), 'svn')
return GenericBaseRecipe.__init__(self, buildout, name, options)
def install(self):
install_path = []
env = os.environ
env['LD_LIBRARY_PATH'] = self.options['python-lib']
project_dir = self.options['site-dir'].strip()
trac_admin = self.options['trac-admin'].strip()
admin = self.options['admin-user'].strip()
passwd = self.options['admin-password'].strip()
config = os.path.join(project_dir, 'conf/trac.ini')
filestat = self.options['file-status'].strip()
self.logger.info("Checking if trac project is not installed...")
if os.path.exists(filestat):
os.unlink(filestat)
if not os.path.exists(project_dir):
self.logger.info("Starting trac project installation at %s" % project_dir)
trac_args = [trac_admin, project_dir, 'initenv']
db_string = "mysql://%s:%s@%s:%s/%s" % (
self.options['mysql-username'].strip(),
self.options['mysql-password'].strip(),
self.options['mysql-host'].strip(),
self.options['mysql-port'].strip(),
self.options['mysql-database'].strip()
)
process_install = subprocess.Popen(trac_args, stdout=subprocess.PIPE,
stdin=subprocess.PIPE, stderr=subprocess.STDOUT, env=env)
process_install.stdin.write('%s\n%s\n' % (self.options['project'].strip(),
db_string))
result = process_install.communicate()[0]
process_install.stdin.close()
if process_install.returncode is None or process_install.returncode != 0:
if os.path.exists(project_dir):
shutil.rmtree(project_dir)
self.logger.error("Failed to initialize Trac.\nThe error was: %s" % result)
return []
os.mkdir(self.options['git-dir'])
os.mkdir(self.options['svn-dir'])
os.mkdir(self.options['wsgi-dir'])
os.unlink(config)
shutil.copy(self.options['trac-ini'].strip(), config)
shutil.copy(self.options['trac-wsgi'].strip(),
os.path.join(self.options['wsgi-dir'], 'trac.wsgi'))
else:
self.logger.info("The directory %s already exist, skip project installation"
% project_dir)
trac_args = [trac_admin, project_dir, 'repository', 'list']
process_upgrade = subprocess.Popen(trac_args, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
result = process_upgrade.communicate()[0]
if process_upgrade.returncode is None or process_upgrade.returncode != 0:
self.logger.error("Failed to run Trac.\nThe error was: %s" % result)
return []
#Add All grant to admin user
self.logger.info("Granting admin rights to the admin user.")
trac_grant = [trac_admin, project_dir, "permission add %s TRAC_ADMIN" % admin]
process = subprocess.Popen(trac_grant, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT, env=env)
result = process.communicate()[0]
if process.returncode is None or process.returncode != 0:
raise Exception("Failed to execute Trac-admin.\nThe error was: %s" % result)
self.logger.info("Copying additional plugins into plugins directory")
plugins_dir = os.path.join(project_dir, "plugins")
for item in os.listdir(self.options['plugins-egg-dir'].strip()):
source = os.path.join(self.options['plugins-egg-dir'].strip(), item)
destination = os.path.join(plugins_dir, item)
if not os.path.exists(destination):
shutil.copytree(source, destination)
svn_list = json.loads(self.options.get('svn-project-list', '{}'))
for svn_repo in svn_list:
svn_repo_path = os.path.join(self.options['svn-dir'], svn_repo)
if not os.path.exists(svn_repo_path):
self.logger.info("Initializing %s SVN repository..." % svn_repo)
svn_args = [self.options['svn-repo-script'], project_dir,
svn_repo, svn_list[svn_repo]]
process = subprocess.Popen(svn_args, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
result = process.communicate()[0]
if process.returncode is None or process.returncode != 0:
shutil.rmtree(svn_repo_path)
raise Exception("Failed to create repository.\nThe error was: %s" % result)
shutil.copy(self.options['trac-svn-hook'].strip(),
os.path.join(svn_repo_path, 'hooks/post-commit'))
shutil.copy(self.options['post-revprop-change'].strip(),
os.path.join(svn_repo_path, 'hooks/post-revprop-change'))
self.logger.info("Finished initializing %s reposiroty" % svn_repo)
repolist = json.loads(self.options.get('git-project-list', '{}'))
for repo, desc in repolist.iteritems():
absolute_path = os.path.join(self.options['git-dir'], '%s.git' % repo)
if not os.path.exists(absolute_path):
self.logger.info("Initializing %s GIT repository..." % repo)
subprocess.check_call([self.options['git-binary'], 'init',
'--bare', absolute_path])
subprocess.check_call([trac_admin, project_dir, 'repository',
'add', repo, absolute_path, 'git'], env=env)
subprocess.check_call([trac_admin, project_dir, 'repository',
'resync', repo], env=env)
# XXX: Hardcoded path
shutil.copy(self.options['trac-git-hook'].strip(),
os.path.join(absolute_path, 'hooks/post-commit'))
description_filename = os.path.join(absolute_path, 'description')
with open(description_filename, 'w') as description_file:
description_file.write(desc)
user_list = json.loads(self.options.get('user-list', '{}'))
fd = open(os.path.join(project_dir, 'svnpasswd'), 'w')
fd.write("[users]\n%s = %s" % (admin, passwd))
os.system("%s -cb %s %s %s" % (self.options['htpasswd'],
self.options['passwd-file'],
admin, passwd)
)
for user in user_list:
self.logger.info("Creating or updating user %s ..." % user)
user_args = [self.options['htpasswd'], '-b', self.options['passwd-file'],
user, user_list[user]]
process = subprocess.Popen(user_args, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
result = process.communicate()[0]
if process.returncode is None or process.returncode != 0:
raise Exception("Failed to create user %s.\nThe error was: %s" %
(user, result))
fd.write("\n%s = %s" % (user, user_list[user]))
fd.close()
open(filestat, "w").write("done.")
return install_path
[buildout]
parts =
certificate-authority
ca-stunnel
logrotate
logrotate-entry-apache
logrotate-entry-stunnel
cron
cron-entry-logrotate
promise
frontend-ajaxupload-promise
frontend-website2-promise
frontend-website-promise
# content-promise
publish-connection-informations
eggs-directory = ${buildout:eggs-directory}
develop-eggs-directory = ${buildout:develop-eggs-directory}
offline = true
#----------------
#--
#-- Creation of all needed directories.
[rootdirectory]
recipe = slapos.cookbook:mkdirectory
etc = $${buildout:directory}/etc
var = $${buildout:directory}/var
srv = $${buildout:directory}/srv
bin = $${buildout:directory}/bin
tmp = $${buildout:directory}/tmp
[basedirectory]
recipe = slapos.cookbook:mkdirectory
log = $${rootdirectory:var}/log
services = $${rootdirectory:etc}/service
run = $${rootdirectory:var}/run
backup = $${rootdirectory:srv}/backup
promises = $${rootdirectory:etc}/promise
[directory]
recipe = slapos.cookbook:mkdirectory
cron-entries = $${rootdirectory:etc}/cron.d
crontabs = $${rootdirectory:etc}/crontabs
cronstamps = $${rootdirectory:etc}/cronstamps
ca-dir = $${rootdirectory:srv}/ssl
httpd-log = $${basedirectory:log}/apache
php-ini-dir = $${rootdirectory:etc}/php
tmp-php = $${rootdirectory:tmp}/php
logrotate-entries = $${rootdirectory:etc}/logrotate.d
logrotate-backup = $${basedirectory:backup}/logrotate
report = $${rootdirectory:etc}/report
stunnel-conf = $${rootdirectory:etc}/stunnel
xml-report = $${rootdirectory:var}/xml_report
www = $${rootdirectory:srv}/www/
[cadirectory]
recipe = slapos.cookbook:mkdirectory
requests = $${directory:ca-dir}/requests
private = $${directory:ca-dir}/private
certs = $${directory:ca-dir}/certs
newcerts = $${directory:ca-dir}/newcerts
crl = $${directory:ca-dir}/crl
#----------------
#--
#-- Deploy cron.
[cron]
recipe = slapos.cookbook:cron
dcrond-binary = ${dcron:location}/sbin/crond
cron-entries = $${directory:cron-entries}
crontabs = $${directory:crontabs}
cronstamps = $${directory:cronstamps}
catcher = $${cron-simplelogger:wrapper}
binary = $${basedirectory:services}/crond
[cron-simplelogger]
recipe = slapos.cookbook:simplelogger
wrapper = $${rootdirectory:bin}/cron_simplelogger
log = $${basedirectory:log}/crond.log
#----------------
#--
#-- Deploy logrotate.
[cron-entry-logrotate]
<= cron
recipe = slapos.cookbook:cron.d
name = logrotate
frequency = 0 0 * * *
command = $${logrotate:wrapper}
[logrotate]
recipe = slapos.cookbook:logrotate
# Binaries
logrotate-binary = ${logrotate:location}/usr/sbin/logrotate
gzip-binary = ${gzip:location}/bin/gzip
gunzip-binary = ${gzip:location}/bin/gunzip
# Directories
wrapper = $${rootdirectory:bin}/logrotate
conf = $${rootdirectory:etc}/logrotate.conf
logrotate-entries = $${directory:logrotate-entries}
backup = $${directory:logrotate-backup}
state-file = $${rootdirectory:srv}/logrotate.status
#----------------
#--
#-- Deploy stunnel.
[stunnel]
recipe = slapos.cookbook:stunnel
client = true
stunnel-binary = ${stunnel:location}/bin/stunnel
remote-host = $${mariadb-urlparse:host}
remote-port = $${mariadb-urlparse:port}
local-host = $${slap-network-information:local-ipv4}
local-port = 3306
log-file = $${basedirectory:log}/stunnel.log
config-file = $${directory:stunnel-conf}/stunnel.conf
key-file = $${directory:stunnel-conf}/stunnel.key
cert-file = $${directory:stunnel-conf}/stunnel.crt
pid-file = $${basedirectory:run}/stunnel.pid
wrapper = $${rootdirectory:bin}/raw_stunnel
post-rotate-script = $${rootdirectory:bin}/stunnel_post_rotate
[logrotate-entry-stunnel]
<= logrotate
recipe = slapos.cookbook:logrotate.d
name = stunnel
log = $${stunnel:log-file}
frequency = daily
rotate-num = 30
notifempty = true
create = true
post = $${stunnel:post-rotate-script}
#----------------
#--
#-- Certificate stuff.
[certificate-authority]
recipe = slapos.cookbook:certificate_authority
openssl-binary = ${openssl:location}/bin/openssl
ca-dir = $${directory:ca-dir}
requests-directory = $${cadirectory:requests}
wrapper = $${basedirectory:services}/ca
ca-private = $${cadirectory:private}
ca-certs = $${cadirectory:certs}
ca-newcerts = $${cadirectory:newcerts}
ca-crl = $${cadirectory:crl}
[ca-stunnel]
<= certificate-authority
recipe = slapos.cookbook:certificate_authority.request
executable = $${stunnel:wrapper}
wrapper = $${basedirectory:services}/stunnel
key-file = $${stunnel:key-file}
cert-file = $${stunnel:cert-file}
#----------------
#--
#-- Request MariaDB instance and parse its URL.
[request-mariadb]
<= slap-connection
recipe = slapos.cookbook:request
name = MariaDB
software-url = $${slap-connection:software-release-url}
software-type = mariadb
return = url
sla = computer_guid
sla-computer_guid = $${slap-connection:computer-id}
[mariadb-urlparse]
recipe = slapos.cookbook:urlparse
url = $${request-mariadb:connection-url}
#----------------
#--
#-- Deploy Apache + PHP application.
[httpd-conf]
recipe = slapos.recipe.template
url = ${template-httpd-conf:location}/${template-httpd-conf:filename}
output = $${rootdirectory:etc}/apache.conf
mode = 0600
document_root = $${rootdirectory:srv}/www/
pid_file = $${basedirectory:run}/apache.pid
lock_file = $${basedirectory:run}/apache.lock
ip = $${slap-network-information:global-ipv6}
port = 8080
port2 = 8070
port3 = 8090
error_log = $${directory:httpd-log}/error.log
access_log = $${directory:httpd-log}/access.log
php_ini_dir = $${directory:php-ini-dir}
# Deploy Apache + PHP application
[apache-php]
recipe = slapos.cookbook:apachephp
source = ${application:location}
template =
configuration =
htdocs = $${directory:www}
pid-file = $${basedirectory:run}/apache.pid
lock-file = $${basedirectory:run}/apache.lock
ip = $${httpd-conf:ip}
port = $${httpd-conf:port}
url = http://[$${:ip}]:$${:port}/
error-log = $${directory:httpd-log}/error.log
access-log = $${directory:httpd-log}/access.log
php-ini-dir = $${directory:php-ini-dir}
tmp-dir = $${directory:tmp-php}
wrapper = $${basedirectory:services}/apache
httpd-binary = ${apache:location}/bin/httpd
default-conf = false
httpd-conf = $${httpd-conf:output}
mysql-username = $${mariadb-urlparse:username}
mysql-password = $${mariadb-urlparse:password}
mysql-database = $${mariadb-urlparse:path}
mysql-host = $${stunnel:local-host}
mysql-port = $${stunnel:local-port}
[logrotate-entry-apache]
<= logrotate
recipe = slapos.cookbook:logrotate.d
name = apache
log = $${apache-php:error-log} $${apache-php:access-log}
frequency = daily
rotate-num = 30
sharedscripts = true
notifempty = true
create = true
#----------------
#--
#-- Request frontends.
[request-frontend]
<= slap-connection
recipe = slapos.cookbook:requestoptional
name = Frontend-Website
# XXX We have hardcoded SR URL here.
software-url = $${slap-parameter:frontend-software-url}
slave = true
config = url custom_domain
config-url = http://[$${apache-php:ip}]:$${apache-php:port}/
return = site_url
config-custom_domain = $${slap-parameter:domain}
[request-frontend-ajaxupload]
<= slap-connection
recipe = slapos.cookbook:requestoptional
name = Frontend-FileManager
# XXX We have hardcoded SR URL here.
software-url = $${slap-parameter:frontend-software-url}
slave = true
config = url custom_domain
config-url = http://[$${httpd-conf:ip}]:$${httpd-conf:port2}/
return = site_url
config-custom_domain = $${slap-parameter:domain2}
[request-frontend2]
<= slap-connection
recipe = slapos.cookbook:requestoptional
name = Frontend-Website2
# XXX We have hardcoded SR URL here.
software-url = $${slap-parameter:frontend-software-url}
slave = true
config = url custom_domain
config-url = http://[$${httpd-conf:ip}]:$${httpd-conf:port3}/
return = site_url
config-custom_domain = $${slap-parameter:domain3}
#----------------
#--
#-- Deploy slapmonitor.
#[slapmonitor]
#recipe = slapos.cookbook:slapmonitor
#pid-file = $${basedirectory:run}/apache.pid
#database-path = $${basedirectory:log}/slapmonitor.db
#slapmonitor-path = ${buildout:bin-directory}/slapmonitor
#path = $${basedirectory:services}/slapmonitor
#
#[slapmonitor-xml]
#recipe = slapos.cookbook:slapmonitor-xml
#database-path = $${basedirectory:log}/slapmonitor.db
#slapmonitor-xml-path = ${buildout:bin-directory}/slapmonitor-xml
#path = $${directory:report}/slapmonitor-xml
#----------------
#--
#-- Publish instance parameters.
[publish-connection-informations]
recipe = slapos.cookbook:publish
website-backend-url = $${apache-php:url}
website-url = $${request-frontend:connection-site_url}
website2-backend-url = http://[$${apache-php:ip}]:$${httpd-conf:port3}
website2-url = $${request-frontend2:connection-site_url}
filemanager-backend-url = http://[$${apache-php:ip}]:$${httpd-conf:port2}
fileManager-url = $${request-frontend-ajaxupload:connection-site_url}
mysql-username = $${mariadb-urlparse:username}
mysql-password = $${mariadb-urlparse:password}
mysql-database = $${mariadb-urlparse:path}
mysql-host = $${stunnel:local-host}
mysql-port = $${stunnel:local-port}
#----------------
#--
#-- Deploy promises scripts.
[promise]
recipe = slapos.cookbook:check_port_listening
path = $${basedirectory:promises}/apache
hostname = $${apache-php:ip}
port = $${apache-php:port}
[frontend-website-promise]
recipe = slapos.cookbook:check_url_available
path = $${basedirectory:promises}/frontend-website
url = $${request-frontend:connection-site_url}
dash_path = ${dash:location}/bin/dash
curl_path = ${curl:location}/bin/curl
[frontend-website2-promise]
recipe = slapos.cookbook:check_url_available
path = $${basedirectory:promises}/frontend-website2
url = $${request-frontend2:connection-site_url}
dash_path = ${dash:location}/bin/dash
curl_path = ${curl:location}/bin/curl
[frontend-ajaxupload-promise]
recipe = slapos.cookbook:check_url_available
path = $${basedirectory:promises}/frontend-ajaxupload
url = $${request-frontend-ajaxupload:connection-site_url}
dash_path = ${dash:location}/bin/dash
curl_path = ${curl:location}/bin/curl
[content-promise]
recipe = slapos.cookbook:check_page_content
path = $${basedirectory:promises}/content
url = $${request-frontend-ajaxupload:connection-site_url}
match = AjaXplorer
dash_path = ${dash:location}/bin/dash
curl_path = ${curl:location}/bin/curl
[slap-parameter]
# Default value if no domain is specified
domain =
domain2 =
domain3 =
frontend-software-url = http://git.erp5.org/gitweb/slapos.git/blob_plain/HEAD:/software/apache-frontend/software.cfg
# Default value if no ssh parameter is specified
logbox-ip =
logbox-port =
logbox-user =
logbox-passwd =
[buildout]
parts =
switch_softwaretype
eggs-directory = ${buildout:eggs-directory}
develop-eggs-directory = ${buildout:develop-eggs-directory}
offline = true
[switch_softwaretype]
recipe = slapos.cookbook:softwaretype
default = ${instance-apache:output}
mariadb = ${instance-mariadb:output}
\ No newline at end of file
[buildout]
parts =
slapos-cookbook
subversion
apache-php
instance
instance-apache
instance-mariadb
template-httpd-conf
application
website1-template
website2-template
extends =
../../stack/slapos.cfg
../../component/apache/buildout.cfg
../../component/apache-php/buildout.cfg
../../component/logrotate/buildout.cfg
../../component/subversion/buildout.cfg
../../component/gzip/buildout.cfg
../../component/dcron/buildout.cfg
../../component/dash/buildout.cfg
../../component/stunnel/buildout.cfg
../../component/lxml-python/buildout.cfg
[instance]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/instance.cfg
output = ${buildout:directory}/template.cfg
mode = 0644
md5sum = 4c7936accb3658871b635158198b7905
[instance-apache]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/instance-apachephp.cfg
output = ${buildout:directory}/template-apachephp.cfg
md5sum = ef5c61127a21c016014021477d1791e3
mode = 0644
[instance-mariadb]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/../../stack/lamp/mariadb/instance-mariadb.cfg.in
output = ${buildout:directory}/template-mariadb.cfg
mode = 0644
[application]
recipe = hexagonit.recipe.download
url = http://garr.dl.sourceforge.net/project/ajaxplorer/ajaxplorer/dev-channel/4.3.4/ajaxplorer-core-4.3.4.tar.gz
md5sum = 2f2ff8bda7bbe841ef0e870c724eb74f
strip-top-level-dir = true
[website]
recipe = z3c.recipe.mkdir
path1 = ${application:location}/data/files/website
path2 = ${application:location}/data/files/website2
paths =
${:path1}
${:path2}
[website1-template]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/templates/index.html.in
output = ${website:path1}/index.html
md5sum = c5695762361b801c284ee23a150cd1f1
mode = 0644
[website2-template]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/templates/index.html.in
output = ${website:path2}/index.html
md5sum = c5695762361b801c284ee23a150cd1f1
mode = 0644
[template-httpd-conf]
recipe = slapos.recipe.download
url = ${:_profile_base_location_}/templates/${:filename}
mode = 0644
filename = apache.conf.in
md5sum = 6788381fadd8ca96f892d33df3163da0
location = ${buildout:parts-directory}/${:_buildout_section_name_}
[networkcache]
# signature certificates of the following uploaders.
# Romain Courteaud
# Sebastien Robin
# Kazuhiko Shiozaki
# Cedric de Saint Martin
# Yingjie Xu
# Gabriel Monnerat
# Łukasz Nowak
# Test Agent (Automatic update from tests)
signature-certificate-list =
-----BEGIN CERTIFICATE-----
MIIB4DCCAUkCADANBgkqhkiG9w0BAQsFADA5MQswCQYDVQQGEwJGUjEZMBcGA1UE
CBMQRGVmYXVsdCBQcm92aW5jZTEPMA0GA1UEChMGTmV4ZWRpMB4XDTExMDkxNTA5
MDAwMloXDTEyMDkxNTA5MDAwMlowOTELMAkGA1UEBhMCRlIxGTAXBgNVBAgTEERl
ZmF1bHQgUHJvdmluY2UxDzANBgNVBAoTBk5leGVkaTCBnzANBgkqhkiG9w0BAQEF
AAOBjQAwgYkCgYEApYZv6OstoqNzxG1KI6iE5U4Ts2Xx9lgLeUGAMyfJLyMmRLhw
boKOyJ9Xke4dncoBAyNPokUR6iWOcnPHtMvNOsBFZ2f7VA28em3+E1JRYdeNUEtX
Z0s3HjcouaNAnPfjFTXHYj4um1wOw2cURSPuU5dpzKBbV+/QCb5DLheynisCAwEA
ATANBgkqhkiG9w0BAQsFAAOBgQBCZLbTVdrw3RZlVVMFezSHrhBYKAukTwZrNmJX
mHqi2tN8tNo6FX+wmxUUAf3e8R2Ymbdbn2bfbPpcKQ2fG7PuKGvhwMG3BlF9paEC
q7jdfWO18Zp/BG7tagz0jmmC4y/8akzHsVlruo2+2du2freE8dK746uoMlXlP93g
QUUGLQ==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB8jCCAVugAwIBAgIJAPu2zchZ2BxoMA0GCSqGSIb3DQEBBQUAMBIxEDAOBgNV
BAMMB3RzeGRldjMwHhcNMTExMDE0MTIxNjIzWhcNMTIxMDEzMTIxNjIzWjASMRAw
DgYDVQQDDAd0c3hkZXYzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrPbh+
YGmo6mWmhVb1vTqX0BbeU0jCTB8TK3i6ep3tzSw2rkUGSx3niXn9LNTFNcIn3MZN
XHqbb4AS2Zxyk/2tr3939qqOrS4YRCtXBwTCuFY6r+a7pZsjiTNddPsEhuj4lEnR
L8Ax5mmzoi9nE+hiPSwqjRwWRU1+182rzXmN4QIDAQABo1AwTjAdBgNVHQ4EFgQU
/4XXREzqBbBNJvX5gU8tLWxZaeQwHwYDVR0jBBgwFoAU/4XXREzqBbBNJvX5gU8t
LWxZaeQwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQA07q/rKoE7fAda
FED57/SR00OvY9wLlFEF2QJ5OLu+O33YUXDDbGpfUSF9R8l0g9dix1JbWK9nQ6Yd
R/KCo6D0sw0ZgeQv1aUXbl/xJ9k4jlTxmWbPeiiPZEqU1W9wN5lkGuLxV4CEGTKU
hJA/yXa1wbwIPGvX3tVKdOEWPRXZLg==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB7jCCAVegAwIBAgIJAJWA0jQ4o9DGMA0GCSqGSIb3DQEBBQUAMA8xDTALBgNV
BAMMBHg2MXMwIBcNMTExMTI0MTAyNDQzWhgPMjExMTEwMzExMDI0NDNaMA8xDTAL
BgNVBAMMBHg2MXMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANdJNiFsRlkH
vq2kHP2zdxEyzPAWZH3CQ3Myb3F8hERXTIFSUqntPXDKXDb7Y/laqjMXdj+vptKk
3Q36J+8VnJbSwjGwmEG6tym9qMSGIPPNw1JXY1R29eF3o4aj21o7DHAkhuNc5Tso
67fUSKgvyVnyH4G6ShQUAtghPaAwS0KvAgMBAAGjUDBOMB0GA1UdDgQWBBSjxFUE
RfnTvABRLAa34Ytkhz5vPzAfBgNVHSMEGDAWgBSjxFUERfnTvABRLAa34Ytkhz5v
PzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAFLDS7zNhlrQYSQO5KIj
z2RJe3fj4rLPklo3TmP5KLvendG+LErE2cbKPqnhQ2oVoj6u9tWVwo/g03PMrrnL
KrDm39slYD/1KoE5kB4l/p6KVOdeJ4I6xcgu9rnkqqHzDwI4v7e8/D3WZbpiFUsY
vaZhjNYKWQf79l6zXfOvphzJ
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB9jCCAV+gAwIBAgIJAO4V/jiMoICoMA0GCSqGSIb3DQEBBQUAMBMxETAPBgNV
BAMMCENPTVAtMjMyMCAXDTEyMDIxNjExMTAyM1oYDzIxMTIwMTIzMTExMDIzWjAT
MREwDwYDVQQDDAhDT01QLTIzMjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
wi/3Z8W9pUiegUXIk/AiFDQ0UJ4JFAwjqr+HSRUirlUsHHT+8DzH/hfcTDX1I5BB
D1ADk+ydXjMm3OZrQcXjn29OUfM5C+g+oqeMnYQImN0DDQIOcUyr7AJc4xhvuXQ1
P2pJ5NOd3tbd0kexETa1LVhR6EgBC25LyRBRae76qosCAwEAAaNQME4wHQYDVR0O
BBYEFMDmW9aFy1sKTfCpcRkYnP6zUd1cMB8GA1UdIwQYMBaAFMDmW9aFy1sKTfCp
cRkYnP6zUd1cMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAskbFizHr
b6d3iIyN+wffxz/V9epbKIZVEGJd/6LrTdLiUfJPec7FaxVCWNyKBlCpINBM7cEV
Gn9t8mdVQflNqOlAMkOlUv1ZugCt9rXYQOV7rrEYJBWirn43BOMn9Flp2nibblby
If1a2ZoqHRxoNo2yTmm7TSYRORWVS+vvfjY=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB9jCCAV+gAwIBAgIJAIlBksrZVkK8MA0GCSqGSIb3DQEBBQUAMBMxETAPBgNV
BAMMCENPTVAtMzU3MCAXDTEyMDEyNjEwNTUyOFoYDzIxMTIwMTAyMTA1NTI4WjAT
MREwDwYDVQQDDAhDT01QLTM1NzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
ts+iGUwi44vtIfwXR8DCnLtHV4ydl0YTK2joJflj0/Ws7mz5BYkxIU4fea/6+VF3
i11nwBgYgxQyjNztgc9u9O71k1W5tU95yO7U7bFdYd5uxYA9/22fjObaTQoC4Nc9
mTu6r/VHyJ1yRsunBZXvnk/XaKp7gGE9vNEyJvPn2bkCAwEAAaNQME4wHQYDVR0O
BBYEFKuGIYu8+6aEkTVg62BRYaD11PILMB8GA1UdIwQYMBaAFKuGIYu8+6aEkTVg
62BRYaD11PILMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAMoTRpBxK
YLEZJbofF7gSrRIcrlUJYXfTfw1QUBOKkGFFDsiJpEg4y5pUk1s5Jq9K3SDzNq/W
it1oYjOhuGg3al8OOeKFrU6nvNTF1BAvJCl0tr3POai5yXyN5jlK/zPfypmQYxE+
TaqQSGBJPVXYt6lrq/PRD9ciZgKLOwEqK8w=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB9jCCAV+gAwIBAgIJAPHoWu90gbsgMA0GCSqGSIb3DQEBBQUAMBQxEjAQBgNV
BAMMCXZpZmlibm9kZTAeFw0xMjAzMTkyMzIwNTVaFw0xMzAzMTkyMzIwNTVaMBQx
EjAQBgNVBAMMCXZpZmlibm9kZTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
ozBijpO8PS5RTeKTzA90vi9ezvv4vVjNaguqT4UwP9+O1+i6yq1Y2W5zZxw/Klbn
oudyNzie3/wqs9VfPmcyU9ajFzBv/Tobm3obmOqBN0GSYs5fyGw+O9G3//6ZEhf0
NinwdKmrRX+d0P5bHewadZWIvlmOupcnVJmkks852BECAwEAAaNQME4wHQYDVR0O
BBYEFF9EtgfZZs8L2ZxBJxSiY6eTsTEwMB8GA1UdIwQYMBaAFF9EtgfZZs8L2ZxB
JxSiY6eTsTEwMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAc43YTfc6
baSemaMAc/jz8LNLhRE5dLfLOcRSoHda8y0lOrfe4lHT6yP5l8uyWAzLW+g6s3DA
Yme/bhX0g51BmI6gjKJo5DoPtiXk/Y9lxwD3p7PWi+RhN+AZQ5rpo8UfwnnN059n
yDuimQfvJjBFMVrdn9iP6SfMjxKaGk6gVmI=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB9jCCAV+gAwIBAgIJAMNZBmoIOXPBMA0GCSqGSIb3DQEBBQUAMBMxETAPBgNV
BAMMCENPTVAtMTMyMCAXDTEyMDUwMjEyMDQyNloYDzIxMTIwNDA4MTIwNDI2WjAT
MREwDwYDVQQDDAhDT01QLTEzMjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
6peZQt1sAmMAmSG9BVxxcXm8x15kE9iAplmANYNQ7z2YO57c10jDtlYlwVfi/rct
xNUOKQtc8UQtV/fJWP0QT0GITdRz5X/TkWiojiFgkopza9/b1hXs5rltYByUGLhg
7JZ9dZGBihzPfn6U8ESAKiJzQP8Hyz/o81FPfuHCftsCAwEAAaNQME4wHQYDVR0O
BBYEFNuxsc77Z6/JSKPoyloHNm9zF9yqMB8GA1UdIwQYMBaAFNuxsc77Z6/JSKPo
yloHNm9zF9yqMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAl4hBaJy1
cgiNV2+Z5oNTrHgmzWvSY4duECOTBxeuIOnhql3vLlaQmo0p8Z4c13kTZq2s3nhd
Loe5mIHsjRVKvzB6SvIaFUYq/EzmHnqNdpIGkT/Mj7r/iUs61btTcGUCLsUiUeci
Vd0Ozh79JSRpkrdI8R/NRQ2XPHAo+29TT70=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB9jCCAV+gAwIBAgIJAKRvzcy7OH0UMA0GCSqGSIb3DQEBBQUAMBMxETAPBgNV
BAMMCENPTVAtNzcyMCAXDTEyMDgxMDE1NDI1MVoYDzIxMTIwNzE3MTU0MjUxWjAT
MREwDwYDVQQDDAhDT01QLTc3MjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
o7aipd6MbnuGDeR1UJUjuMLQUariAyQ2l2ZDS6TfOwjHiPw/mhzkielgk73kqN7A
sUREx41eTcYCXzTq3WP3xCLE4LxLg1eIhd4nwNHj8H18xR9aP0AGjo4UFl5BOMa1
mwoyBt3VtfGtUmb8whpeJgHhqrPPxLoON+i6fIbXDaUCAwEAAaNQME4wHQYDVR0O
BBYEFEfjy3OopT2lOksKmKBNHTJE2hFlMB8GA1UdIwQYMBaAFEfjy3OopT2lOksK
mKBNHTJE2hFlMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAaNRx6YN2
M/p3R8/xS6zvH1EqJ3FFD7XeAQ52WuQnKSREzuw0dsw12ClxjcHiQEFioyTiTtjs
5pW18Ry5Ie7iFK4cQMerZwWPxBodEbAteYlRsI6kePV7Gf735Y1RpuN8qZ2sYL6e
x2IMeSwJ82BpdEI5niXxB+iT0HxhmR+XaMI=
-----END CERTIFICATE-----
[versions]
#Error: Couldn't install: lxml 3.1.2
lxml = 3.1.1
# Numpy 1.7.0 doesn't install well
numpy = 1.6.2
# websockify 0.4.1 doesn't install well
websockify = 0.3.0
slapos.cookbook=0.78.1
setuptools = 0.6c12dev-r88846
Jinja2 = 2.7
MarkupSafe = 0.18
Werkzeug = 0.8.3
buildout-versions = 1.7
inotifyx = 0.2.0-1
meld3 = 0.6.10
netaddr = 0.7.10
plone.recipe.command = 1.1
pytz = 2013b
slapos.core = 0.35.1
slapos.recipe.build = 0.11.6
slapos.recipe.cmmi = 0.1.1
slapos.recipe.download = 1.0.dev-r4053
slapos.recipe.template = 2.4.2
xml-marshaller = 0.9.7
z3c.recipe.mkdir = 0.5
# Required by:
# slapos.core==0.35.1
Flask = 0.9
# Required by:
# slapos.cookbook==0.78.1
lock-file = 2.0
# Required by:
# slapos.core==0.35.1
netifaces = 0.8-1
# Required by:
# slapos.core==0.35.1
pyflakes = 0.7.2
# Required by:
# slapos.core==0.35.1
supervisor = 3.0b1
# Required by:
# slapos.core==0.35.1
unittest2 = 0.5.1
# Required by:
# slapos.core==0.35.1
zope.interface = 4.0.5
\ No newline at end of file
# Apache static configuration
# Automatically generated
# Basic server configuration
PidFile "${:pid_file}"
Listen ${:ip}:8070
Listen ${:ip}:8080
Listen ${:ip}:8090
PHPINIDir ${:php_ini_dir}
ServerAdmin someone@email
TypesConfig conf/mime.types
AddType application/x-compress .Z
AddType application/x-gzip .gz .tgz
AddType application/x-httpd-php .php .phtml .php5 .php4
AddType application/x-httpd-php-source .phps
# Log configuration
ErrorLog "${:error_log}"
LogLevel warn
LogFormat "%h %{REMOTE_USER}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %{REMOTE_USER}i %l %u %t \"%r\" %>s %b" common
CustomLog "${:access_log}" common
NameVirtualHost ${:ip}:8090
NameVirtualHost ${:ip}:8080
NameVirtualHost ${:ip}:8070
<VirtualHost ${:ip}:8070>
#ServerName www.example.com
# Directory protection
<Directory />
Options FollowSymLinks
AllowOverride None
Require all denied
</Directory>
<Directory ${:document_root}>
Options FollowSymLinks
AllowOverride All
Require all granted
</Directory>
DocumentRoot ${:document_root}
DirectoryIndex index.html index.php
</VirtualHost>
<VirtualHost ${:ip}:8080>
#ServerName www.example.com
# Directory protection
<Directory />
Options FollowSymLinks
AllowOverride None
Require all denied
</Directory>
<Directory ${:document_root}data/files/website/>
Options FollowSymLinks
AllowOverride All
Require all granted
</Directory>
DocumentRoot ${:document_root}data/files/website/
DirectoryIndex index.html index.php
</VirtualHost>
<VirtualHost ${:ip}:8090>
#ServerName www.example.com
# Directory protection
<Directory />
Options FollowSymLinks
AllowOverride None
Require all denied
</Directory>
<Directory ${:document_root}data/files/website2/>
Options FollowSymLinks
AllowOverride All
Require all granted
</Directory>
DocumentRoot ${:document_root}data/files/website2/
DirectoryIndex index.html index.php
</VirtualHost>
# List of modules
LoadModule unixd_module modules/mod_unixd.so
LoadModule access_compat_module modules/mod_access_compat.so
LoadModule authz_core_module modules/mod_authz_core.so
LoadModule authz_host_module modules/mod_authz_host.so
LoadModule log_config_module modules/mod_log_config.so
LoadModule setenvif_module modules/mod_setenvif.so
LoadModule version_module modules/mod_version.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule mime_module modules/mod_mime.so
LoadModule dav_module modules/mod_dav.so
LoadModule dav_fs_module modules/mod_dav_fs.so
LoadModule negotiation_module modules/mod_negotiation.so
LoadModule rewrite_module modules/mod_rewrite.so
LoadModule headers_module modules/mod_headers.so
LoadModule dir_module modules/mod_dir.so
LoadModule php5_module modules/libphp5.so
LoadModule alias_module modules/mod_alias.so
\ No newline at end of file
<html>
<head>
<title>New Document - Created By AjaXplorer</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
</head>
<body bgcolor="#FFFFFF" text="#000000">
<h2>Hi, this website folder is still empty. Please go to your File Manager administration and replace this folder by your new website files.</h2>
</body>
</html>
[buildout]
parts =
boinc-client
publish-connection-informations
eggs-directory = ${buildout:eggs-directory}
develop-eggs-directory = ${buildout:develop-eggs-directory}
offline = true
[rootdirectory]
recipe = slapos.cookbook:mkdirectory
etc = $${buildout:directory}/etc/
var = $${buildout:directory}/var/
srv = $${buildout:directory}/srv/
bin = $${buildout:directory}/bin/
tmp = $${buildout:directory}/tmp/
[basedirectory]
recipe = slapos.cookbook:mkdirectory
log = $${rootdirectory:var}/log/
services = $${rootdirectory:etc}/run/
run = $${rootdirectory:var}/run/
backup = $${rootdirectory:srv}/backup/
promises = $${rootdirectory:etc}/promise/
boinc = $${rootdirectory:srv}/boinc/
[boinc-passwd]
recipe = slapos.cookbook:generate.password
storage-path = $${basedirectory:boinc}/gui_rpc_auth.cfg
bytes = 8
[boinc-client]
recipe = slapos.cookbook:boinc.client
install-dir = $${basedirectory:boinc}
home = $${buildout:directory}
client-wrapper = $${basedirectory:services}/boinc_client
cmd-wrapper = $${basedirectory:services}/boinc_cmd
ip = $${slap-network-information:global-ipv6}
passwd = $${boinc-passwd:passwd}
#specifie a cc_config.xml file to boinc client, use cconfig
cconfig =
boinc-bin = ${boinc:location}/bin/boinc_client
cmd-bin = ${boinc:location}/bin/boinccmd
server-url = $${slap-parameter:boinc-project-url}
key = $${slap-parameter:boinc-account-key}
# Publish all instance parameters
[publish-connection-informations]
recipe = slapos.cookbook:publish
boinc_project_url = $${slap-parameter:boinc-project-url}
boinc_account_key = $${slap-parameter:boinc-account-key}
remote_host = $${boinc-client:ip}
rpc_port = $${boinc-client:rpc-port}
rpc_passwd = $${boinc-passwd:passwd}
[slap-parameter]
#please provide project_url and your session key via SlapOS Master (instance parameters)
boinc-project-url =
boinc-account-key =
[buildout]
parts =
switch_softwaretype
eggs-directory = ${buildout:eggs-directory}
develop-eggs-directory = ${buildout:develop-eggs-directory}
offline = true
[switch_softwaretype]
recipe = slapos.cookbook:softwaretype
default = ${template-boinc:output}
\ No newline at end of file
[buildout]
parts=
slapos-cookbook
boinc
template
template-boinc
extends =
../../component/boinc-client/buildout.cfg
../../stack/slapos.cfg
[template]
# Default template for boinc-client instance.
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/instance.cfg
md5sum = 79f4d781c1b385d2afa75ae4077c5381
output = ${buildout:directory}/template.cfg
mode = 0644
[template-boinc]
# Default template for boinc-client instance.
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/instance-boinc.cfg
md5sum = 4a50c02252792d11b99d88206bc49e12
output = ${buildout:directory}/template-boinc.cfg
mode = 0644
[networkcache]
# signature certificates of the following uploaders.
# Romain Courteaud
# Sebastien Robin
# Kazuhiko Shiozaki
# Cedric de Saint Martin
# Yingjie Xu
# Gabriel Monnerat
# Łukasz Nowak
# Test Agent (Automatic update from tests)
signature-certificate-list =
-----BEGIN CERTIFICATE-----
MIIB4DCCAUkCADANBgkqhkiG9w0BAQsFADA5MQswCQYDVQQGEwJGUjEZMBcGA1UE
CBMQRGVmYXVsdCBQcm92aW5jZTEPMA0GA1UEChMGTmV4ZWRpMB4XDTExMDkxNTA5
MDAwMloXDTEyMDkxNTA5MDAwMlowOTELMAkGA1UEBhMCRlIxGTAXBgNVBAgTEERl
ZmF1bHQgUHJvdmluY2UxDzANBgNVBAoTBk5leGVkaTCBnzANBgkqhkiG9w0BAQEF
AAOBjQAwgYkCgYEApYZv6OstoqNzxG1KI6iE5U4Ts2Xx9lgLeUGAMyfJLyMmRLhw
boKOyJ9Xke4dncoBAyNPokUR6iWOcnPHtMvNOsBFZ2f7VA28em3+E1JRYdeNUEtX
Z0s3HjcouaNAnPfjFTXHYj4um1wOw2cURSPuU5dpzKBbV+/QCb5DLheynisCAwEA
ATANBgkqhkiG9w0BAQsFAAOBgQBCZLbTVdrw3RZlVVMFezSHrhBYKAukTwZrNmJX
mHqi2tN8tNo6FX+wmxUUAf3e8R2Ymbdbn2bfbPpcKQ2fG7PuKGvhwMG3BlF9paEC
q7jdfWO18Zp/BG7tagz0jmmC4y/8akzHsVlruo2+2du2freE8dK746uoMlXlP93g
QUUGLQ==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB8jCCAVugAwIBAgIJAPu2zchZ2BxoMA0GCSqGSIb3DQEBBQUAMBIxEDAOBgNV
BAMMB3RzeGRldjMwHhcNMTExMDE0MTIxNjIzWhcNMTIxMDEzMTIxNjIzWjASMRAw
DgYDVQQDDAd0c3hkZXYzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrPbh+
YGmo6mWmhVb1vTqX0BbeU0jCTB8TK3i6ep3tzSw2rkUGSx3niXn9LNTFNcIn3MZN
XHqbb4AS2Zxyk/2tr3939qqOrS4YRCtXBwTCuFY6r+a7pZsjiTNddPsEhuj4lEnR
L8Ax5mmzoi9nE+hiPSwqjRwWRU1+182rzXmN4QIDAQABo1AwTjAdBgNVHQ4EFgQU
/4XXREzqBbBNJvX5gU8tLWxZaeQwHwYDVR0jBBgwFoAU/4XXREzqBbBNJvX5gU8t
LWxZaeQwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQA07q/rKoE7fAda
FED57/SR00OvY9wLlFEF2QJ5OLu+O33YUXDDbGpfUSF9R8l0g9dix1JbWK9nQ6Yd
R/KCo6D0sw0ZgeQv1aUXbl/xJ9k4jlTxmWbPeiiPZEqU1W9wN5lkGuLxV4CEGTKU
hJA/yXa1wbwIPGvX3tVKdOEWPRXZLg==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB7jCCAVegAwIBAgIJAJWA0jQ4o9DGMA0GCSqGSIb3DQEBBQUAMA8xDTALBgNV
BAMMBHg2MXMwIBcNMTExMTI0MTAyNDQzWhgPMjExMTEwMzExMDI0NDNaMA8xDTAL
BgNVBAMMBHg2MXMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANdJNiFsRlkH
vq2kHP2zdxEyzPAWZH3CQ3Myb3F8hERXTIFSUqntPXDKXDb7Y/laqjMXdj+vptKk
3Q36J+8VnJbSwjGwmEG6tym9qMSGIPPNw1JXY1R29eF3o4aj21o7DHAkhuNc5Tso
67fUSKgvyVnyH4G6ShQUAtghPaAwS0KvAgMBAAGjUDBOMB0GA1UdDgQWBBSjxFUE
RfnTvABRLAa34Ytkhz5vPzAfBgNVHSMEGDAWgBSjxFUERfnTvABRLAa34Ytkhz5v
PzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAFLDS7zNhlrQYSQO5KIj
z2RJe3fj4rLPklo3TmP5KLvendG+LErE2cbKPqnhQ2oVoj6u9tWVwo/g03PMrrnL
KrDm39slYD/1KoE5kB4l/p6KVOdeJ4I6xcgu9rnkqqHzDwI4v7e8/D3WZbpiFUsY
vaZhjNYKWQf79l6zXfOvphzJ
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB9jCCAV+gAwIBAgIJAO4V/jiMoICoMA0GCSqGSIb3DQEBBQUAMBMxETAPBgNV
BAMMCENPTVAtMjMyMCAXDTEyMDIxNjExMTAyM1oYDzIxMTIwMTIzMTExMDIzWjAT
MREwDwYDVQQDDAhDT01QLTIzMjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
wi/3Z8W9pUiegUXIk/AiFDQ0UJ4JFAwjqr+HSRUirlUsHHT+8DzH/hfcTDX1I5BB
D1ADk+ydXjMm3OZrQcXjn29OUfM5C+g+oqeMnYQImN0DDQIOcUyr7AJc4xhvuXQ1
P2pJ5NOd3tbd0kexETa1LVhR6EgBC25LyRBRae76qosCAwEAAaNQME4wHQYDVR0O
BBYEFMDmW9aFy1sKTfCpcRkYnP6zUd1cMB8GA1UdIwQYMBaAFMDmW9aFy1sKTfCp
cRkYnP6zUd1cMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAskbFizHr
b6d3iIyN+wffxz/V9epbKIZVEGJd/6LrTdLiUfJPec7FaxVCWNyKBlCpINBM7cEV
Gn9t8mdVQflNqOlAMkOlUv1ZugCt9rXYQOV7rrEYJBWirn43BOMn9Flp2nibblby
If1a2ZoqHRxoNo2yTmm7TSYRORWVS+vvfjY=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB9jCCAV+gAwIBAgIJAIlBksrZVkK8MA0GCSqGSIb3DQEBBQUAMBMxETAPBgNV
BAMMCENPTVAtMzU3MCAXDTEyMDEyNjEwNTUyOFoYDzIxMTIwMTAyMTA1NTI4WjAT
MREwDwYDVQQDDAhDT01QLTM1NzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
ts+iGUwi44vtIfwXR8DCnLtHV4ydl0YTK2joJflj0/Ws7mz5BYkxIU4fea/6+VF3
i11nwBgYgxQyjNztgc9u9O71k1W5tU95yO7U7bFdYd5uxYA9/22fjObaTQoC4Nc9
mTu6r/VHyJ1yRsunBZXvnk/XaKp7gGE9vNEyJvPn2bkCAwEAAaNQME4wHQYDVR0O
BBYEFKuGIYu8+6aEkTVg62BRYaD11PILMB8GA1UdIwQYMBaAFKuGIYu8+6aEkTVg
62BRYaD11PILMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAMoTRpBxK
YLEZJbofF7gSrRIcrlUJYXfTfw1QUBOKkGFFDsiJpEg4y5pUk1s5Jq9K3SDzNq/W
it1oYjOhuGg3al8OOeKFrU6nvNTF1BAvJCl0tr3POai5yXyN5jlK/zPfypmQYxE+
TaqQSGBJPVXYt6lrq/PRD9ciZgKLOwEqK8w=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB9jCCAV+gAwIBAgIJAPHoWu90gbsgMA0GCSqGSIb3DQEBBQUAMBQxEjAQBgNV
BAMMCXZpZmlibm9kZTAeFw0xMjAzMTkyMzIwNTVaFw0xMzAzMTkyMzIwNTVaMBQx
EjAQBgNVBAMMCXZpZmlibm9kZTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
ozBijpO8PS5RTeKTzA90vi9ezvv4vVjNaguqT4UwP9+O1+i6yq1Y2W5zZxw/Klbn
oudyNzie3/wqs9VfPmcyU9ajFzBv/Tobm3obmOqBN0GSYs5fyGw+O9G3//6ZEhf0
NinwdKmrRX+d0P5bHewadZWIvlmOupcnVJmkks852BECAwEAAaNQME4wHQYDVR0O
BBYEFF9EtgfZZs8L2ZxBJxSiY6eTsTEwMB8GA1UdIwQYMBaAFF9EtgfZZs8L2ZxB
JxSiY6eTsTEwMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAc43YTfc6
baSemaMAc/jz8LNLhRE5dLfLOcRSoHda8y0lOrfe4lHT6yP5l8uyWAzLW+g6s3DA
Yme/bhX0g51BmI6gjKJo5DoPtiXk/Y9lxwD3p7PWi+RhN+AZQ5rpo8UfwnnN059n
yDuimQfvJjBFMVrdn9iP6SfMjxKaGk6gVmI=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB9jCCAV+gAwIBAgIJAMNZBmoIOXPBMA0GCSqGSIb3DQEBBQUAMBMxETAPBgNV
BAMMCENPTVAtMTMyMCAXDTEyMDUwMjEyMDQyNloYDzIxMTIwNDA4MTIwNDI2WjAT
MREwDwYDVQQDDAhDT01QLTEzMjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
6peZQt1sAmMAmSG9BVxxcXm8x15kE9iAplmANYNQ7z2YO57c10jDtlYlwVfi/rct
xNUOKQtc8UQtV/fJWP0QT0GITdRz5X/TkWiojiFgkopza9/b1hXs5rltYByUGLhg
7JZ9dZGBihzPfn6U8ESAKiJzQP8Hyz/o81FPfuHCftsCAwEAAaNQME4wHQYDVR0O
BBYEFNuxsc77Z6/JSKPoyloHNm9zF9yqMB8GA1UdIwQYMBaAFNuxsc77Z6/JSKPo
yloHNm9zF9yqMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAl4hBaJy1
cgiNV2+Z5oNTrHgmzWvSY4duECOTBxeuIOnhql3vLlaQmo0p8Z4c13kTZq2s3nhd
Loe5mIHsjRVKvzB6SvIaFUYq/EzmHnqNdpIGkT/Mj7r/iUs61btTcGUCLsUiUeci
Vd0Ozh79JSRpkrdI8R/NRQ2XPHAo+29TT70=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB9jCCAV+gAwIBAgIJAKRvzcy7OH0UMA0GCSqGSIb3DQEBBQUAMBMxETAPBgNV
BAMMCENPTVAtNzcyMCAXDTEyMDgxMDE1NDI1MVoYDzIxMTIwNzE3MTU0MjUxWjAT
MREwDwYDVQQDDAhDT01QLTc3MjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
o7aipd6MbnuGDeR1UJUjuMLQUariAyQ2l2ZDS6TfOwjHiPw/mhzkielgk73kqN7A
sUREx41eTcYCXzTq3WP3xCLE4LxLg1eIhd4nwNHj8H18xR9aP0AGjo4UFl5BOMa1
mwoyBt3VtfGtUmb8whpeJgHhqrPPxLoON+i6fIbXDaUCAwEAAaNQME4wHQYDVR0O
BBYEFEfjy3OopT2lOksKmKBNHTJE2hFlMB8GA1UdIwQYMBaAFEfjy3OopT2lOksK
mKBNHTJE2hFlMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAaNRx6YN2
M/p3R8/xS6zvH1EqJ3FFD7XeAQ52WuQnKSREzuw0dsw12ClxjcHiQEFioyTiTtjs
5pW18Ry5Ie7iFK4cQMerZwWPxBodEbAteYlRsI6kePV7Gf735Y1RpuN8qZ2sYL6e
x2IMeSwJ82BpdEI5niXxB+iT0HxhmR+XaMI=
-----END CERTIFICATE-----
[versions]
Jinja2 = 2.7
MarkupSafe = 0.18
Werkzeug = 0.8.3
buildout-versions = 1.7
inotifyx = 0.2.0-1
lxml = 3.2.1
meld3 = 0.6.10
netaddr = 0.7.10
plone.recipe.command = 1.1
pytz = 2013b
slapos.core = 0.35.1
slapos.recipe.cmmi = 0.1.1
slapos.recipe.download = 1.0.dev-r4053
slapos.recipe.template = 2.4.2
xml-marshaller = 0.9.7
slapos.cookbook=0.78.1
# Required by:
# slapos.core==0.35.1
Flask = 0.9
# Required by:
# slapos.cookbook==0.78.1
lock-file = 2.0
# Required by:
# slapos.core==0.35.1
netifaces = 0.8-1
# Required by:
# slapos.core==0.35.1
pyflakes = 0.7.2
# Required by:
# hexagonit.recipe.download==1.6nxd002
# slapos.cookbook==0.78.1
# slapos.core==0.35.1
# supervisor==3.0b1
# zc.buildout==1.6.0-dev-SlapOS-010
# zope.interface==4.0.5
setuptools = 0.6c12dev-r88846
# Required by:
# slapos.core==0.35.1
supervisor = 3.0b1
# Required by:
# slapos.core==0.35.1
unittest2 = 0.5.1
# Required by:
# slapos.core==0.35.1
zope.interface = 4.0.5
BOINC Server
============
Introduction
------------
The Berkeley Open Infrastructure for Network Computing (BOINC) is an open
source middleware system for volunteer and grid computing.
http://boinc.berkeley.edu/trac/wiki/ProjectMain
This Software Release is used to deploy an instance of BOINC server on SlapOS
How it work?
------------
The following example show how to request an instance of BOINC server.
BOINC Server Parameters :
- project: The name of your project. Default is project=boinc_test
- full-name: Full name of your project. Default is full-name=Boinc Project SAMPLE
- domain: Use this parameter if you want to define by hand the url of your project.
Ex: domain = http://myboinc.host-dommain.com
- copyright-holder: The name of your compagny. It will be displayed at the footer of
your BOINC project website.
Job Submission Parameters:
- default-template-result (Default is ${boinc-default:template-result}): Set the
default Output Template to use when creating a BOINC work unit.
- default-template-wu (Default is ${boinc-default:template-wu}): Set the
default Input Template to use when creating a BOINC work unit.
- default-extension (Default is ${boinc-default:extension}): For example in windows if
job executable is an .exe, set default-extension=exe
- default-platform (Default is ${boinc-default:platform}): Set the default platform
for job submission. http://boinc.berkeley.edu/trac/wiki/BoincPlatforms
- boinc-app-list: Use this json parameter to submit your job list to BOINC Server.
For exemple:
boinc-app-list = {"APP_NAME":
{"APP_VERSION":
{"use_default":true, "binary":"PATH/URL_OF_BINARY",
"wu-number":NUM, "input-file":"PATH/URL_OF_INPUT_FILE"},
"APP_VERSION2":
{"use_default":false, "binary":"PATH/URL_OF_BINARY",
"wu-number":NUM, "input-file":"PATH/URL_OF_INPUT_FILE",
"extension":"", "platform":"x86_64-pc-linux-gnu",
"template-result":"PATH/URL_OF_OUTPUT_TEMPLATE",
"template-wu":"PATH/URL_OF_INPUT_TEMPLATE"}
}, ...}
APP_NAME example: upper_case (without space)
APP_VERSION examples: 1.00, 2.10, 1.10
Request your instance:
This is a minimal parameter to use:
<?xml version="1.0" encoding="utf-8"?>
<instance>
<parameter id="project">Sample</parameter>
<parameter id="full-name">My BOINC project Sample</parameter>
<parameter id="copyright-holder">my.compagny.com</parameter>
<parameter id="boinc-app-list">JSON-JOB-LIST</parameter>
</instance>
Note: - You can update boinc-app-list anytime, this would allow you to update the
nomber of work unit, or to modify files. For any job modification, APP_NAME and
APP_VERSION is required.
- To create another BOINC project, please request another instance on SlapOS.
Warning: Once your project has been started (and BOINC client is connected on current
server), don't change the project name, otherwise this would cause the lost of current project.
Connect to your instance
------------------------
When your instance is ready, SlapOS must provide 3 URL:
boinc_home_page URL_BASE/PROJECT/ (public web page, BOINC Client will use this URL
to connect to your server)
boinc_admin_page URL_BASE/PROJECT_ops/ (administrative web page)
boinc_result_url URL_BASE/PROJECT_result/ (result web page, this page will allow
you to show job result)
test string
\ No newline at end of file
[buildout]
parts =
switch_softwaretype
eggs-directory = ${buildout:eggs-directory}
develop-eggs-directory = ${buildout:develop-eggs-directory}
offline = true
[switch_softwaretype]
recipe = slapos.cookbook:softwaretype
default = ${template-boinc:output}
mariadb = ${template-mariadb:output}
\ No newline at end of file
[buildout]
parts =
template
application
template_wu
template_result
template_input
slapos-cookbook
instance-egg
extends =
../../stack/boinc/buildout.cfg
#Generate All instances templates
[template]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/instance.cfg
output = ${buildout:directory}/template.cfg
mode = 0644
md5sum = 4a286795a6822ee6d53743191d5374a6
#Download Boinc Application Binary and configure project
[application]
recipe = hexagonit.recipe.download
url = ${boinc:location}/libexec/examples/upper_case
download-only = true
filename = upper_case
#Application configuration
app-name = upper_case
version = 1.00
[template-base]
recipe = slapos.recipe.download
download-only = true
mode = 0644
[template_result]
<= template-base
url = ${:_profile_base_location_}/templates/template_result
filename = template_result
location = ${buildout:parts-directory}/${:_buildout_section_name_}
md5sum = a3f0e9fd559cadcb2f297b952f8face8
[template_wu]
<= template-base
url = ${:_profile_base_location_}/templates/template_wu
filename = template_wu
location = ${buildout:parts-directory}/${:_buildout_section_name_}
md5sum = 66d7ec85ce15e65d2858c11b75fb9574
[template_input]
<= template-base
url = ${:_profile_base_location_}/input/input_file
filename = input_file
location = ${buildout:parts-directory}/${:_buildout_section_name_}
md5sum = 6f8db599de986fab7a21625b7916589c
[boinc-application]
app-list = {"${application:app-name}":{"${application:version}":{"use_default":true, "wu-number":2, "input-file":"${template_input:location}/${template_input:filename}", "binary":"${application:location}/${application:filename}"}}}
[boinc-default]
template-result = ${template_result:location}/${template_result:filename}
template-wu = ${template_wu:location}/${template_wu:filename}
platform = x86_64-pc-linux-gnu
extension =
<file_info>
<name><OUTFILE_0/></name>
<generated_locally/>
<upload_when_present/>
<max_nbytes>5000000</max_nbytes>
<url><UPLOAD_URL/></url>
</file_info>
<result>
<file_ref>
<file_name><OUTFILE_0/></file_name>
<open_name>out</open_name>
</file_ref>
</result>
\ No newline at end of file
<file_info>
<number>0</number>
</file_info>
<workunit>
<file_ref>
<file_number>0</file_number>
<open_name>in</open_name>
</file_ref>
<command_line>-cpu_time 10</command_line>
</workunit>
\ No newline at end of file
[buildout]
parts =
boinc-client
publish-connection-informations
eggs-directory = ${buildout:eggs-directory}
develop-eggs-directory = ${buildout:develop-eggs-directory}
offline = true
[rootdirectory]
recipe = slapos.cookbook:mkdirectory
etc = $${buildout:directory}/etc/
var = $${buildout:directory}/var/
srv = $${buildout:directory}/srv/
bin = $${buildout:directory}/bin/
tmp = $${buildout:directory}/tmp/
[basedirectory]
recipe = slapos.cookbook:mkdirectory
log = $${rootdirectory:var}/log/
boinc_wrapper = $${rootdirectory:etc}/boinc/
run = $${rootdirectory:var}/run/
backup = $${rootdirectory:srv}/backup/
promises = $${rootdirectory:etc}/promise/
boinc = $${rootdirectory:srv}/boinc/
[boinc-passwd]
recipe = slapos.cookbook:generate.password
storage-path = $${basedirectory:boinc}/gui_rpc_auth.cfg
bytes = 8
[boinc-client]
recipe = slapos.cookbook:boinc.client
install-dir = $${basedirectory:boinc}
home = $${buildout:directory}
client-wrapper = $${basedirectory:boinc_wrapper}/boinc_client
cmd-wrapper = $${basedirectory:boinc_wrapper}/boinc_cmd
#specifie a cc_config.xml file to boinc client, use cconfig
ip = $${slap-network-information:global-ipv6}
passwd = $${boinc-passwd:passwd}
cconfig =
boinc-bin = ${boinc:location}/bin/boinc_client
cmd-bin = ${boinc:location}/bin/boinccmd
server-url =
key =
# Publish all instance parameters
[publish-connection-informations]
recipe = slapos.cookbook:publish
#this informations is provide in intern by bonjourgrid
boinc_remote-host = $${boinc-client:ip}
boinc_rpc-port = $${boinc-client:rpc-port}
boinc_rpc-passwd = $${boinc-passwd:passwd}
[buildout]
parts =
condor
boinc-client
computerinfo-script
bonjourgrid-client
publish-connection-informations
extends =
${template-condor:output}
${template-boinc:output}
eggs-directory = ${buildout:eggs-directory}
develop-eggs-directory = ${buildout:develop-eggs-directory}
offline = true
[basedirectory]
recipe = slapos.cookbook:mkdirectory
log = $${rootdirectory:var}/log/
run = $${rootdirectory:var}/run/
services = $${rootdirectory:etc}/service/
backup = $${rootdirectory:srv}/backup/
promises = $${rootdirectory:etc}/promise/
bg_base = $${rootdirectory:srv}/bonjourgrid/
[account-passwd]
recipe = slapos.cookbook:generate.password
storage-path = $${rootdirectory:etc}/.account_passwd
bytes = 8
[computerinfo-script]
recipe = slapos.recipe.template
url = ${computer-info:location}/${computer-info:filename}
output = $${bonjourgrid-client:work_dir}/machineinfo.worker.sh
mode = 0744
ip_address = $${slap-network-information:global-ipv6}
[bonjourgrid-client]
recipe = slapos.cookbook:bonjourgrid.client
client_script = ${bonjourgrid:location}/BonjourGridWorker.py
work_dir = $${basedirectory:bg_base}
install_dir = ${bonjourgrid:location}
boinc_script = $${basedirectory:bg_base}/runBoinc
condor_script = $${basedirectory:bg_base}/runCondor
wrapper = $${basedirectory:services}/bonjourGrid-Worker
log_file = $${basedirectory:log}/bonjourgrid-worker.log
pid_file = $${basedirectory:run}/bonjourgrid-worker.pid
python-bin = ${buildout:executable}
redis-url = $${slap-parameter:redis-ip}
redis-port = $${slap-parameter:redis-port}
#Boinc and Condor parameters
ipv6 = $${slap-network-information:global-ipv6}
email = $${slap-parameter:user-email}
condor_sbin = $${condor:sbin}
condor_bin = $${condor:bin}
boinc_wrapper = $${boinc-client:client-wrapper}
condor_wrapper = $${condor:wrapper-dir}/start_condor
boinc_cmd = $${boinc-client:cmd-bin}
boinc_rpc_port = $${boinc-client:rpc-port}
boinc_install_dir = $${boinc-client:install-dir}
condor_config = $${buildout:directory}/etc/condor_config
condor_config_local = $${condor:local-dir}/condor_config.local
boinc_passwd = $${boinc-client:passwd}
account_name = $${slap-parameter:full-name}
account_passwd = $${account-passwd:passwd}
[publish-connection-informations]
boinc-account-email = $${slap-parameter:user-email}
boinc-account-name = $${slap-parameter:full-name}
boinc-account-passwd = $${account-passwd:passwd}
[slap-parameter]
user-email = your.email@your.domain.com
full-name = Your Full Name
redis-ip =
redis-port = 6379
\ No newline at end of file
[buildout]
parts =
condor
publish-connection-informations
eggs-directory = ${buildout:eggs-directory}
develop-eggs-directory = ${buildout:develop-eggs-directory}
#Enable download
newest = false
offline = false
# Create all needed directories
[rootdirectory]
recipe = slapos.cookbook:mkdirectory
etc = $${buildout:directory}/etc/
var = $${buildout:directory}/var/
condor = $${buildout:directory}/condor/
job = $${buildout:directory}/jobs/
bin = $${buildout:directory}/bin/
sbin = $${buildout:directory}/sbin/
srv = $${buildout:directory}/srv/
[basedirectory]
recipe = slapos.cookbook:mkdirectory
log = $${rootdirectory:var}/log/
run = $${rootdirectory:var}/run/
backup = $${rootdirectory:srv}/backup/
promises = $${rootdirectory:etc}/promise/
condor = $${rootdirectory:etc}/condor/
[wrapperdirectory]
recipe = slapos.cookbook:mkdirectory
wrapper = $${basedirectory:run}/condor
[condor]
recipe = slapos.cookbook:condor
#Change default wrapper dir to /etc/condor/
wrapper-dir = $${basedirectory:condor}
ip = $${slap-network-information:global-ipv6}
package = ${condor:location}
rootdirectory = $${buildout:directory}
local-dir = $${rootdirectory:condor}
job-dir = $${rootdirectory:job}
java-bin = ${java:location}/bin
bin = $${wrapperdirectory:wrapper}/bin/
sbin = $${wrapperdirectory:wrapper}/sbin/
dash = ${dash:location}/bin/dash
environment =
LD_LIBRARY_PATH=${libexpat:location}/lib:${kerberos:location}/lib:${openldap:location}/lib:${zlib:location}/lib
PATH=${perl:location}/bin:${java:location}/bin:${kerberos:location}/bin:${openldap:location}/bin:%(PATH)s
HOME=$${rootdirectory:condor}
HOSTNAME=$${slap-parameter:condor_host}
#Condor user parameter
condor_host = $${slap-parameter:condor_host}
collector_name = $${slap-parameter:condor_collector_name}
#Condor machine role: worker=submit,execute manager=manager,submit
machine-role = worker
disk-space = $${slap-parameter:condor_diskspace}
allowed-write = $${slap-parameter:condor_allowed-write}
admin-email =
# Publish all instance parameters (url of instance)
[publish-connection-informations]
recipe = slapos.cookbook:publish
condor_ipv6_address = $${condor:ip}
condor_instance_type = worker
condor_host = $${condor:condor_host}
[slap-parameter]
# Default values if not specified
condor_host = [$${slap-network-information:global-ipv6}]
condor_collector_name = SLAPOS-CONDOR-POOL
condor_diskspace = 5
condor_allowed-write = $${:condor_host}
\ No newline at end of file
[buildout]
parts =
switch_softwaretype
eggs-directory = ${buildout:eggs-directory}
develop-eggs-directory = ${buildout:develop-eggs-directory}
offline = true
[switch_softwaretype]
recipe = slapos.cookbook:softwaretype
default = ${template-bonjourgrid:output}
\ No newline at end of file
[buildout]
# Local development - to be remove
develop =
${:parts-directory}/slapos.cookbook-repository
parts=
slapos-cookbook
boinc
condor
computer-info
bonjourgrid
template
template-boinc
template-condor
template-bonjourgrid
slapos.cookbook-repository
check-recipe
extends =
../../component/boinc-client/buildout.cfg
../../component/condor/buildout.cfg
../../component/git/buildout.cfg
../../stack/slapos.cfg
[template-bonjourgrid]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/bonjourgrid-instance.cfg
output = ${buildout:directory}/template-bonjourgrid.cfg
mode = 0644
md5sum = 4cf5a1a44bc7185f8882ab7247f309fc
[bonjourgrid]
recipe = hexagonit.recipe.download
url = ${:_profile_base_location_}/bonjourgrid.src/bonjourgrid.slapos.tar.gz
md5sum = 5b4594b8451d83eedfa5224dbdcbb872
[template]
# Default template for boinc-client instance.
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/instance.cfg
md5sum = 1fad063b948b00be92cbd4d6b1bb8c10
output = ${buildout:directory}/template.cfg
mode = 0644
[computer-info]
recipe = hexagonit.recipe.download
url = ${:_profile_base_location_}/templates/machineinfo.worker.sh.in
md5sum = 994fcb4dff1c86755b27f7c4a085e24a
filename = machineinfo.worker.sh.in
download-only = true
[template-boinc]
# Default template for boinc-client instance.
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/boinc-instance.cfg
md5sum = 0d9da949721c58494fde07ab03684331
output = ${buildout:directory}/template-boinc.cfg
mode = 0644
[template-condor]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/condor-instance.cfg
output = ${buildout:directory}/template-condor.cfg
md5sum = c314c3a338e5f5fa7862cf2ff14bef1b
mode = 0644
# Local development
[slapos.cookbook-repository]
recipe = plone.recipe.command
stop-on-error = true
branch = grid-computing
revision =
location = ${buildout:parts-directory}/${:_buildout_section_name_}
command = "${git:location}/bin/git" clone --branch "${:branch}" --quiet http://git.erp5.org/repos/slapos.git "${:location}" && if [ -n "${:revision}" ]; then cd "${:location}" && "${git:location}/bin/git" reset --quiet --hard "${:revision}" ; fi
update-command = cd "${:location}" && "${git:location}/bin/git" fetch --quiet && if [ -n "${:revision}" ]; then "${git:location}/bin/git" reset --hard "${:revision}"; else "${git:location}/bin/git" reset --quiet --hard @{upstream} ; fi
[check-recipe]
recipe = plone.recipe.command
stop-on-error = true
update-command = ${:command}
command = grep parts ${buildout:develop-eggs-directory}/slapos.cookbook.egg-link
[versions]
lxml = 2.3.6
\ No newline at end of file
#!/bin/sh
# This script generates a file (with the name `hostname`) of the characteristics of the machine
Mhz=`grep -i Mhz /proc/cpuinfo | cut -d : -f2 | head -1 | cut -f2 -d " "`
mem=`grep -i MemTotal /proc/meminfo | cut -f2 -d :`
Ram=`echo $mem | cut -f1 -d " "`
Cpu=`uname -a | cut -f3 -d " "`
H=`hostname`
Nbproc=`grep processor /proc/cpuinfo |wc -l`
Ip=${:ip_address}
c="{'"MHZ"':\"$Mhz\",'"Ram"':\"$Ram\",'"Cpu"':\"$Cpu\",'"HOST"':\"$H\",'"IP"':\"$Ip\"}"
filename=`hostname`
echo $c > $filename
\ No newline at end of file
Universe = vanilla
Executable = simple
Arguments = 4 10
Log = simple.log
Output = simple.$(Process).out
Error = simple.$(Process).error
Queue
Arguments = 4 11
Queue
Arguments = 4 12
Queue
\ No newline at end of file
test string
\ No newline at end of file
[buildout]
parts =
redis
bonjourgrid
boinc-server
certificate-authority
ca-stunnel
logrotate
logrotate-entry-apache
logrotate-entry-stunnel
cron
cron-entry-logrotate
cron-entry-boinc
promise
slapmonitor
frontend-promise
content-promise
publish-connection-informations
boinc-app
condor
app-submit
extends =
${template-condor:output}
${template-boinc:output}
${template-redis:output}
[rootdirectory]
recipe = slapos.cookbook:mkdirectory
etc = $${buildout:directory}/etc/
srv = $${buildout:directory}/srv/
var = $${buildout:directory}/var/
bin = $${buildout:directory}/bin/
[basedirectory]
recipe = slapos.cookbook:mkdirectory
scripts = $${rootdirectory:etc}/run/
log = $${rootdirectory:var}/log/
run = $${rootdirectory:var}/run/
backup = $${rootdirectory:srv}/backup/
promises = $${rootdirectory:etc}/promise/
bonjourgrid = $${rootdirectory:etc}/bonjourgrid.d/
bg_base = $${rootdirectory:srv}/bonjourgrid/
condor = $${rootdirectory:etc}/condor/
boinc = $${rootdirectory:etc}/boinc/
#Override Boinc server part with custom variables for BonjourGrid
#Change the wrapper directory to /bin/boinc/
[boinc-server]
wrapper-dir = $${basedirectory:boinc}
[condor]
#Change default wrapper dir to /etc/condor/
wrapper-dir = $${basedirectory:condor}
[bonjourgrid]
recipe = slapos.cookbook:bonjourgrid
master_script = ${bonjourgrid:location}/BonjourGridMaster.py
work_dir = $${basedirectory:bg_base}
install_dir = ${bonjourgrid:location}
condor-wrapper = $${condor:wrapper-dir}
boinc-wrapper = $${boinc-server:wrapper-dir}
boinc_condor_wrapper = $${basedirectory:bonjourgrid}/bonjourGrid
wrapper = $${basedirectory:services}/bonjourGrid
log_file = $${basedirectory:log}/bonjourgrid.log
pid_file = $${basedirectory:run}/bonjourgrid.pid
nworkers = $${slap-parameter:worker-number}
redis-url = $${slap-parameter:server-url}
redis-port = $${slap-parameter:server-port}
redis-passwd = $${slap-parameter:server-password}
type = $${slap-parameter:project-type}
python-bin = ${buildout:executable}
url-boinc = $${boinc-app:url-base}$${boinc-app:project}/
condor_host = $${slap-parameter:condor-host}
ipv6 = $${condor:ip}
[publish-connection-informations]
bg_instance_type = $${slap-parameter:project-type}
condor_ipv6_address = $${condor:ip}
condor_instance_type = $${condor:machine-role}
condor_host = $${condor:condor_host}
redis_ip = $${bonjourgrid:redis-url}
redis_port = $${bonjourgrid:redis-port}
redis_passwd = $${bonjourgrid:redis-passwd}
redis_uses_password = $${redis:use_passwd}
[slap-parameter]
project = bonjourgrid
server-url = $${redis:ipv6}
server-port = $${redis:port}
server-password = $${redis:passwd}
worker-number = 1
#specified if we want to run BOINC or Condor project:
#project-type = boinc | condor
project-type = boinc
###Condor Parameters #####
condor-host = [$${slap-network-information:global-ipv6}]
condor-collector-name = SLAPOS-CONDOR-POOL
condor-role = manager
condor-diskspace = 5
condor-admin-email =
condor-allowed-write = $${:condor-host}
#submit application, using Json application list
condor-app-list = ${condor-application:list}
###Redis Parameters####
use_passwd = false
###BOINC parameters --Refer to Boinc Stack######
[buildout]
parts =
switch_softwaretype
eggs-directory = ${buildout:eggs-directory}
develop-eggs-directory = ${buildout:develop-eggs-directory}
offline = true
[switch_softwaretype]
recipe = slapos.cookbook:softwaretype
default = ${bonjourgrid-instance:output}
mariadb = ${template-mariadb:output}
\ No newline at end of file
[buildout]
# Local development - to be remove
develop =
${:parts-directory}/slapos.cookbook-repository
parts =
template
application
template_wu
template_result
template_input
template-redis
slapos-cookbook
instance-egg
condor
redis
template-condor
description-file
executable
bonjourgrid-instance
bonjourgrid
slapos.cookbook-repository
check-recipe
extends =
../../stack/boinc/buildout.cfg
../../component/condor/buildout.cfg
../../component/redis/buildout.cfg
../../component/git/buildout.cfg
../../stack/slapos.cfg
#Generate All instances templates
[template]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/instance.cfg
output = ${buildout:directory}/template.cfg
mode = 0644
md5sum = 2f23572c39bfcedcdebdb5963aeefc38
################################
### BonjourGrid description ####
################################
[bonjourgrid-instance]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/instance-bonjourgrid.cfg
output = ${buildout:directory}/template-bonjourgrid.cfg
mode = 0644
md5sum = 59cc789d6ce765d3d25f9bd6f9659e55
[bonjourgrid]
recipe = hexagonit.recipe.download
url = ${:_profile_base_location_}/bonjourgrid.src/bonjourgrid.slapos.tar.gz
md5sum = 5b4594b8451d83eedfa5224dbdcbb872
#################################
### Redis-Server description ####
#################################
[template-redis]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/../redis-server/instance-redis.cfg
output = ${buildout:directory}/template-redis.cfg
mode = 0644
md5sum = 8b223d1fe0ffd40c7151766730da7fcb
#################################
### BOINC Server description ####
#################################
#Download Boinc Application Binary and configure project
[application]
recipe = hexagonit.recipe.download
url = ${boinc:location}/libexec/examples/upper_case
download-only = true
filename = upper_case
#Application configuration
app-name = upper_case
version = 1.00
[template-base]
recipe = slapos.recipe.download
download-only = true
mode = 0644
[template_result]
<= template-base
url = ${:_profile_base_location_}/templates/template_result
filename = template_result
location = ${buildout:parts-directory}/${:_buildout_section_name_}
md5sum = a3f0e9fd559cadcb2f297b952f8face8
[template_wu]
<= template-base
url = ${:_profile_base_location_}/templates/template_wu
filename = template_wu
location = ${buildout:parts-directory}/${:_buildout_section_name_}
md5sum = 66d7ec85ce15e65d2858c11b75fb9574
[template_input]
<= template-base
url = ${:_profile_base_location_}/input/input_file
filename = input_file
location = ${buildout:parts-directory}/${:_buildout_section_name_}
md5sum = 6f8db599de986fab7a21625b7916589c
[boinc-application]
app-list = {"${application:app-name}":{"${application:version}":{"use_default":true, "wu-number":2, "input-file":"${template_input:location}/${template_input:filename}", "binary":"${application:location}/${application:filename}"}}}
[boinc-default]
template-result = ${template_result:location}/${template_result:filename}
template-wu = ${template_wu:location}/${template_wu:filename}
platform = x86_64-pc-linux-gnu
extension =
##########################
###Condor description ####
##########################
[template-condor]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/../condor/instance-condor.cfg
output = ${buildout:directory}/template-condor.cfg
md5sum = 42985a425369e4f93211cfaad21d8eb8
mode = 0644
[description-file]
recipe = slapos.recipe.download
mode = 0644
url = ${:_profile_base_location_}/condor_job/submit
filename = submit
location = ${buildout:parts-directory}/${:_buildout_section_name_}
md5sum = 8180d88348b89b55216f8dd4475a9eea
[executable]
recipe = slapos.recipe.download
mode = 0774
url = ${:_profile_base_location_}/condor_job/simple
filename = simple
location = ${buildout:parts-directory}/${:_buildout_section_name_}
md5sum = c512f495cdd112bceb04feab7c909a10
[condor-application]
list = {"condor_test":{"description-file":"${description-file:location}/${description-file:filename}", "executable":"${executable:location}/${executable:filename}", "executable-name":"${executable:filename}", "files":{}}}
######################################################"
# Local development
[slapos.cookbook-repository]
recipe = plone.recipe.command
stop-on-error = true
branch = grid-computing
revision =
location = ${buildout:parts-directory}/${:_buildout_section_name_}
command = "${git:location}/bin/git" clone --branch "${:branch}" --quiet http://git.erp5.org/repos/slapos.git "${:location}" && if [ -n "${:revision}" ]; then cd "${:location}" && "${git:location}/bin/git" reset --quiet --hard "${:revision}" ; fi
update-command = cd "${:location}" && "${git:location}/bin/git" fetch --quiet && if [ -n "${:revision}" ]; then "${git:location}/bin/git" reset --hard "${:revision}"; else "${git:location}/bin/git" reset --quiet --hard @{upstream} ; fi
[check-recipe]
recipe = plone.recipe.command
stop-on-error = true
update-command = ${:command}
command = grep parts ${buildout:develop-eggs-directory}/slapos.cookbook.egg-link
[versions]
lxml = 2.3.6
\ No newline at end of file
<file_info>
<name><OUTFILE_0/></name>
<generated_locally/>
<upload_when_present/>
<max_nbytes>5000000</max_nbytes>
<url><UPLOAD_URL/></url>
</file_info>
<result>
<file_ref>
<file_name><OUTFILE_0/></file_name>
<open_name>out</open_name>
</file_ref>
</result>
\ No newline at end of file
<file_info>
<number>0</number>
</file_info>
<workunit>
<file_ref>
<file_number>0</file_number>
<open_name>in</open_name>
</file_ref>
<command_line>-cpu_time 10</command_line>
</workunit>
\ No newline at end of file
[buildout]
parts =
condor
app-submit
publish-connection-informations
eggs-directory = ${buildout:eggs-directory}
develop-eggs-directory = ${buildout:develop-eggs-directory}
#Enable download
newest = false
offline = false
# Create all needed directories
[rootdirectory]
recipe = slapos.cookbook:mkdirectory
etc = $${buildout:directory}/etc/
var = $${buildout:directory}/var/
condor = $${buildout:directory}/condor/
job = $${buildout:directory}/jobs/
bin = $${buildout:directory}/bin/
sbin = $${buildout:directory}/sbin/
srv = $${buildout:directory}/srv/
[basedirectory]
recipe = slapos.cookbook:mkdirectory
log = $${rootdirectory:var}/log/
scripts = $${rootdirectory:etc}/run/
run = $${rootdirectory:var}/run/
backup = $${rootdirectory:srv}/backup/
promises = $${rootdirectory:etc}/promise/
[wrapperdirectory]
recipe = slapos.cookbook:mkdirectory
wrapper = $${basedirectory:run}/condor
[condor]
recipe = slapos.cookbook:condor
wrapper-dir = $${basedirectory:scripts}
ip = $${slap-network-information:global-ipv6}
package = ${condor:location}
rootdirectory = $${buildout:directory}
local-dir = $${rootdirectory:condor}
job-dir = $${rootdirectory:job}
java-bin = ${java:location}/bin
bin = $${wrapperdirectory:wrapper}/bin/
sbin = $${wrapperdirectory:wrapper}/sbin/
dash = ${dash:location}/bin/dash
environment =
LD_LIBRARY_PATH=${libexpat:location}/lib:${kerberos:location}/lib:${openldap:location}/lib:${zlib:location}/lib
PATH=${perl:location}/bin:${java:location}/bin:${kerberos:location}/bin:${openldap:location}/bin:%(PATH)s
HOME=$${rootdirectory:condor}
HOSTNAME=$${slap-parameter:condor-host}
#Condor user parameter
condor_host = $${slap-parameter:condor-host}
collector_name = $${slap-parameter:condor-collector-name}
#Condor machine role: worker=submit,execute manager=manager,submit
machine-role = $${slap-parameter:condor-role}
disk-space = $${slap-parameter:condor-diskspace}
allowed-write = $${slap-parameter:condor-allowed-write}
admin-email = $${slap-parameter:condor-admin-email}
[app-submit]
<= condor
recipe = slapos.cookbook:condor.submit
condor-app-list = $${slap-parameter:condor-app-list}
# Publish all instance parameters (url of instance)
[publish-connection-informations]
recipe = slapos.cookbook:publish
condor_ipv6_address = $${condor:ip}
condor_instance_type = $${condor:machine-role}
condor_host = $${condor:condor_host}
[slap-parameter]
# Default values if not specified
condor-host = [$${slap-network-information:global-ipv6}]
condor-collector-name = SLAPOS-CONDOR-POOL
condor-role = manager
condor-diskspace = 5
condor-admin-email =
condor-allowed-write = $${:condor-host}
#submit application, using Json application list
condor-app-list = ${condor-application:list}
[buildout]
parts =
switch_softwaretype
eggs-directory = ${buildout:eggs-directory}
develop-eggs-directory = ${buildout:develop-eggs-directory}
offline = true
[switch_softwaretype]
recipe = slapos.cookbook:softwaretype
default = ${template-condor:output}
\ No newline at end of file
[buildout]
parts =
condor
slapos-cookbook
template
template-condor
description-file
executable
extends =
../../component/condor/buildout.cfg
../../stack/slapos.cfg
[template]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/instance.cfg
output = ${buildout:directory}/template.cfg
mode = 0644
md5sum = 9e9db6f4c5e38ce3fd45d43c2bf616a8
[template-condor]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/instance-condor.cfg
output = ${buildout:directory}/template-condor.cfg
md5sum = 42985a425369e4f93211cfaad21d8eb8
mode = 0644
[description-file]
recipe = slapos.recipe.download
mode = 0644
url = ${:_profile_base_location_}/template/submit
filename = submit
location = ${buildout:parts-directory}/${:_buildout_section_name_}
md5sum = 8180d88348b89b55216f8dd4475a9eea
[executable]
recipe = slapos.recipe.download
mode = 0774
url = ${:_profile_base_location_}/template/simple
filename = simple
location = ${buildout:parts-directory}/${:_buildout_section_name_}
md5sum = c512f495cdd112bceb04feab7c909a10
[condor-application]
list = {"condor_test":{"description-file":"${description-file:location}/${description-file:filename}", "executable":"${executable:location}/${executable:filename}", "executable-name":"${executable:filename}", "files":{}}}
[networkcache]
# signature certificates of the following uploaders.
# Romain Courteaud
# Sebastien Robin
# Kazuhiko Shiozaki
# Cedric de Saint Martin
# Yingjie Xu
# Gabriel Monnerat
# Łukasz Nowak
# Test Agent (Automatic update from tests)
# Alain Takoudjou
signature-certificate-list =
-----BEGIN CERTIFICATE-----
MIIB4DCCAUkCADANBgkqhkiG9w0BAQsFADA5MQswCQYDVQQGEwJGUjEZMBcGA1UE
CBMQRGVmYXVsdCBQcm92aW5jZTEPMA0GA1UEChMGTmV4ZWRpMB4XDTExMDkxNTA5
MDAwMloXDTEyMDkxNTA5MDAwMlowOTELMAkGA1UEBhMCRlIxGTAXBgNVBAgTEERl
ZmF1bHQgUHJvdmluY2UxDzANBgNVBAoTBk5leGVkaTCBnzANBgkqhkiG9w0BAQEF
AAOBjQAwgYkCgYEApYZv6OstoqNzxG1KI6iE5U4Ts2Xx9lgLeUGAMyfJLyMmRLhw
boKOyJ9Xke4dncoBAyNPokUR6iWOcnPHtMvNOsBFZ2f7VA28em3+E1JRYdeNUEtX
Z0s3HjcouaNAnPfjFTXHYj4um1wOw2cURSPuU5dpzKBbV+/QCb5DLheynisCAwEA
ATANBgkqhkiG9w0BAQsFAAOBgQBCZLbTVdrw3RZlVVMFezSHrhBYKAukTwZrNmJX
mHqi2tN8tNo6FX+wmxUUAf3e8R2Ymbdbn2bfbPpcKQ2fG7PuKGvhwMG3BlF9paEC
q7jdfWO18Zp/BG7tagz0jmmC4y/8akzHsVlruo2+2du2freE8dK746uoMlXlP93g
QUUGLQ==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB8jCCAVugAwIBAgIJAPu2zchZ2BxoMA0GCSqGSIb3DQEBBQUAMBIxEDAOBgNV
BAMMB3RzeGRldjMwHhcNMTExMDE0MTIxNjIzWhcNMTIxMDEzMTIxNjIzWjASMRAw
DgYDVQQDDAd0c3hkZXYzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrPbh+
YGmo6mWmhVb1vTqX0BbeU0jCTB8TK3i6ep3tzSw2rkUGSx3niXn9LNTFNcIn3MZN
XHqbb4AS2Zxyk/2tr3939qqOrS4YRCtXBwTCuFY6r+a7pZsjiTNddPsEhuj4lEnR
L8Ax5mmzoi9nE+hiPSwqjRwWRU1+182rzXmN4QIDAQABo1AwTjAdBgNVHQ4EFgQU
/4XXREzqBbBNJvX5gU8tLWxZaeQwHwYDVR0jBBgwFoAU/4XXREzqBbBNJvX5gU8t
LWxZaeQwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQA07q/rKoE7fAda
FED57/SR00OvY9wLlFEF2QJ5OLu+O33YUXDDbGpfUSF9R8l0g9dix1JbWK9nQ6Yd
R/KCo6D0sw0ZgeQv1aUXbl/xJ9k4jlTxmWbPeiiPZEqU1W9wN5lkGuLxV4CEGTKU
hJA/yXa1wbwIPGvX3tVKdOEWPRXZLg==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB7jCCAVegAwIBAgIJAJWA0jQ4o9DGMA0GCSqGSIb3DQEBBQUAMA8xDTALBgNV
BAMMBHg2MXMwIBcNMTExMTI0MTAyNDQzWhgPMjExMTEwMzExMDI0NDNaMA8xDTAL
BgNVBAMMBHg2MXMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANdJNiFsRlkH
vq2kHP2zdxEyzPAWZH3CQ3Myb3F8hERXTIFSUqntPXDKXDb7Y/laqjMXdj+vptKk
3Q36J+8VnJbSwjGwmEG6tym9qMSGIPPNw1JXY1R29eF3o4aj21o7DHAkhuNc5Tso
67fUSKgvyVnyH4G6ShQUAtghPaAwS0KvAgMBAAGjUDBOMB0GA1UdDgQWBBSjxFUE
RfnTvABRLAa34Ytkhz5vPzAfBgNVHSMEGDAWgBSjxFUERfnTvABRLAa34Ytkhz5v
PzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAFLDS7zNhlrQYSQO5KIj
z2RJe3fj4rLPklo3TmP5KLvendG+LErE2cbKPqnhQ2oVoj6u9tWVwo/g03PMrrnL
KrDm39slYD/1KoE5kB4l/p6KVOdeJ4I6xcgu9rnkqqHzDwI4v7e8/D3WZbpiFUsY
vaZhjNYKWQf79l6zXfOvphzJ
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB9jCCAV+gAwIBAgIJAO4V/jiMoICoMA0GCSqGSIb3DQEBBQUAMBMxETAPBgNV
BAMMCENPTVAtMjMyMCAXDTEyMDIxNjExMTAyM1oYDzIxMTIwMTIzMTExMDIzWjAT
MREwDwYDVQQDDAhDT01QLTIzMjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
wi/3Z8W9pUiegUXIk/AiFDQ0UJ4JFAwjqr+HSRUirlUsHHT+8DzH/hfcTDX1I5BB
D1ADk+ydXjMm3OZrQcXjn29OUfM5C+g+oqeMnYQImN0DDQIOcUyr7AJc4xhvuXQ1
P2pJ5NOd3tbd0kexETa1LVhR6EgBC25LyRBRae76qosCAwEAAaNQME4wHQYDVR0O
BBYEFMDmW9aFy1sKTfCpcRkYnP6zUd1cMB8GA1UdIwQYMBaAFMDmW9aFy1sKTfCp
cRkYnP6zUd1cMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAskbFizHr
b6d3iIyN+wffxz/V9epbKIZVEGJd/6LrTdLiUfJPec7FaxVCWNyKBlCpINBM7cEV
Gn9t8mdVQflNqOlAMkOlUv1ZugCt9rXYQOV7rrEYJBWirn43BOMn9Flp2nibblby
If1a2ZoqHRxoNo2yTmm7TSYRORWVS+vvfjY=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB9jCCAV+gAwIBAgIJAIlBksrZVkK8MA0GCSqGSIb3DQEBBQUAMBMxETAPBgNV
BAMMCENPTVAtMzU3MCAXDTEyMDEyNjEwNTUyOFoYDzIxMTIwMTAyMTA1NTI4WjAT
MREwDwYDVQQDDAhDT01QLTM1NzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
ts+iGUwi44vtIfwXR8DCnLtHV4ydl0YTK2joJflj0/Ws7mz5BYkxIU4fea/6+VF3
i11nwBgYgxQyjNztgc9u9O71k1W5tU95yO7U7bFdYd5uxYA9/22fjObaTQoC4Nc9
mTu6r/VHyJ1yRsunBZXvnk/XaKp7gGE9vNEyJvPn2bkCAwEAAaNQME4wHQYDVR0O
BBYEFKuGIYu8+6aEkTVg62BRYaD11PILMB8GA1UdIwQYMBaAFKuGIYu8+6aEkTVg
62BRYaD11PILMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAMoTRpBxK
YLEZJbofF7gSrRIcrlUJYXfTfw1QUBOKkGFFDsiJpEg4y5pUk1s5Jq9K3SDzNq/W
it1oYjOhuGg3al8OOeKFrU6nvNTF1BAvJCl0tr3POai5yXyN5jlK/zPfypmQYxE+
TaqQSGBJPVXYt6lrq/PRD9ciZgKLOwEqK8w=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB9jCCAV+gAwIBAgIJAPHoWu90gbsgMA0GCSqGSIb3DQEBBQUAMBQxEjAQBgNV
BAMMCXZpZmlibm9kZTAeFw0xMjAzMTkyMzIwNTVaFw0xMzAzMTkyMzIwNTVaMBQx
EjAQBgNVBAMMCXZpZmlibm9kZTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
ozBijpO8PS5RTeKTzA90vi9ezvv4vVjNaguqT4UwP9+O1+i6yq1Y2W5zZxw/Klbn
oudyNzie3/wqs9VfPmcyU9ajFzBv/Tobm3obmOqBN0GSYs5fyGw+O9G3//6ZEhf0
NinwdKmrRX+d0P5bHewadZWIvlmOupcnVJmkks852BECAwEAAaNQME4wHQYDVR0O
BBYEFF9EtgfZZs8L2ZxBJxSiY6eTsTEwMB8GA1UdIwQYMBaAFF9EtgfZZs8L2ZxB
JxSiY6eTsTEwMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAc43YTfc6
baSemaMAc/jz8LNLhRE5dLfLOcRSoHda8y0lOrfe4lHT6yP5l8uyWAzLW+g6s3DA
Yme/bhX0g51BmI6gjKJo5DoPtiXk/Y9lxwD3p7PWi+RhN+AZQ5rpo8UfwnnN059n
yDuimQfvJjBFMVrdn9iP6SfMjxKaGk6gVmI=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB9jCCAV+gAwIBAgIJAMNZBmoIOXPBMA0GCSqGSIb3DQEBBQUAMBMxETAPBgNV
BAMMCENPTVAtMTMyMCAXDTEyMDUwMjEyMDQyNloYDzIxMTIwNDA4MTIwNDI2WjAT
MREwDwYDVQQDDAhDT01QLTEzMjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
6peZQt1sAmMAmSG9BVxxcXm8x15kE9iAplmANYNQ7z2YO57c10jDtlYlwVfi/rct
xNUOKQtc8UQtV/fJWP0QT0GITdRz5X/TkWiojiFgkopza9/b1hXs5rltYByUGLhg
7JZ9dZGBihzPfn6U8ESAKiJzQP8Hyz/o81FPfuHCftsCAwEAAaNQME4wHQYDVR0O
BBYEFNuxsc77Z6/JSKPoyloHNm9zF9yqMB8GA1UdIwQYMBaAFNuxsc77Z6/JSKPo
yloHNm9zF9yqMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAl4hBaJy1
cgiNV2+Z5oNTrHgmzWvSY4duECOTBxeuIOnhql3vLlaQmo0p8Z4c13kTZq2s3nhd
Loe5mIHsjRVKvzB6SvIaFUYq/EzmHnqNdpIGkT/Mj7r/iUs61btTcGUCLsUiUeci
Vd0Ozh79JSRpkrdI8R/NRQ2XPHAo+29TT70=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB9jCCAV+gAwIBAgIJAKRvzcy7OH0UMA0GCSqGSIb3DQEBBQUAMBMxETAPBgNV
BAMMCENPTVAtNzcyMCAXDTEyMDgxMDE1NDI1MVoYDzIxMTIwNzE3MTU0MjUxWjAT
MREwDwYDVQQDDAhDT01QLTc3MjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
o7aipd6MbnuGDeR1UJUjuMLQUariAyQ2l2ZDS6TfOwjHiPw/mhzkielgk73kqN7A
sUREx41eTcYCXzTq3WP3xCLE4LxLg1eIhd4nwNHj8H18xR9aP0AGjo4UFl5BOMa1
mwoyBt3VtfGtUmb8whpeJgHhqrPPxLoON+i6fIbXDaUCAwEAAaNQME4wHQYDVR0O
BBYEFEfjy3OopT2lOksKmKBNHTJE2hFlMB8GA1UdIwQYMBaAFEfjy3OopT2lOksK
mKBNHTJE2hFlMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAaNRx6YN2
M/p3R8/xS6zvH1EqJ3FFD7XeAQ52WuQnKSREzuw0dsw12ClxjcHiQEFioyTiTtjs
5pW18Ry5Ie7iFK4cQMerZwWPxBodEbAteYlRsI6kePV7Gf735Y1RpuN8qZ2sYL6e
x2IMeSwJ82BpdEI5niXxB+iT0HxhmR+XaMI=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB8jCCAVugAwIBAgIJANlTfgX/9cX7MA0GCSqGSIb3DQEBBQUAMBExDzANBgNV
BAMMBkNPTVAtMDAgFw0xMzA1MzAxMTUyMDhaGA8yMTEzMDUwNjExNTIwOFowETEP
MA0GA1UEAwwGQ09NUC0wMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDSGtkh
UPOcYMRiL2czmdfeHNB34nXEr5fMpglbA9RO9Cakf6YhK0jU5Y7kzAb6ZlyEzcC+
YkYWQZ9WCLwGuUvThg5iYlnBxmksv5Ot+5DKyTL4hdMEPCQ0RaLcXSkbxk56q3Rn
EQdYL+IJXS1KGMRWbl4Ql3NhShM9q7vBgyoMuwIDAQABo1AwTjAdBgNVHQ4EFgQU
EpO2oyW/sFAS9eojDbYo3hEOOIIwHwYDVR0jBBgwFoAUEpO2oyW/sFAS9eojDbYo
3hEOOIIwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQBP02wmekqmeD23
90NmwDwyEznDPEJDJybREtP+T++EJ1Q/rcnxIQ5a1iOEWY4RdH87H/+2O/7nDzGs
L0KzeG3WDdmnxLMQ5zpG9Qd5twC0GoMl1zf+8f9/t4QE7Dn4IosP3H3dkcRDQRch
SKYaJZHMckKx40/hhRsyFDR1Gj215g==
-----END CERTIFICATE-----
[versions]
Jinja2 = 2.7
MarkupSafe = 0.18
Werkzeug = 0.8.3
buildout-versions = 1.7
hexagonit.recipe.cmmi = 2.0
inotifyx = 0.2.0-1
lxml = 3.2.1
meld3 = 0.6.10
netaddr = 0.7.10
plone.recipe.command = 1.1
pytz = 2013b
slapos.core = 0.35.1
slapos.recipe.build = 0.11.6
slapos.recipe.cmmi = 0.1.1
slapos.recipe.download = 1.0.dev-r4053
slapos.recipe.template = 2.4.2
xml-marshaller = 0.9.7
slapos.cookbook=0.78.1
# Required by:
# slapos.core==0.35.1
Flask = 0.9
# Required by:
# slapos.cookbook==0.78.1
lock-file = 2.0
# Required by:
# slapos.core==0.35.1
netifaces = 0.8-1
# Required by:
# slapos.core==0.35.1
pyflakes = 0.7.2
# Required by:
# hexagonit.recipe.download==1.6nxd002
# slapos.cookbook==0.78.1
# slapos.core==0.35.1
# supervisor==3.0b1
# zc.buildout==1.6.0-dev-SlapOS-010
# zope.interface==4.0.5
setuptools = 0.6c12dev-r88846
# Required by:
# slapos.core==0.35.1
supervisor = 3.0b1
# Required by:
# slapos.core==0.35.1
unittest2 = 0.5.1
# Required by:
# slapos.core==0.35.1
zope.interface = 4.0.5
\ No newline at end of file
Universe = vanilla
Executable = simple
Arguments = 4 10
Log = simple.log
Output = simple.$(Process).out
Error = simple.$(Process).error
Queue
Arguments = 4 11
Queue
Arguments = 4 12
Queue
\ No newline at end of file
......@@ -18,8 +18,13 @@ offline = true
[instance-parameter]
# Fetches parameters defined in SlapOS Master for this instance.
# Always the same.
# Fetch arbitrary parameters defined by the user in SlapOS Master for his instance.
# We use the slapconfiguration recipe with a few parameters (partition id,
# computer id, certificate, etc).
# It will then authenticate to SlapOS Master and fetch the instance parameters.
# The parameters are accessible from $${instance-parameter:configuration.name-of-parameter}
# Always the same. Just copy/paste.
# See docstring of slapos.cookbook:slapconfiguration for more informations.
recipe = slapos.cookbook:slapconfiguration
computer = $${slap_connection:computer_id}
partition = $${slap_connection:partition_id}
......@@ -28,10 +33,13 @@ key = $${slap_connection:key_file}
cert = $${slap_connection:cert_file}
# Define default parameter(s) that will be used later, in case user didn't
# specify it
# All parameters are available through the configuration.XX syntax.
# specify it.
# All possible parameters should have a default.
configuration.name = anonymous
# In our use case, we are expecting from the user to specify one (optional) parameter: "name". We put the default value here if he doesn't specify it, so that it doesn't crash.
configuration.name = John Doe
# If our use case requires that the user can specify a mail address so that his instance can mail to him (for example), we can do:
# configuration.mail-address =
# If the user doesn't specify it, it won't break and the recipe can handle it (i.e don't send any mail for example).
# Create all needed directories, depending on your needs
......
......@@ -25,6 +25,6 @@ parts =
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/instance.cfg.in
output = ${buildout:directory}/instance.cfg
# MD5 checksum can be skipped for development, but must be filled for production
#md5sum =
# MD5 checksum can be skipped for development (easier to develop), but must be filled for production
md5sum = 1fc461c00e86485bee77a942f39e3c43
mode = 0644
[buildout]
eggs-directory = ${buildout:eggs-directory}
develop-eggs-directory = ${buildout:develop-eggs-directory}
offline = true
parts =
publish-connection-informations
redis
[rootdirectory]
recipe = slapos.cookbook:mkdirectory
etc = $${buildout:directory}/etc/
srv = $${buildout:directory}/srv/
var = $${buildout:directory}/var/
bin = $${buildout:directory}/bin/
[basedirectory]
recipe = slapos.cookbook:mkdirectory
scripts = $${rootdirectory:etc}/run/
services = $${rootdirectory:etc}/service/
promises = $${rootdirectory:etc}/promise/
run = $${rootdirectory:var}/run/
log = $${rootdirectory:var}/log/
[master-passwd]
recipe = slapos.cookbook:generate.password
storage-path = $${rootdirectory:etc}/.passwd
bytes = 4
[redis]
recipe = slapos.cookbook:redis.server
server_bin = ${redis:location}/bin/redis-server
ipv6 = $${slap-network-information:global-ipv6}
port = 6379
use_passwd = $${slap-parameter:use_passwd}
pid_file = $${basedirectory:run}/redis.pid
server_dir = $${rootdirectory:srv}
passwd = $${master-passwd:passwd}
config_file = $${rootdirectory:etc}/redis.conf
log_file = $${basedirectory:log}/redis.log
wrapper = $${basedirectory:services}/redis_server
promise_wrapper = $${basedirectory:promises}/redis
# Send informations to SlapOS Master
[publish-connection-informations]
recipe = slapos.cookbook:publish
redis_ip = $${redis:ipv6}
redis_port = $${redis:port}
redis_passwd = $${redis:passwd}
redis_uses_password = $${redis:use_passwd}
[slap-parameter]
use_passwd = false
\ No newline at end of file
[buildout]
eggs-directory = ${buildout:eggs-directory}
develop-eggs-directory = ${buildout:develop-eggs-directory}
offline = true
parts =
switch-softwaretype
[switch-softwaretype]
recipe = slapos.cookbook:softwaretype
default = ${template-redis:output}
\ No newline at end of file
[buildout]
parts =
slapos-cookbook
redis
template
template-redis
extends =
../../component/redis/buildout.cfg
../../component/git/buildout.cfg
../../stack/slapos.cfg
[template]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/instance.cfg
output = ${buildout:directory}/template.cfg
mode = 0644
md5sum = 5d2008c96a569c3ce498ddc0933afea3
[template-redis]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/instance-redis.cfg
output = ${buildout:directory}/template-redis.cfg
mode = 0644
md5sum = f7b01ca7698c1b771f0653d64dc945a7
[networkcache]
# signature certificates of the following uploaders.
# Romain Courteaud
# Sebastien Robin
# Kazuhiko Shiozaki
# Cedric de Saint Martin
# Yingjie Xu
# Gabriel Monnerat
# Łukasz Nowak
# Test Agent (Automatic update from tests)
# Alain Takoudjou
signature-certificate-list =
-----BEGIN CERTIFICATE-----
MIIB4DCCAUkCADANBgkqhkiG9w0BAQsFADA5MQswCQYDVQQGEwJGUjEZMBcGA1UE
CBMQRGVmYXVsdCBQcm92aW5jZTEPMA0GA1UEChMGTmV4ZWRpMB4XDTExMDkxNTA5
MDAwMloXDTEyMDkxNTA5MDAwMlowOTELMAkGA1UEBhMCRlIxGTAXBgNVBAgTEERl
ZmF1bHQgUHJvdmluY2UxDzANBgNVBAoTBk5leGVkaTCBnzANBgkqhkiG9w0BAQEF
AAOBjQAwgYkCgYEApYZv6OstoqNzxG1KI6iE5U4Ts2Xx9lgLeUGAMyfJLyMmRLhw
boKOyJ9Xke4dncoBAyNPokUR6iWOcnPHtMvNOsBFZ2f7VA28em3+E1JRYdeNUEtX
Z0s3HjcouaNAnPfjFTXHYj4um1wOw2cURSPuU5dpzKBbV+/QCb5DLheynisCAwEA
ATANBgkqhkiG9w0BAQsFAAOBgQBCZLbTVdrw3RZlVVMFezSHrhBYKAukTwZrNmJX
mHqi2tN8tNo6FX+wmxUUAf3e8R2Ymbdbn2bfbPpcKQ2fG7PuKGvhwMG3BlF9paEC
q7jdfWO18Zp/BG7tagz0jmmC4y/8akzHsVlruo2+2du2freE8dK746uoMlXlP93g
QUUGLQ==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB8jCCAVugAwIBAgIJAPu2zchZ2BxoMA0GCSqGSIb3DQEBBQUAMBIxEDAOBgNV
BAMMB3RzeGRldjMwHhcNMTExMDE0MTIxNjIzWhcNMTIxMDEzMTIxNjIzWjASMRAw
DgYDVQQDDAd0c3hkZXYzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrPbh+
YGmo6mWmhVb1vTqX0BbeU0jCTB8TK3i6ep3tzSw2rkUGSx3niXn9LNTFNcIn3MZN
XHqbb4AS2Zxyk/2tr3939qqOrS4YRCtXBwTCuFY6r+a7pZsjiTNddPsEhuj4lEnR
L8Ax5mmzoi9nE+hiPSwqjRwWRU1+182rzXmN4QIDAQABo1AwTjAdBgNVHQ4EFgQU
/4XXREzqBbBNJvX5gU8tLWxZaeQwHwYDVR0jBBgwFoAU/4XXREzqBbBNJvX5gU8t
LWxZaeQwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQA07q/rKoE7fAda
FED57/SR00OvY9wLlFEF2QJ5OLu+O33YUXDDbGpfUSF9R8l0g9dix1JbWK9nQ6Yd
R/KCo6D0sw0ZgeQv1aUXbl/xJ9k4jlTxmWbPeiiPZEqU1W9wN5lkGuLxV4CEGTKU
hJA/yXa1wbwIPGvX3tVKdOEWPRXZLg==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB7jCCAVegAwIBAgIJAJWA0jQ4o9DGMA0GCSqGSIb3DQEBBQUAMA8xDTALBgNV
BAMMBHg2MXMwIBcNMTExMTI0MTAyNDQzWhgPMjExMTEwMzExMDI0NDNaMA8xDTAL
BgNVBAMMBHg2MXMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANdJNiFsRlkH
vq2kHP2zdxEyzPAWZH3CQ3Myb3F8hERXTIFSUqntPXDKXDb7Y/laqjMXdj+vptKk
3Q36J+8VnJbSwjGwmEG6tym9qMSGIPPNw1JXY1R29eF3o4aj21o7DHAkhuNc5Tso
67fUSKgvyVnyH4G6ShQUAtghPaAwS0KvAgMBAAGjUDBOMB0GA1UdDgQWBBSjxFUE
RfnTvABRLAa34Ytkhz5vPzAfBgNVHSMEGDAWgBSjxFUERfnTvABRLAa34Ytkhz5v
PzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAFLDS7zNhlrQYSQO5KIj
z2RJe3fj4rLPklo3TmP5KLvendG+LErE2cbKPqnhQ2oVoj6u9tWVwo/g03PMrrnL
KrDm39slYD/1KoE5kB4l/p6KVOdeJ4I6xcgu9rnkqqHzDwI4v7e8/D3WZbpiFUsY
vaZhjNYKWQf79l6zXfOvphzJ
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB9jCCAV+gAwIBAgIJAO4V/jiMoICoMA0GCSqGSIb3DQEBBQUAMBMxETAPBgNV
BAMMCENPTVAtMjMyMCAXDTEyMDIxNjExMTAyM1oYDzIxMTIwMTIzMTExMDIzWjAT
MREwDwYDVQQDDAhDT01QLTIzMjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
wi/3Z8W9pUiegUXIk/AiFDQ0UJ4JFAwjqr+HSRUirlUsHHT+8DzH/hfcTDX1I5BB
D1ADk+ydXjMm3OZrQcXjn29OUfM5C+g+oqeMnYQImN0DDQIOcUyr7AJc4xhvuXQ1
P2pJ5NOd3tbd0kexETa1LVhR6EgBC25LyRBRae76qosCAwEAAaNQME4wHQYDVR0O
BBYEFMDmW9aFy1sKTfCpcRkYnP6zUd1cMB8GA1UdIwQYMBaAFMDmW9aFy1sKTfCp
cRkYnP6zUd1cMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAskbFizHr
b6d3iIyN+wffxz/V9epbKIZVEGJd/6LrTdLiUfJPec7FaxVCWNyKBlCpINBM7cEV
Gn9t8mdVQflNqOlAMkOlUv1ZugCt9rXYQOV7rrEYJBWirn43BOMn9Flp2nibblby
If1a2ZoqHRxoNo2yTmm7TSYRORWVS+vvfjY=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB9jCCAV+gAwIBAgIJAIlBksrZVkK8MA0GCSqGSIb3DQEBBQUAMBMxETAPBgNV
BAMMCENPTVAtMzU3MCAXDTEyMDEyNjEwNTUyOFoYDzIxMTIwMTAyMTA1NTI4WjAT
MREwDwYDVQQDDAhDT01QLTM1NzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
ts+iGUwi44vtIfwXR8DCnLtHV4ydl0YTK2joJflj0/Ws7mz5BYkxIU4fea/6+VF3
i11nwBgYgxQyjNztgc9u9O71k1W5tU95yO7U7bFdYd5uxYA9/22fjObaTQoC4Nc9
mTu6r/VHyJ1yRsunBZXvnk/XaKp7gGE9vNEyJvPn2bkCAwEAAaNQME4wHQYDVR0O
BBYEFKuGIYu8+6aEkTVg62BRYaD11PILMB8GA1UdIwQYMBaAFKuGIYu8+6aEkTVg
62BRYaD11PILMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAMoTRpBxK
YLEZJbofF7gSrRIcrlUJYXfTfw1QUBOKkGFFDsiJpEg4y5pUk1s5Jq9K3SDzNq/W
it1oYjOhuGg3al8OOeKFrU6nvNTF1BAvJCl0tr3POai5yXyN5jlK/zPfypmQYxE+
TaqQSGBJPVXYt6lrq/PRD9ciZgKLOwEqK8w=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB9jCCAV+gAwIBAgIJAPHoWu90gbsgMA0GCSqGSIb3DQEBBQUAMBQxEjAQBgNV
BAMMCXZpZmlibm9kZTAeFw0xMjAzMTkyMzIwNTVaFw0xMzAzMTkyMzIwNTVaMBQx
EjAQBgNVBAMMCXZpZmlibm9kZTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
ozBijpO8PS5RTeKTzA90vi9ezvv4vVjNaguqT4UwP9+O1+i6yq1Y2W5zZxw/Klbn
oudyNzie3/wqs9VfPmcyU9ajFzBv/Tobm3obmOqBN0GSYs5fyGw+O9G3//6ZEhf0
NinwdKmrRX+d0P5bHewadZWIvlmOupcnVJmkks852BECAwEAAaNQME4wHQYDVR0O
BBYEFF9EtgfZZs8L2ZxBJxSiY6eTsTEwMB8GA1UdIwQYMBaAFF9EtgfZZs8L2ZxB
JxSiY6eTsTEwMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAc43YTfc6
baSemaMAc/jz8LNLhRE5dLfLOcRSoHda8y0lOrfe4lHT6yP5l8uyWAzLW+g6s3DA
Yme/bhX0g51BmI6gjKJo5DoPtiXk/Y9lxwD3p7PWi+RhN+AZQ5rpo8UfwnnN059n
yDuimQfvJjBFMVrdn9iP6SfMjxKaGk6gVmI=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB9jCCAV+gAwIBAgIJAMNZBmoIOXPBMA0GCSqGSIb3DQEBBQUAMBMxETAPBgNV
BAMMCENPTVAtMTMyMCAXDTEyMDUwMjEyMDQyNloYDzIxMTIwNDA4MTIwNDI2WjAT
MREwDwYDVQQDDAhDT01QLTEzMjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
6peZQt1sAmMAmSG9BVxxcXm8x15kE9iAplmANYNQ7z2YO57c10jDtlYlwVfi/rct
xNUOKQtc8UQtV/fJWP0QT0GITdRz5X/TkWiojiFgkopza9/b1hXs5rltYByUGLhg
7JZ9dZGBihzPfn6U8ESAKiJzQP8Hyz/o81FPfuHCftsCAwEAAaNQME4wHQYDVR0O
BBYEFNuxsc77Z6/JSKPoyloHNm9zF9yqMB8GA1UdIwQYMBaAFNuxsc77Z6/JSKPo
yloHNm9zF9yqMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAl4hBaJy1
cgiNV2+Z5oNTrHgmzWvSY4duECOTBxeuIOnhql3vLlaQmo0p8Z4c13kTZq2s3nhd
Loe5mIHsjRVKvzB6SvIaFUYq/EzmHnqNdpIGkT/Mj7r/iUs61btTcGUCLsUiUeci
Vd0Ozh79JSRpkrdI8R/NRQ2XPHAo+29TT70=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB9jCCAV+gAwIBAgIJAKRvzcy7OH0UMA0GCSqGSIb3DQEBBQUAMBMxETAPBgNV
BAMMCENPTVAtNzcyMCAXDTEyMDgxMDE1NDI1MVoYDzIxMTIwNzE3MTU0MjUxWjAT
MREwDwYDVQQDDAhDT01QLTc3MjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
o7aipd6MbnuGDeR1UJUjuMLQUariAyQ2l2ZDS6TfOwjHiPw/mhzkielgk73kqN7A
sUREx41eTcYCXzTq3WP3xCLE4LxLg1eIhd4nwNHj8H18xR9aP0AGjo4UFl5BOMa1
mwoyBt3VtfGtUmb8whpeJgHhqrPPxLoON+i6fIbXDaUCAwEAAaNQME4wHQYDVR0O
BBYEFEfjy3OopT2lOksKmKBNHTJE2hFlMB8GA1UdIwQYMBaAFEfjy3OopT2lOksK
mKBNHTJE2hFlMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAaNRx6YN2
M/p3R8/xS6zvH1EqJ3FFD7XeAQ52WuQnKSREzuw0dsw12ClxjcHiQEFioyTiTtjs
5pW18Ry5Ie7iFK4cQMerZwWPxBodEbAteYlRsI6kePV7Gf735Y1RpuN8qZ2sYL6e
x2IMeSwJ82BpdEI5niXxB+iT0HxhmR+XaMI=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB8jCCAVugAwIBAgIJANlTfgX/9cX7MA0GCSqGSIb3DQEBBQUAMBExDzANBgNV
BAMMBkNPTVAtMDAgFw0xMzA1MzAxMTUyMDhaGA8yMTEzMDUwNjExNTIwOFowETEP
MA0GA1UEAwwGQ09NUC0wMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDSGtkh
UPOcYMRiL2czmdfeHNB34nXEr5fMpglbA9RO9Cakf6YhK0jU5Y7kzAb6ZlyEzcC+
YkYWQZ9WCLwGuUvThg5iYlnBxmksv5Ot+5DKyTL4hdMEPCQ0RaLcXSkbxk56q3Rn
EQdYL+IJXS1KGMRWbl4Ql3NhShM9q7vBgyoMuwIDAQABo1AwTjAdBgNVHQ4EFgQU
EpO2oyW/sFAS9eojDbYo3hEOOIIwHwYDVR0jBBgwFoAUEpO2oyW/sFAS9eojDbYo
3hEOOIIwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQBP02wmekqmeD23
90NmwDwyEznDPEJDJybREtP+T++EJ1Q/rcnxIQ5a1iOEWY4RdH87H/+2O/7nDzGs
L0KzeG3WDdmnxLMQ5zpG9Qd5twC0GoMl1zf+8f9/t4QE7Dn4IosP3H3dkcRDQRch
SKYaJZHMckKx40/hhRsyFDR1Gj215g==
-----END CERTIFICATE-----
[versions]
slapos.cookbook=0.78.1
Jinja2 = 2.7
MarkupSafe = 0.18
Werkzeug = 0.8.3
buildout-versions = 1.7
hexagonit.recipe.cmmi = 2.0
inotifyx = 0.2.0-1
lxml = 3.2.1
meld3 = 0.6.10
netaddr = 0.7.10
plone.recipe.command = 1.1
pytz = 2013b
slapos.core = 0.35.1
slapos.recipe.cmmi = 0.1.1
slapos.recipe.template = 2.4.2
xml-marshaller = 0.9.7
# Required by:
# slapos.core==0.35.1
Flask = 0.9
# Required by:
# slapos.cookbook==0.78.1
lock-file = 2.0
# Required by:
# slapos.core==0.35.1
netifaces = 0.8-1
# Required by:
# slapos.core==0.35.1
pyflakes = 0.7.2
# Required by:
# hexagonit.recipe.download==1.6nxd002
# slapos.cookbook==0.78.1
# slapos.core==0.35.1
# supervisor==3.0b2
# zc.buildout==1.6.0-dev-SlapOS-010
# zope.interface==4.0.5
setuptools = 0.6c12dev-r88846
# Required by:
# slapos.core==0.35.1
supervisor = 3.0b2
# Required by:
# slapos.core==0.35.1
unittest2 = 0.5.1
# Required by:
# slapos.core==0.35.1
zope.interface = 4.0.5
slaprunner
==========
Introduction
------------
This software release is used to deploy Slaprunner instances.
Slaprunner is an all-in-one IDE used to develop and test profiles and recipes for SlapOS.
Parameters
----------
authorized-key
~~~~~~~~~~~~~~
You need to specify your SSH public key in order to connect to the SSH server of this instance.
Example of parameter XML::
<?xml version="1.0" encoding="utf-8"?>
<instance>
<parameter id="authorized-key">ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCdNp7qZMVAzNc07opHshiIFDmJpYXQpetfcSgUj39a409d42PpsJElp7WsAE/x0nN6gUIoWIl7UiAlMzf6bKEJGJVSOZEPTmiJVlgK1Gp+kE0x9yNcncYg7p38Jny0daVA/NkkpAFyRsAm5kLGzyLtaCcktSvy0cJuy7WSSHU05pd1f8Y8thofE9g5t+/JA2VZvipxPkRfkFAG3aOAGLULlTImTSDFSDFGSDFG5F6mMnl7yvY2d6vEHVBu+K+aKmAwZVfCUwtSpa/tq3i2Lppjrw3UfrxbQSFHZCkzefr+u+l4YYe+tJrX7rYJYXD7LIfZfdSeFTlHFaN/yI1 user@host.local</parameter>
</instance>
instance-amount
~~~~~~~~~~~~~~~
Optional parameter.
Default: 10
[buildout]
extends =
../../component/dash/buildout.cfg
../../component/dropbear/buildout.cfg
../../component/git/buildout.cfg
../../component/lxml-python/buildout.cfg
../../stack/flask.cfg
../../stack/shacache-client.cfg
../../stack/slapos.cfg
parts =
template
slapos-cookbook
eggs
[template]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/instance.cfg
output = ${buildout:directory}/template.cfg
mode = 0644
md5sum = 5307e4200f044ae57b504ad68444491c
[template-runner]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/instance-runner.cfg
output = ${buildout:directory}/template-runner.cfg
md5sum = 4861be4a581686feef9f9edea865d7ee
mode = 0644
[eggs]
recipe = z3c.recipe.scripts
eggs =
${lxml-python:egg}
slapos.libnetworkcache
slapos.toolbox[flask_auth]
slapos.core
cns.recipe.symlink
# Development profile of slaprunner.
# Exactly the same as software.cfg, but fetch the slapos.cookbook and
# slapos.toolbox from git repository instead of fetching stable version,
# allowing to play with bleeding edge environment.
# You'll need to run buildout twice for this profile.
[buildout]
extends = common.cfg
parts +=
slapos.cookbook-repository
slapos.core-repository
slapos.toolbox-repository
check-recipe
develop =
${:parts-directory}/slapos.cookbook-repository
${:parts-directory}/slapos.core-repository
${:parts-directory}/slapos.toolbox-repository
[slapos.toolbox-repository]
recipe = slapos.recipe.build:gitclone
repository = http://git.erp5.org/repos/slapos.toolbox.git
branch = slaprunner
git-executable = ${git:location}/bin/git
[slapos.cookbook-repository]
recipe = slapos.recipe.build:gitclone
repository = http://git.erp5.org/repos/slapos.git
branch = slaprunner
git-executable = ${git:location}/bin/git
[slapos.core-repository]
recipe = slapos.recipe.build:gitclone
repository = http://git.erp5.org/repos/slapos.core.git
branch = master
git-executable = ${git:location}/bin/git
[check-recipe]
recipe = plone.recipe.command
stop-on-error = true
update-command = ${:command}
command =
grep parts ${buildout:develop-eggs-directory}/slapos.cookbook.egg-link &&
grep parts ${buildout:develop-eggs-directory}/slapos.core.egg-link &&
grep parts ${buildout:develop-eggs-directory}/slapos.toolbox.egg-link
[buildout]
parts =
slaprunner
test-runner
sshkeys-dropbear
dropbear-server-add-authorized-key
sshkeys-authority
publish-connection-informations
slaprunner-promise
slaprunner-frontend-promise
dropbear-promise
symlinks
eggs-directory = ${buildout:eggs-directory}
develop-eggs-directory = ${buildout:develop-eggs-directory}
offline = true
# Create all needed directories
[directory]
recipe = slapos.cookbook:mkdirectory
etc = $${buildout:directory}/etc/
var = $${buildout:directory}/var/
srv = $${buildout:directory}/srv/
bin = $${buildout:directory}/bin/
sshkeys = $${:srv}/sshkeys
services = $${:etc}/service/
scripts = $${:etc}/run/
ssh = $${:etc}/ssh/
log = $${:var}/log/
run = $${:var}/run/
backup = $${:srv}/backup/
promises = $${:etc}/promise/
test = $${:etc}/test/
[runnerdirectory]
recipe = slapos.cookbook:mkdirectory
home = $${directory:srv}/runner/
test = $${directory:srv}/test/
project = $${:home}/project
software-root = $${:home}/software
instance-root = $${:home}/instance
project-test = $${:test}/project
software-test = $${:test}/software
instance-test = $${:test}/instance
sessions = $${buildout:directory}/.sessions
#Create password recovery code for slaprunner
[recovery-code]
recipe = slapos.cookbook:generate.password
storage-path = $${directory:etc}/.rcode
bytes = 4
[slaprunner]
recipe = slapos.cookbook:slaprunner
slaprunner = ${buildout:directory}/bin/slaprunner
slapgrid_sr = ${buildout:directory}/bin/slapgrid-sr
slapgrid_cp = ${buildout:directory}/bin/slapgrid-cp
slapproxy = ${buildout:directory}/bin/slapproxy
supervisor = ${buildout:directory}/bin/slapgrid-supervisorctl
git-binary = ${git:location}/bin/git
slapos.cfg = $${directory:etc}/slapos.cfg
working-directory = $${runnerdirectory:home}
project-directory = $${runnerdirectory:project}
software-directory = $${runnerdirectory:software-root}
instance-directory = $${runnerdirectory:instance-root}
etc_dir = $${directory:etc}
log_dir = $${directory:log}
run_dir = $${directory:run}
ssh_client = $${sshkeys-dropbear:wrapper}
public_key = $${sshkeys-dropbear:public-key}
private_key = $${sshkeys-dropbear:private-key}
ipv4 = $${slap-network-information:local-ipv4}
ipv6 = $${slap-network-information:global-ipv6}
proxy_port = 50000
runner_port = 50000
partition-amount = $${slap-parameter:instance-amount}
wrapper = $${directory:services}/slaprunner
debug = $${slap-parameter:debug}
# Backward compatiblity
cloud9-url =
[test-runner]
<= slaprunner
recipe = slapos.cookbook:slaprunner.test
slaprunnertest = ${buildout:directory}/bin/slaprunnertest
slapos.cfg = $${directory:etc}/slapos-test.cfg
working-directory = $${runnerdirectory:test}
project-directory = $${runnerdirectory:project-test}
software-directory = $${runnerdirectory:software-test}
instance-directory = $${runnerdirectory:instance-test}
proxy_port = 8602
wrapper = $${directory:bin}/runTestSuite
etc_dir = $${directory:test}
# Deploy dropbear (minimalist SSH server)
[sshkeys-directory]
recipe = slapos.cookbook:mkdirectory
requests = $${directory:sshkeys}/requests/
keys = $${directory:sshkeys}/keys/
[sshkeys-authority]
recipe = slapos.cookbook:sshkeys_authority
request-directory = $${sshkeys-directory:requests}
keys-directory = $${sshkeys-directory:keys}
wrapper = $${directory:services}/sshkeys_authority
keygen-binary = ${dropbear:location}/bin/dropbearkey
[dropbear-server]
recipe = slapos.cookbook:dropbear
host = $${slap-network-information:global-ipv6}
port = 2222
home = $${directory:ssh}
wrapper = $${directory:bin}/raw_sshd
shell = /bin/bash
rsa-keyfile = $${directory:ssh}/server_key.rsa
dropbear-binary = ${dropbear:location}/sbin/dropbear
[sshkeys-dropbear]
<= sshkeys-authority
recipe = slapos.cookbook:sshkeys_authority.request
name = dropbear
type = rsa
executable = $${dropbear-server:wrapper}
public-key = $${dropbear-server:rsa-keyfile}.pub
private-key = $${dropbear-server:rsa-keyfile}
wrapper = $${directory:services}/sshd
[dropbear-server-add-authorized-key]
<= dropbear-server
recipe = slapos.cookbook:dropbear.add_authorized_key
key = $${slap-parameter:authorized-key}
# Request frontend
[request-frontend]
<= slap-connection
recipe = slapos.cookbook:requestoptional
name = Frontend
# XXX We have hardcoded SR URL here.
software-url = http://git.erp5.org/gitweb/slapos.git/blob_plain/HEAD:/software/apache-frontend/software.cfg
slave = true
config = url
config-url = $${slaprunner:access-url}
return = site_url
# Send informations to SlapOS Master
[publish-connection-informations]
recipe = slapos.cookbook:publish
backend_url = $${slaprunner:access-url}
url = $${request-frontend:connection-site_url}
ssh_command = ssh $${dropbear-server:host} -p $${dropbear-server:port}
password_recovery_code = $${recovery-code:passwd}
# Deploy promises scripts
[slaprunner-promise]
recipe = slapos.cookbook:check_port_listening
path = $${directory:promises}/slaprunner
hostname = $${slaprunner:ipv6}
port = $${slaprunner:runner_port}
[slaprunner-frontend-promise]
recipe = slapos.cookbook:check_url_available
path = $${directory:promises}/slaprunner_frontend
url = $${request-frontend:connection-site_url}
dash_path = ${dash:location}/bin/dash
curl_path = ${curl:location}/bin/curl
[dropbear-promise]
recipe = slapos.cookbook:check_port_listening
path = $${directory:promises}/dropbear
hostname = $${dropbear-server:host}
port = $${dropbear-server:port}
[symlinks]
recipe = cns.recipe.symlink
symlink_target = $${directory:bin}
symlink_base = ${buildout:directory}/bin
[slap-parameter]
# Default value if no ssh key is specified
authorized-key =
# Default value of instances number in slaprunner
instance-amount = 10
debug = false
[buildout]
parts =
switch_softwaretype
eggs-directory = ${buildout:eggs-directory}
develop-eggs-directory = ${buildout:develop-eggs-directory}
offline = true
[switch_softwaretype]
recipe = slapos.cookbook:softwaretype
default = ${template-runner:output}
\ No newline at end of file
# Production profile of slaprunner.
# Exactly the same as common.cfg, but:
# 1/ Use a defined set of Python eggs instead of using the latest available
# ones from Pypi, to ensure stability;
# 2/ Define list of trusted certificates for the cache.
[buildout]
extends = common.cfg
[networkcache]
# signature certificates of the following uploaders.
# Cedric de Saint Martin
# Test Agent
signature-certificate-list =
-----BEGIN CERTIFICATE-----
MIIB9jCCAV+gAwIBAgIJAO4V/jiMoICoMA0GCSqGSIb3DQEBBQUAMBMxETAPBgNV
BAMMCENPTVAtMjMyMCAXDTEyMDIxNjExMTAyM1oYDzIxMTIwMTIzMTExMDIzWjAT
MREwDwYDVQQDDAhDT01QLTIzMjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
wi/3Z8W9pUiegUXIk/AiFDQ0UJ4JFAwjqr+HSRUirlUsHHT+8DzH/hfcTDX1I5BB
D1ADk+ydXjMm3OZrQcXjn29OUfM5C+g+oqeMnYQImN0DDQIOcUyr7AJc4xhvuXQ1
P2pJ5NOd3tbd0kexETa1LVhR6EgBC25LyRBRae76qosCAwEAAaNQME4wHQYDVR0O
BBYEFMDmW9aFy1sKTfCpcRkYnP6zUd1cMB8GA1UdIwQYMBaAFMDmW9aFy1sKTfCp
cRkYnP6zUd1cMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAskbFizHr
b6d3iIyN+wffxz/V9epbKIZVEGJd/6LrTdLiUfJPec7FaxVCWNyKBlCpINBM7cEV
Gn9t8mdVQflNqOlAMkOlUv1ZugCt9rXYQOV7rrEYJBWirn43BOMn9Flp2nibblby
If1a2ZoqHRxoNo2yTmm7TSYRORWVS+vvfjY=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB9jCCAV+gAwIBAgIJAKRvzcy7OH0UMA0GCSqGSIb3DQEBBQUAMBMxETAPBgNV
BAMMCENPTVAtNzcyMCAXDTEyMDgxMDE1NDI1MVoYDzIxMTIwNzE3MTU0MjUxWjAT
MREwDwYDVQQDDAhDT01QLTc3MjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
o7aipd6MbnuGDeR1UJUjuMLQUariAyQ2l2ZDS6TfOwjHiPw/mhzkielgk73kqN7A
sUREx41eTcYCXzTq3WP3xCLE4LxLg1eIhd4nwNHj8H18xR9aP0AGjo4UFl5BOMa1
mwoyBt3VtfGtUmb8whpeJgHhqrPPxLoON+i6fIbXDaUCAwEAAaNQME4wHQYDVR0O
BBYEFEfjy3OopT2lOksKmKBNHTJE2hFlMB8GA1UdIwQYMBaAFEfjy3OopT2lOksK
mKBNHTJE2hFlMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAaNRx6YN2
M/p3R8/xS6zvH1EqJ3FFD7XeAQ52WuQnKSREzuw0dsw12ClxjcHiQEFioyTiTtjs
5pW18Ry5Ie7iFK4cQMerZwWPxBodEbAteYlRsI6kePV7Gf735Y1RpuN8qZ2sYL6e
x2IMeSwJ82BpdEI5niXxB+iT0HxhmR+XaMI=
-----END CERTIFICATE-----
[versions]
Flask-Auth = 0.85
Jinja2 = 2.6
Werkzeug = 0.8.3
apache-libcloud = 0.11.4
async = 0.6.1
buildout-versions = 1.7
cns.recipe.symlink = 0.2.3
gitdb = 0.5.4
slapos.recipe.cmmi = 0.1.1
inotifyx = 0.2.0
lxml = 3.0.1
meld3 = 0.6.10
netaddr = 0.7.10
plone.recipe.command = 1.1
pycrypto = 2.6
pytz = 2012j
slapos.cookbook = 0.71.1
slapos.core = 0.34
slapos.libnetworkcache = 0.13.3
slapos.recipe.build = 0.11.5
slapos.recipe.template = 2.4.2
slapos.toolbox = 0.34.0
smmap = 0.8.2
xml-marshaller = 0.9.7
z3c.recipe.scripts = 1.0.1
# Required by:
# slapos.core==0.34
# slapos.toolbox==0.34.0
Flask = 0.9
# Required by:
# slapos.toolbox==0.34.0
GitPython = 0.3.2.RC1
# Required by:
# slapos.toolbox==0.34.0
atomize = 0.1.1
# Required by:
# slapos.toolbox==0.34.0
feedparser = 5.1.3
# Required by:
# slapos.recipe.cmmi==0.1.1
hexagonit.recipe.download = 1.6nxd002
# Required by:
# slapos.core==0.34
netifaces = 0.8
# Required by:
# slapos.toolbox==0.34.0
paramiko = 1.9.0
# Required by:
# slapos.toolbox==0.34.0
psutil = 0.6.1
# Required by:
# slapos.core==0.34
pyflakes = 0.5.0
# Required by:
# cns.recipe.symlink==0.2.3
# slapos.cookbook==0.71.1
# slapos.core==0.34
# slapos.libnetworkcache==0.13.3
# slapos.toolbox==0.34.0
# supervisor==3.0b1
# zc.buildout==1.6.0-dev-SlapOS-010
# zope.interface==4.0.3
setuptools = 0.6c12dev-r88846
# Required by:
# slapos.core==0.34
supervisor = 3.0b1
# Required by:
# slapos.core==0.34
unittest2 = 0.5.1
# Required by:
# slapos.core==0.34
zope.interface = 4.0.3
[buildout]
parts =
urls
mariadb
stunnel
certificate-authority
ca-stunnel
logrotate
logrotate-entry-mariadb
logrotate-entry-stunnel
logrotate-entry-cron
cron
cron-entry-logrotate
slapmonitor
slapreport
gzip-binary = ${gzip:location}/bin/gzip
eggs-directory = ${buildout:eggs-directory}
develop-eggs-directory = ${buildout:develop-eggs-directory}
offline = true
[rootdirectory]
recipe = slapos.cookbook:mkdirectory
etc = $${buildout:directory}/etc/
var = $${buildout:directory}/var/
srv = $${buildout:directory}/srv/
bin = $${buildout:directory}/bin/
[basedirectory]
recipe = slapos.cookbook:mkdirectory
log = $${rootdirectory:var}/log/
scripts = $${rootdirectory:etc}/run/
services = $${rootdirectory:etc}/service/
run = $${rootdirectory:var}/run/
backup = $${rootdirectory:srv}/backup/
promises = $${rootdirectory:etc}/promise/
[directory]
recipe = slapos.cookbook:mkdirectory
cron-entries = $${rootdirectory:etc}/cron.d/
crontabs = $${rootdirectory:etc}/crontabs/
cronstamps = $${rootdirectory:etc}/cronstamps/
ca-dir = $${rootdirectory:srv}/ssl/
mariadb-data = $${rootdirectory:srv}/mariadb/
logrotate-backup = $${basedirectory:backup}/logrotate/
stunnel-conf = $${rootdirectory:etc}/stunnel/
logrotate-entries = $${rootdirectory:etc}/logrotate.d/
[urls]
recipe = slapos.cookbook:publish
url = mysqls://$${mariadb:user}:$${mariadb:password}@[$${stunnel:remote-host}]:$${stunnel:remote-port}/$${mariadb:database}
[mariadb]
recipe = slapos.cookbook:mysql
# Options
recovering = false
user = trac
port = 3306
password = $${mysql-password:passwd}
ip = $${slap-network-information:local-ipv4}
database = trac
# Paths
wrapper = $${basedirectory:services}/mariadb
update-wrapper = $${basedirectory:scripts}/mariadb_update
logrotate-post = $${rootdirectory:bin}/mariadb_post_logrotate
data-directory = $${directory:mariadb-data}
pid-file = $${basedirectory:run}/mariadb.pid
socket = $${basedirectory:run}/mariadb.sock
error-log = $${basedirectory:log}/mariadb_error.log
conf-file = $${rootdirectory:etc}/mariadb.cnf
promise = $${basedirectory:promises}/mysql
# Binary information
mysql-base-directory = ${mariadb:location}
mysql-binary = ${mariadb:location}/bin/mysql
mysql-install-binary = ${mariadb:location}/scripts/mysql_install_db
mysql-upgrade-binary = ${mariadb:location}/bin/mysql_upgrade
mysqld-binary = ${mariadb:location}/bin/mysqld
[mysql-password]
recipe = slapos.cookbook:generate.password
storage-path = $${rootdirectory:etc}/.passwd
bytes = 4
[slapmonitor]
recipe = slapos.cookbook:slapmonitor
pid-file = $${basedirectory:run}/mariadb.pid
database-path = $${basedirectory:log}/slapmonitor.db
shell-path = ${dash:location}/bin/dash
slapmonitor-path = ${buildout:bin-directory}/slapmonitor
path = $${basedirectory:scripts}/slapmonitor
[slapreport]
recipe = slapos.cookbook:slapreport
pid-file = $${basedirectory:run}/mariadb.pid
consumption-log-path = $${basedirectory:log}/instance_consumption.log
database-path = $${basedirectory:log}/slapmonitor.db
logbox-ip = 87.98.152.12
logbox-port = 5122
logbox-user = admin
logbox-passwd = passer
shell-path = ${dash:location}/bin/dash
slapreport-path = ${buildout:bin-directory}/slapreport
path = $${basedirectory:scripts}/slapreport
[certificate-authority]
recipe = slapos.cookbook:certificate_authority
openssl-binary = ${openssl:location}/bin/openssl
ca-dir = $${directory:ca-dir}
requests-directory = $${cadirectory:requests}
wrapper = $${basedirectory:services}/ca
ca-private = $${cadirectory:private}
ca-certs = $${cadirectory:certs}
ca-newcerts = $${cadirectory:newcerts}
ca-crl = $${cadirectory:crl}
[cadirectory]
recipe = slapos.cookbook:mkdirectory
requests = $${directory:ca-dir}/requests/
private = $${directory:ca-dir}/private/
certs = $${directory:ca-dir}/certs/
newcerts = $${directory:ca-dir}/newcerts/
crl = $${directory:ca-dir}/crl/
[ca-stunnel]
<= certificate-authority
recipe = slapos.cookbook:certificate_authority.request
executable = $${stunnel:wrapper}
wrapper = $${basedirectory:services}/stunnel
key-file = $${stunnel:key-file}
cert-file = $${stunnel:cert-file}
[stunnel]
recipe = slapos.cookbook:stunnel
stunnel-binary = ${stunnel:location}/bin/stunnel
wrapper = $${rootdirectory:bin}/stunnel
log-file = $${basedirectory:log}/stunnel.log
config-file = $${directory:stunnel-conf}/stunnel.conf
key-file = $${directory:stunnel-conf}/stunnel.key
cert-file = $${directory:stunnel-conf}/stunnel.crt
pid-file = $${basedirectory:run}/stunnel.pid
local-host = $${mariadb:ip}
local-port = $${mariadb:port}
remote-host = $${slap-network-information:global-ipv6}
remote-port = 6446
client = false
post-rotate-script = $${rootdirectory:bin}/stunnel_post_rotate
[logrotate]
recipe = slapos.cookbook:logrotate
# Binaries
logrotate-binary = ${logrotate:location}/usr/sbin/logrotate
gzip-binary = $${buildout:gzip-binary}
gunzip-binary = ${gzip:location}/bin/gunzip
# Directories
wrapper = $${rootdirectory:bin}/logrotate
conf = $${rootdirectory:etc}/logrotate.conf
logrotate-entries = $${directory:logrotate-entries}
backup = $${directory:logrotate-backup}
state-file = $${rootdirectory:srv}/logrotate.status
[logrotate-entry-mariadb]
<= logrotate
recipe = slapos.cookbook:logrotate.d
name = mariadb
log = $${mariadb:error-log}
frequency = daily
rotate-num = 30
post = $${mariadb:logrotate-post}
sharedscripts = true
notifempty = true
create = true
[logrotate-entry-stunnel]
<= logrotate
recipe = slapos.cookbook:logrotate.d
name = stunnel
log = $${stunnel:log-file}
frequency = daily
rotate-num = 30
notifempty = true
create = true
post = $${stunnel:post-rotate-script}
[logrotate-entry-cron]
<= logrotate
recipe =slapos.cookbook:logrotate.d
name = crond
log = $${cron-simplelogger:log}
frequency = daily
rotate-num = 30
notifempty = true
create = true
[cron]
recipe = slapos.cookbook:cron
dcrond-binary = ${dcron:location}/sbin/crond
cron-entries = $${directory:cron-entries}
crontabs = $${directory:crontabs}
cronstamps = $${directory:cronstamps}
catcher = $${cron-simplelogger:wrapper}
binary = $${basedirectory:services}/crond
[cron-simplelogger]
recipe = slapos.cookbook:simplelogger
wrapper = $${rootdirectory:bin}/cron_simplelogger
log = $${basedirectory:log}/crond.log
[cron-entry-logrotate]
<= cron
recipe = slapos.cookbook:cron.d
name = logrotate
frequency = 0 0 * * *
command = $${logrotate:wrapper}
[slap-parameter]
#Default value if no ssh parameters specified
logbox-ip =
logbox-port =
logbox-user =
logbox-passwd =
\ No newline at end of file
[buildout]
parts =
certificate-authority
ca-stunnel
logrotate
logrotate-entry-stunnel
logrotate-entry-apache
cron
cron-entry-logrotate
trac-config
trac-git-hook-script
trac-svn-hook-script
post-revprop-change-script
gitweb-conf
httpd
gitdaemon
promise
ca-shellinabox
frontend-promise
content-promise
publish-connection-informations
eggs-directory = ${buildout:eggs-directory}
develop-eggs-directory = ${buildout:develop-eggs-directory}
offline = true
#----------------
#--
#-- Creation of all needed directories.
[rootdirectory]
recipe = slapos.cookbook:mkdirectory
etc = $${buildout:directory}/etc
var = $${buildout:directory}/var
srv = $${buildout:directory}/srv
bin = $${buildout:directory}/bin
tmp = $${buildout:directory}/tmp
[basedirectory]
recipe = slapos.cookbook:mkdirectory
log = $${rootdirectory:var}/log
services = $${rootdirectory:etc}/service
run = $${rootdirectory:var}/run
backup = $${rootdirectory:srv}/backup
promises = $${rootdirectory:etc}/promise
[directory]
recipe = slapos.cookbook:mkdirectory
cron-entries = $${rootdirectory:etc}/cron.d
crontabs = $${rootdirectory:etc}/crontabs
cronstamps = $${rootdirectory:etc}/cronstamps
ca-dir = $${rootdirectory:srv}/ssl
httpd-log = $${basedirectory:log}/apache
logrotate-entries = $${rootdirectory:etc}/logrotate.d
logrotate-backup = $${basedirectory:backup}/logrotate
tracconfig = $${rootdirectory:srv}
stunnel-conf = $${rootdirectory:etc}/stunnel
shellinabox = $${rootdirectory:srv}/shellinabox/
[cadirectory]
recipe = slapos.cookbook:mkdirectory
requests = $${directory:ca-dir}/requests
private = $${directory:ca-dir}/private
certs = $${directory:ca-dir}/certs
newcerts = $${directory:ca-dir}/newcerts
crl = $${directory:ca-dir}/crl
#----------------
#--
#-- Deploy cron.
[cron]
recipe = slapos.cookbook:cron
dcrond-binary = ${dcron:location}/sbin/crond
cron-entries = $${directory:cron-entries}
crontabs = $${directory:crontabs}
cronstamps = $${directory:cronstamps}
catcher = $${cron-simplelogger:wrapper}
binary = $${basedirectory:services}/crond
[cron-simplelogger]
recipe = slapos.cookbook:simplelogger
wrapper = $${rootdirectory:bin}/cron_simplelogger
log = $${basedirectory:log}/crond.log
#----------------
#--
#-- Deploy logrotate.
[cron-entry-logrotate]
<= cron
recipe = slapos.cookbook:cron.d
name = logrotate
frequency = 0 0 * * *
command = $${logrotate:wrapper}
[logrotate]
recipe = slapos.cookbook:logrotate
# Binaries
logrotate-binary = ${logrotate:location}/usr/sbin/logrotate
gzip-binary = ${gzip:location}/bin/gzip
gunzip-binary = ${gzip:location}/bin/gunzip
# Directories
wrapper = $${rootdirectory:bin}/logrotate
conf = $${rootdirectory:etc}/logrotate.conf
logrotate-entries = $${directory:logrotate-entries}
backup = $${directory:logrotate-backup}
state-file = $${rootdirectory:srv}/logrotate.status
#----------------
#--
#-- Deploy stunnel.
[stunnel]
recipe = slapos.cookbook:stunnel
client = true
stunnel-binary = ${stunnel:location}/bin/stunnel
remote-host = $${mariadb-urlparse:host}
remote-port = $${mariadb-urlparse:port}
local-host = $${slap-network-information:local-ipv4}
local-port = 3306
log-file = $${basedirectory:log}/stunnel.log
config-file = $${directory:stunnel-conf}/stunnel.conf
key-file = $${directory:stunnel-conf}/stunnel.key
cert-file = $${directory:stunnel-conf}/stunnel.crt
pid-file = $${basedirectory:run}/stunnel.pid
wrapper = $${rootdirectory:bin}/raw_stunnel
post-rotate-script = $${rootdirectory:bin}/stunnel_post_rotate
[logrotate-entry-stunnel]
<= logrotate
recipe = slapos.cookbook:logrotate.d
name = stunnel
log = $${stunnel:log-file}
frequency = daily
rotate-num = 30
notifempty = true
create = true
post = $${stunnel:post-rotate-script}
#----------------
#--
#-- Certificate stuff.
[certificate-authority]
recipe = slapos.cookbook:certificate_authority
openssl-binary = ${openssl:location}/bin/openssl
ca-dir = $${directory:ca-dir}
requests-directory = $${cadirectory:requests}
wrapper = $${basedirectory:services}/ca
ca-private = $${cadirectory:private}
ca-certs = $${cadirectory:certs}
ca-newcerts = $${cadirectory:newcerts}
ca-crl = $${cadirectory:crl}
[ca-stunnel]
<= certificate-authority
recipe = slapos.cookbook:certificate_authority.request
executable = $${stunnel:wrapper}
wrapper = $${basedirectory:services}/stunnel
key-file = $${stunnel:key-file}
cert-file = $${stunnel:cert-file}
#----------------
#--
#-- Request MariaDB instance and parse its URL.
[request-mariadb]
<= slap-connection
recipe = slapos.cookbook:request
name = MariaDB
software-url = $${slap-connection:software-release-url}
software-type = mariadb
return = url
sla = computer_guid
sla-computer_guid = $${slap-connection:computer-id}
[mariadb-urlparse]
recipe = slapos.cookbook:urlparse
url = $${request-mariadb:connection-url}
#----------------
#--
#-- Deploy Apache + PHP application.
[httpd-conf]
recipe = slapos.recipe.template
url = ${template-httpd-conf:location}/${template-httpd-conf:filename}
output = $${rootdirectory:etc}/apache.conf
document_root = $${rootdirectory:srv}/site/
wsgi_location = $${rootdirectory:srv}/site/apache
gitweb-static-dir = ${gitweb:location}/share/gitweb/static/
gitweb-script = $${gitweb-cgi:output}
git-http-backend = $${git-http-backend-cgi:output}
cgid-sock = $${basedirectory:run}/cgid.sock
pid_file = $${basedirectory:run}/apache.pid
lock_file = $${basedirectory:run}/apache.lock
ip = $${slap-network-information:global-ipv6}
port = 8080
error_log = $${directory:httpd-log}/error.log
access_log = $${directory:httpd-log}/access.log
[trac-config]
recipe = slapos.recipe.template
url = ${tracIni:location}/${tracIni:filename}
output = $${directory:tracconfig}/trac-config-model.ini
mode = 0600
project_dir = $${rootdirectory:srv}/site
#project_url = http://[$${slap-network-information:global-ipv6}]:8080
project_url = $${request-frontend:connection-site_url}
trac_plugins = $${:project_dir}/plugins
git_bin = ${git:location}/bin/git
git_project_base = $${:project_dir}/git
git_project_list =
git_url = $${:project_url}git
admin_email = $${slap-parameter:admin-email}
project_description = $${slap-parameter:project-desc}
project_footer = $${slap-parameter:project-footer}
project_name = $${slap-parameter:project-name}
#MySQL informations
mysql_username = $${mariadb-urlparse:username}
mysql_password = $${mariadb-urlparse:password}
mysql_database = $${mariadb-urlparse:path}
mysql_host = $${stunnel:local-host}
mysql_port = $${stunnel:local-port}
[trac-wsgi]
recipe = slapos.recipe.template
url = ${tracWsgi:location}/${tracWsgi:filename}
output = $${directory:tracconfig}/trac.wsgi
mode = 0700
trac_env = $${trac-config:project_dir}
python_bin = ${python2.7:location}/bin/python2.7
[trac-svn-hook-script]
recipe = slapos.recipe.template
url = ${trac-svn-hook:location}/${trac-svn-hook:filename}
output = $${directory:tracconfig}/trac-svn-hook
mode = 0700
trac_env = $${trac-config:project_dir}
trac_admin = ${buildout:bin-directory}
python_bin = ${python2.7:location}/bin
python_lib = ${python2.7:location}/lib
svn_python = ${subversion-1.9:location}/lib/svn-python
[trac-git-hook-script]
recipe = slapos.recipe.template
url = ${trac-git-hook:location}/${trac-git-hook:filename}
output = $${directory:tracconfig}/trac-git-hook
mode = 0700
git_bin = ${git:location}/bin/git
trac_admin = ${buildout:bin-directory}/trac-admin
trac_env = $${trac-config:project_dir}
[post-revprop-change-script]
recipe = slapos.recipe.template
url = ${post-revprop-change:location}/${post-revprop-change:filename}
output = $${directory:tracconfig}/post-revprop-change
mode = 0700
trac_svn_hook = $${trac-svn-hook-script:output}
[trac-svnrepo-script]
recipe = slapos.recipe.template
url = ${create-svn-repo:location}/${create-svn-repo:filename}
output = $${rootdirectory:bin}/create-svn-repository.sh
mode = 0700
trac_admin = ${buildout:bin-directory}
svn_bin = ${subversion-1.9:location}/bin
svn_python = ${subversion-1.9:location}/lib/svn-python
python_lib = ${python2.7:location}/lib
[gitweb-conf]
recipe = slapos.recipe.template
url = ${template-gitweb-conf:location}/${template-gitweb-conf:filename}
output = $${rootdirectory:etc}/gitweb.conf
url-list = $${trac-config:project_url}git http://[$${slap-network-information:global-ipv6}]:8080/git git://[$${slap-network-information:global-ipv6}]
base-directory = $${trac-config:project_dir}/git
[gitweb-cgi]
recipe = slapos.recipe.template
url = ${template-gitweb-cgi:location}/${template-gitweb-cgi:filename}
output = $${rootdirectory:bin}/gitweb.cgi
mode = 700
perl = ${perl:location}/bin/perl
gitweb = ${gitweb:location}/share/gitweb/gitweb.cgi
[git-http-backend-cgi]
recipe = slapos.recipe.template
url = ${template-git-http-backend-cgi:location}/${template-git-http-backend-cgi:filename}
output = $${rootdirectory:bin}/git-http-backend.cgi
mode = 700
githttpbackend = ${git:location}/libexec/git-core/git-http-backend
base-directory = $${trac-config:project_dir}/git
[trac-admin]
recipe = slapos.cookbook:pwgen
file = $${buildout:directory}/.password
pwgen-binary = ${pwgen:location}/bin/pwgen
user = TracAdmin
#---------------------
#to avoid manipulate apache after installation, this part is installed before
#running apache services for the first time
[inittrac]
recipe = slapos.cookbook:trac
site-dir = $${trac-config:project_dir}
site-url = $${trac-config:project_url}
project = $${slap-parameter:project-name}
#Use to install trac additional plugins
plugins-egg-dir = ${trac-plugins-egg:location}
#Usefull for update pythonPath
eggs-dirs =
${buildout:eggs-directory}
${buildout:develop-eggs-directory}
python-lib = ${python2.7:location}/lib
trac-admin = ${buildout:bin-directory}/trac-admin
admin-user = $${trac-admin:user}
admin-password = $${trac-admin:password}
#MySQL informations
mysql-username = $${mariadb-urlparse:username}
mysql-password = $${mariadb-urlparse:password}
mysql-database = $${mariadb-urlparse:path}
mysql-host = $${stunnel:local-host}
mysql-port = $${stunnel:local-port}
#SVN - GIT Project list
svn-project-list = $${slap-parameter:svn-project-list}
git-project-list = $${slap-parameter:git-project-list}
git-binary = ${git:location}/bin/git
#configurations files
trac-ini = $${trac-config:output}
trac-wsgi = $${trac-wsgi:output}
svn-repo-script = $${trac-svnrepo-script:output}
post-revprop-change = $${post-revprop-change-script:output}
trac-svn-hook = $${trac-svn-hook-script:output}
trac-git-hook = $${trac-git-hook-script:output}
file-status = $${buildout:directory}/.status
#Trac User list
htpasswd = ${apache:location}/bin/htpasswd
passwd-file = $${trac-config:project_dir}/.htpasswd
user-list = $${slap-parameter:trac-user-list}
[httpd]
recipe = slapos.cookbook:wrapper
command-line = ${apache:location}/bin/httpd -DFOREGROUND -f "$${httpd-conf:output}"
environment = PYTHONPATH=${subversion-1.9:location}/lib/svn-python:$${inittrac:python_path}
LD_LIBRARY_PATH=${python2.7:location}/lib
wrapper-path = $${basedirectory:services}/httpd
wait-for-files = $${inittrac:file-status}
[gitdaemon]
recipe = slapos.cookbook:wrapper
ip = $${slap-network-information:global-ipv6}
port = 9418
command-line = ${git:location}/bin/git daemon --export-all --listen=$${:ip} --port=$${:port} --interpolated-path=$${inittrac:site-dir}/git/%D
wrapper-path = $${basedirectory:services}/git-daemon
wait-for-files = $${inittrac:file-status}
[logrotate-entry-apache]
<= logrotate
recipe = slapos.cookbook:logrotate.d
name = apache
log = $${httpd-conf:error_log} $${httpd-conf:access_log}
frequency = daily
rotate-num = 30
sharedscripts = true
notifempty = true
create = true
#--------------------------
#-----
#---- Request Console for Trac-administration (cannot use Trac without console admin)
[ca-shellinabox]
<= certificate-authority
recipe = slapos.cookbook:certificate_authority.request
executable = $${shellinabox:wrapper}
wrapper = $${basedirectory:services}/shellinaboxd
key-file = $${shellinabox:key-file}
cert-file = $${shellinabox:cert-file}
[shellinabox]
recipe = slapos.cookbook:shellinabox
ipv6 = $${slap-network-information:global-ipv6}
port = 9000
shell = $${shell:wrapper}
wrapper = $${rootdirectory:bin}/shellinaboxd_raw
shellinabox-binary = ${shellinabox:location}/bin/shellinaboxd
password = $${trac-admin:password}
directory = $${inittrac:site-dir}
login-shell = $${rootdirectory:bin}/login
certificate-directory = $${directory:shellinabox}
cert-file = $${directory:shellinabox}/public.crt
key-file = $${directory:shellinabox}/private.key
[shell-wrapper]
recipe = slapos.cookbook:wrapper
command-line = ${buildout:bin-directory}/trac-admin $${inittrac:site-dir}
environment = PYTHONPATH=${subversion-1.9:location}/lib/svn-python:$${inittrac:python_path}
ENV=$${inittrac:site-dir}
SNV_REPOS=$${inittrac:site-dir}/svn
GIT_REPOS=$${inittrac:site-dir}/git
wrapper-path = $${rootdirectory:bin}/shell_raw
[shell]
recipe = slapos.cookbook:shell
wrapper = $${rootdirectory:bin}/shell
shell = $${shell-wrapper:wrapper-path}
home = $${inittrac:site-dir}
ps1 = "\\w> "
path =
#----------------
#--
#-- Request frontend.
#-- We need to remove dependancy between apache, trac and frontend, because url is needed in
#-- trac configuration file and apache depend on trac.
[request-frontend]
<= slap-connection
recipe = slapos.cookbook:requestoptional
name = Frontend
# XXX We have hardcoded SR URL here.
software-url = http://git.erp5.org/gitweb/slapos.git/blob_plain/HEAD:/software/apache-frontend/software.cfg
slave = true
config = url custom_domain
config-url = http://[$${slap-network-information:global-ipv6}]:8080
return = site_url
config-custom_domain = $${slap-parameter:domain}
#----------------
#--
#-- Publish instance parameters.
[publish-connection-informations]
recipe = slapos.cookbook:publish
backend_url = http://[$${httpd-conf:ip}]:$${httpd-conf:port}/
frontend_url = $${request-frontend:connection-site_url}
git = $${request-frontend:connection-site_url}git/
svn = $${request-frontend:connection-site_url}svn/
admin_user = $${trac-admin:user}
admin_password = $${trac-admin:password}
admin_shell = https://[$${shellinabox:ipv6}]:$${shellinabox:port}/
#----------------
#--
#-- Deploy promises scripts.
[promise]
recipe = slapos.cookbook:check_port_listening
path = $${basedirectory:promises}/apache
hostname = $${httpd-conf:ip}
port = $${httpd-conf:port}
[frontend-promise]
recipe = slapos.cookbook:check_url_available
path = $${basedirectory:promises}/frontend
url = $${request-frontend:connection-site_url}
dash_path = ${dash:location}/bin/dash
curl_path = ${curl:location}/bin/curl
[content-promise]
recipe = slapos.cookbook:check_page_content
path = $${basedirectory:promises}/content
url = $${request-frontend:connection-site_url}
dash_path = ${dash:location}/bin/dash
curl_path = ${curl:location}/bin/curl
match = $${slap-parameter:project-name}
[slap-parameter]
domain =
project-name = project
project-desc = My example project
project-footer = Visit the Trac open source project at<br /><a href="http://trac.edgewall.org/">http://trac.edgewall.org/</a>
admin-email = you.admin@email.com
trac-user-list = {}
svn-project-list = {}
git-project-list = {}
[buildout]
parts =
switch_softwaretype
eggs-directory = ${buildout:eggs-directory}
develop-eggs-directory = ${buildout:develop-eggs-directory}
offline = true
[switch_softwaretype]
recipe = slapos.cookbook:softwaretype
default = ${instance-trac:output}
mariadb = ${instance-mariadb:output}
\ No newline at end of file
[buildout]
#develop =
# ${:parts-directory}/slapos.cookbook-repository
# ${trac-plugins-egg:location}/accountmanager
parts =
apache-wsgi
slapos-cookbook
gitweb
subversion-1.9
instance-egg
instance
instance-trac
instance-mariadb
template-httpd-conf
tracWsgi
tracIni
trac-svn-hook
trac-git-hook
post-revprop-change
template-gitweb-cgi
template-gitweb-conf
template-git-http-backend-cgi
# trac-plugins-egg
# check-egg
# slapos.cookbook-repository
# check-recipe
extends =
../../stack/slapos.cfg
../../component/apache/buildout.cfg
../../component/python-2.7/buildout.cfg
../../component/apache-wsgi/buildout.cfg
../../component/logrotate/buildout.cfg
../../component/subversion/buildout.cfg
../../component/gzip/buildout.cfg
../../component/dcron/buildout.cfg
../../component/dash/buildout.cfg
../../component/stunnel/buildout.cfg
../../component/lxml-python/buildout.cfg
../../component/mysql-python/buildout.cfg
../../component/git/buildout.cfg
../../component/pwgen/buildout.cfg
../../component/shellinabox/buildout.cfg
../../component/perl/buildout.cfg
allow-hosts +=
*.edgewall.org
*.edgewall.com
[lxml-python]
python = python2.7
[instance-egg]
recipe = z3c.recipe.scripts
python = python2.7
eggs =
${mysql-python:egg}
slapos.toolbox
collective.recipe.cmd
Genshi
docutils
Pygments
pytz
Trac
[trac-plugins-egg]
recipe = plone.recipe.command
svn = ${subversion-1.9:location}/bin/svn
location = ${buildout:parts-directory}/${:_buildout_section_name_}
#command = ${:svn} co http://trac-hacks.org/svn/simplemultiprojectplugin/trunk/ ${:multipleproject}
command = ${:svn} co http://trac-hacks.org/svn/accountmanagerplugin/0.11 ${:location}/accountmanager
[check-egg]
recipe = plone.recipe.command
stop-on-error = true
update-command = ${:command}
command = grep parts ${buildout:develop-eggs-directory}/accountmanager.egg-link
[instance]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/instance.cfg
output = ${buildout:directory}/template.cfg
mode = 0644
md5sum = bc6ed91a1862a10af661713aa0691848
[instance-trac]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/instance-trac.cfg
output = ${buildout:directory}/template-trac.cfg
md5sum = 1546a60e086b4d083d58ad4fca6dcca8
mode = 0644
[instance-mariadb]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/instance-mariadb.cfg
output = ${buildout:directory}/template-mariadb.cfg
md5sum = 4ea69039e41ff45bffe8f2620bdf187c
mode = 0644
[template-download]
recipe = slapos.recipe.download
url = ${:_profile_base_location_}/templates/${:filename}
mode = 0644
location = ${buildout:parts-directory}/${:_buildout_section_name_}
[tracIni]
<= template-download
filename = trac.ini.in
md5sum = 10286b368b9b6eacae2cdd6caf362759
[tracWsgi]
<= template-download
filename = trac.wsgi.in
md5sum = 5226978477d3336f21f0d8684d23a55a
[trac-svn-hook]
<= template-download
filename = trac-svn-hook.in
md5sum = 81a0e2627af1db4c1d601aabc0ebee0a
[trac-git-hook]
<= template-download
filename = trac-git-hook.in
md5sum = 8704e9717bf1223157b3d25de5a8d9d6
[post-revprop-change]
<= template-download
filename = post-revprop-change.in
md5sum = 917deaeda572ca3e98c2baaf15fcdacc
[create-svn-repo]
<= template-download
filename = create-svn-repo.sh.in
md5sum = 3e4d25ce53dcc3729f4bc682e0d2d239
[template-httpd-conf]
<= template-download
filename = apache.in
md5sum = 4f6d1b748c149f32a39c89931e0cd94a
[template-gitweb-cgi]
<= template-download
filename = gitweb.cgi.in
md5sum = 957a7741c7ab60c4bee6c640e0bdd2fb
[template-gitweb-conf]
<= template-download
filename = gitweb.conf.in
md5sum = ace5a69f59c0be7ea7454183a5550537
[template-git-http-backend-cgi]
<= template-download
filename = git-http-backend.cgi.in
md5sum = d6101df47ddd3b04e34e1f0284686b55
# Local development
[slapos.cookbook-repository]
recipe = plone.recipe.command
stop-on-error = true
branch = trac
revision =
location = ${buildout:parts-directory}/${:_buildout_section_name_}
command = "${git:location}/bin/git" clone --branch "${:branch}" --quiet http://git.erp5.org/repos/slapos.git "${:location}" && if [ -n "${:revision}" ]; then cd "${:location}" && "${git:location}/bin/git" reset --quiet --hard "${:revision}" ; fi
update-command = cd "${:location}" && "${git:location}/bin/git" fetch --quiet && if [ -n "${:revision}" ]; then "${git:location}/bin/git" reset --hard "${:revision}"; else "${git:location}/bin/git" reset --quiet --hard @{upstream} ; fi
[check-recipe]
recipe = plone.recipe.command
stop-on-error = true
update-command = ${:command}
command = grep parts ${buildout:develop-eggs-directory}/slapos.cookbook.egg-link
[networkcache]
# signature certificates of the following uploaders.
# Romain Courteaud
# Sebastien Robin
# Kazuhiko Shiozaki
# Cedric de Saint Martin
# Yingjie Xu
# Gabriel Monnerat
# Łukasz Nowak
# Test Agent (Automatic update from tests)
# Alain Takoudjou
signature-certificate-list =
-----BEGIN CERTIFICATE-----
MIIB4DCCAUkCADANBgkqhkiG9w0BAQsFADA5MQswCQYDVQQGEwJGUjEZMBcGA1UE
CBMQRGVmYXVsdCBQcm92aW5jZTEPMA0GA1UEChMGTmV4ZWRpMB4XDTExMDkxNTA5
MDAwMloXDTEyMDkxNTA5MDAwMlowOTELMAkGA1UEBhMCRlIxGTAXBgNVBAgTEERl
ZmF1bHQgUHJvdmluY2UxDzANBgNVBAoTBk5leGVkaTCBnzANBgkqhkiG9w0BAQEF
AAOBjQAwgYkCgYEApYZv6OstoqNzxG1KI6iE5U4Ts2Xx9lgLeUGAMyfJLyMmRLhw
boKOyJ9Xke4dncoBAyNPokUR6iWOcnPHtMvNOsBFZ2f7VA28em3+E1JRYdeNUEtX
Z0s3HjcouaNAnPfjFTXHYj4um1wOw2cURSPuU5dpzKBbV+/QCb5DLheynisCAwEA
ATANBgkqhkiG9w0BAQsFAAOBgQBCZLbTVdrw3RZlVVMFezSHrhBYKAukTwZrNmJX
mHqi2tN8tNo6FX+wmxUUAf3e8R2Ymbdbn2bfbPpcKQ2fG7PuKGvhwMG3BlF9paEC
q7jdfWO18Zp/BG7tagz0jmmC4y/8akzHsVlruo2+2du2freE8dK746uoMlXlP93g
QUUGLQ==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB8jCCAVugAwIBAgIJAPu2zchZ2BxoMA0GCSqGSIb3DQEBBQUAMBIxEDAOBgNV
BAMMB3RzeGRldjMwHhcNMTExMDE0MTIxNjIzWhcNMTIxMDEzMTIxNjIzWjASMRAw
DgYDVQQDDAd0c3hkZXYzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrPbh+
YGmo6mWmhVb1vTqX0BbeU0jCTB8TK3i6ep3tzSw2rkUGSx3niXn9LNTFNcIn3MZN
XHqbb4AS2Zxyk/2tr3939qqOrS4YRCtXBwTCuFY6r+a7pZsjiTNddPsEhuj4lEnR
L8Ax5mmzoi9nE+hiPSwqjRwWRU1+182rzXmN4QIDAQABo1AwTjAdBgNVHQ4EFgQU
/4XXREzqBbBNJvX5gU8tLWxZaeQwHwYDVR0jBBgwFoAU/4XXREzqBbBNJvX5gU8t
LWxZaeQwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQA07q/rKoE7fAda
FED57/SR00OvY9wLlFEF2QJ5OLu+O33YUXDDbGpfUSF9R8l0g9dix1JbWK9nQ6Yd
R/KCo6D0sw0ZgeQv1aUXbl/xJ9k4jlTxmWbPeiiPZEqU1W9wN5lkGuLxV4CEGTKU
hJA/yXa1wbwIPGvX3tVKdOEWPRXZLg==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB7jCCAVegAwIBAgIJAJWA0jQ4o9DGMA0GCSqGSIb3DQEBBQUAMA8xDTALBgNV
BAMMBHg2MXMwIBcNMTExMTI0MTAyNDQzWhgPMjExMTEwMzExMDI0NDNaMA8xDTAL
BgNVBAMMBHg2MXMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANdJNiFsRlkH
vq2kHP2zdxEyzPAWZH3CQ3Myb3F8hERXTIFSUqntPXDKXDb7Y/laqjMXdj+vptKk
3Q36J+8VnJbSwjGwmEG6tym9qMSGIPPNw1JXY1R29eF3o4aj21o7DHAkhuNc5Tso
67fUSKgvyVnyH4G6ShQUAtghPaAwS0KvAgMBAAGjUDBOMB0GA1UdDgQWBBSjxFUE
RfnTvABRLAa34Ytkhz5vPzAfBgNVHSMEGDAWgBSjxFUERfnTvABRLAa34Ytkhz5v
PzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAFLDS7zNhlrQYSQO5KIj
z2RJe3fj4rLPklo3TmP5KLvendG+LErE2cbKPqnhQ2oVoj6u9tWVwo/g03PMrrnL
KrDm39slYD/1KoE5kB4l/p6KVOdeJ4I6xcgu9rnkqqHzDwI4v7e8/D3WZbpiFUsY
vaZhjNYKWQf79l6zXfOvphzJ
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB9jCCAV+gAwIBAgIJAO4V/jiMoICoMA0GCSqGSIb3DQEBBQUAMBMxETAPBgNV
BAMMCENPTVAtMjMyMCAXDTEyMDIxNjExMTAyM1oYDzIxMTIwMTIzMTExMDIzWjAT
MREwDwYDVQQDDAhDT01QLTIzMjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
wi/3Z8W9pUiegUXIk/AiFDQ0UJ4JFAwjqr+HSRUirlUsHHT+8DzH/hfcTDX1I5BB
D1ADk+ydXjMm3OZrQcXjn29OUfM5C+g+oqeMnYQImN0DDQIOcUyr7AJc4xhvuXQ1
P2pJ5NOd3tbd0kexETa1LVhR6EgBC25LyRBRae76qosCAwEAAaNQME4wHQYDVR0O
BBYEFMDmW9aFy1sKTfCpcRkYnP6zUd1cMB8GA1UdIwQYMBaAFMDmW9aFy1sKTfCp
cRkYnP6zUd1cMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAskbFizHr
b6d3iIyN+wffxz/V9epbKIZVEGJd/6LrTdLiUfJPec7FaxVCWNyKBlCpINBM7cEV
Gn9t8mdVQflNqOlAMkOlUv1ZugCt9rXYQOV7rrEYJBWirn43BOMn9Flp2nibblby
If1a2ZoqHRxoNo2yTmm7TSYRORWVS+vvfjY=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB9jCCAV+gAwIBAgIJAIlBksrZVkK8MA0GCSqGSIb3DQEBBQUAMBMxETAPBgNV
BAMMCENPTVAtMzU3MCAXDTEyMDEyNjEwNTUyOFoYDzIxMTIwMTAyMTA1NTI4WjAT
MREwDwYDVQQDDAhDT01QLTM1NzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
ts+iGUwi44vtIfwXR8DCnLtHV4ydl0YTK2joJflj0/Ws7mz5BYkxIU4fea/6+VF3
i11nwBgYgxQyjNztgc9u9O71k1W5tU95yO7U7bFdYd5uxYA9/22fjObaTQoC4Nc9
mTu6r/VHyJ1yRsunBZXvnk/XaKp7gGE9vNEyJvPn2bkCAwEAAaNQME4wHQYDVR0O
BBYEFKuGIYu8+6aEkTVg62BRYaD11PILMB8GA1UdIwQYMBaAFKuGIYu8+6aEkTVg
62BRYaD11PILMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAMoTRpBxK
YLEZJbofF7gSrRIcrlUJYXfTfw1QUBOKkGFFDsiJpEg4y5pUk1s5Jq9K3SDzNq/W
it1oYjOhuGg3al8OOeKFrU6nvNTF1BAvJCl0tr3POai5yXyN5jlK/zPfypmQYxE+
TaqQSGBJPVXYt6lrq/PRD9ciZgKLOwEqK8w=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB9jCCAV+gAwIBAgIJAPHoWu90gbsgMA0GCSqGSIb3DQEBBQUAMBQxEjAQBgNV
BAMMCXZpZmlibm9kZTAeFw0xMjAzMTkyMzIwNTVaFw0xMzAzMTkyMzIwNTVaMBQx
EjAQBgNVBAMMCXZpZmlibm9kZTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
ozBijpO8PS5RTeKTzA90vi9ezvv4vVjNaguqT4UwP9+O1+i6yq1Y2W5zZxw/Klbn
oudyNzie3/wqs9VfPmcyU9ajFzBv/Tobm3obmOqBN0GSYs5fyGw+O9G3//6ZEhf0
NinwdKmrRX+d0P5bHewadZWIvlmOupcnVJmkks852BECAwEAAaNQME4wHQYDVR0O
BBYEFF9EtgfZZs8L2ZxBJxSiY6eTsTEwMB8GA1UdIwQYMBaAFF9EtgfZZs8L2ZxB
JxSiY6eTsTEwMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAc43YTfc6
baSemaMAc/jz8LNLhRE5dLfLOcRSoHda8y0lOrfe4lHT6yP5l8uyWAzLW+g6s3DA
Yme/bhX0g51BmI6gjKJo5DoPtiXk/Y9lxwD3p7PWi+RhN+AZQ5rpo8UfwnnN059n
yDuimQfvJjBFMVrdn9iP6SfMjxKaGk6gVmI=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB9jCCAV+gAwIBAgIJAMNZBmoIOXPBMA0GCSqGSIb3DQEBBQUAMBMxETAPBgNV
BAMMCENPTVAtMTMyMCAXDTEyMDUwMjEyMDQyNloYDzIxMTIwNDA4MTIwNDI2WjAT
MREwDwYDVQQDDAhDT01QLTEzMjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
6peZQt1sAmMAmSG9BVxxcXm8x15kE9iAplmANYNQ7z2YO57c10jDtlYlwVfi/rct
xNUOKQtc8UQtV/fJWP0QT0GITdRz5X/TkWiojiFgkopza9/b1hXs5rltYByUGLhg
7JZ9dZGBihzPfn6U8ESAKiJzQP8Hyz/o81FPfuHCftsCAwEAAaNQME4wHQYDVR0O
BBYEFNuxsc77Z6/JSKPoyloHNm9zF9yqMB8GA1UdIwQYMBaAFNuxsc77Z6/JSKPo
yloHNm9zF9yqMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAl4hBaJy1
cgiNV2+Z5oNTrHgmzWvSY4duECOTBxeuIOnhql3vLlaQmo0p8Z4c13kTZq2s3nhd
Loe5mIHsjRVKvzB6SvIaFUYq/EzmHnqNdpIGkT/Mj7r/iUs61btTcGUCLsUiUeci
Vd0Ozh79JSRpkrdI8R/NRQ2XPHAo+29TT70=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB9jCCAV+gAwIBAgIJAKRvzcy7OH0UMA0GCSqGSIb3DQEBBQUAMBMxETAPBgNV
BAMMCENPTVAtNzcyMCAXDTEyMDgxMDE1NDI1MVoYDzIxMTIwNzE3MTU0MjUxWjAT
MREwDwYDVQQDDAhDT01QLTc3MjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
o7aipd6MbnuGDeR1UJUjuMLQUariAyQ2l2ZDS6TfOwjHiPw/mhzkielgk73kqN7A
sUREx41eTcYCXzTq3WP3xCLE4LxLg1eIhd4nwNHj8H18xR9aP0AGjo4UFl5BOMa1
mwoyBt3VtfGtUmb8whpeJgHhqrPPxLoON+i6fIbXDaUCAwEAAaNQME4wHQYDVR0O
BBYEFEfjy3OopT2lOksKmKBNHTJE2hFlMB8GA1UdIwQYMBaAFEfjy3OopT2lOksK
mKBNHTJE2hFlMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAaNRx6YN2
M/p3R8/xS6zvH1EqJ3FFD7XeAQ52WuQnKSREzuw0dsw12ClxjcHiQEFioyTiTtjs
5pW18Ry5Ie7iFK4cQMerZwWPxBodEbAteYlRsI6kePV7Gf735Y1RpuN8qZ2sYL6e
x2IMeSwJ82BpdEI5niXxB+iT0HxhmR+XaMI=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB8jCCAVugAwIBAgIJANlTfgX/9cX7MA0GCSqGSIb3DQEBBQUAMBExDzANBgNV
BAMMBkNPTVAtMDAgFw0xMzA1MzAxMTUyMDhaGA8yMTEzMDUwNjExNTIwOFowETEP
MA0GA1UEAwwGQ09NUC0wMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDSGtkh
UPOcYMRiL2czmdfeHNB34nXEr5fMpglbA9RO9Cakf6YhK0jU5Y7kzAb6ZlyEzcC+
YkYWQZ9WCLwGuUvThg5iYlnBxmksv5Ot+5DKyTL4hdMEPCQ0RaLcXSkbxk56q3Rn
EQdYL+IJXS1KGMRWbl4Ql3NhShM9q7vBgyoMuwIDAQABo1AwTjAdBgNVHQ4EFgQU
EpO2oyW/sFAS9eojDbYo3hEOOIIwHwYDVR0jBBgwFoAUEpO2oyW/sFAS9eojDbYo
3hEOOIIwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQBP02wmekqmeD23
90NmwDwyEznDPEJDJybREtP+T++EJ1Q/rcnxIQ5a1iOEWY4RdH87H/+2O/7nDzGs
L0KzeG3WDdmnxLMQ5zpG9Qd5twC0GoMl1zf+8f9/t4QE7Dn4IosP3H3dkcRDQRch
SKYaJZHMckKx40/hhRsyFDR1Gj215g==
-----END CERTIFICATE-----
[versions]
#Error: Couldn't install: lxml 3.1.2
lxml = 3.1.1
lock-file = 2.0
Genshi = 0.7
Jinja2 = 2.6
MySQL-python = 1.2.4
Pygments = 1.6
Trac = 1.0.1
Werkzeug = 0.8.3
apache-libcloud = 0.12.4
async = 0.6.1
buildout-versions = 1.7
collective.recipe.cmd = 0.6
docutils = 0.10
gitdb = 0.5.4
hexagonit.recipe.cmmi = 2.0
slapos.recipe.cmmi = 0.1.1
inotifyx = 0.2.0
meld3 = 0.6.10
netaddr = 0.7.10
plone.recipe.command = 1.1
pycrypto = 2.6
pytz = 2013b
slapos.recipe.download = 1.0.dev-r4053
slapos.recipe.template = 2.4.2
slapos.toolbox = 0.34.0
smmap = 0.8.2
z3c.recipe.scripts = 1.0.1
slapos.cookbook = 0.78.1
# Required by:
# slapos.core==0.35.1
# slapos.toolbox==0.34.0
Flask = 0.9
# Required by:
# slapos.toolbox==0.34.0
GitPython = 0.3.2.RC1
# Required by:
# slapos.toolbox==0.34.0
atomize = 0.1.1
# Required by:
# slapos.toolbox==0.34.0
feedparser = 5.1.3
# Required by:
# slapos.core==0.35.1
netifaces = 0.8
# Required by:
# slapos.toolbox==0.34.0
paramiko = 1.10.1
# Required by:
# slapos.toolbox==0.34.0
psutil = 0.7.0
# Required by:
# slapos.core==0.35.1
pyflakes = 0.7.1
# Required by:
# hexagonit.recipe.download==1.6nxd002
# slapos.cookbook==0.78.1
# slapos.core==0.35.1
# supervisor==3.0b1
# zc.buildout==1.6.0-dev-SlapOS-010
# zope.interface==4.0.5
setuptools = 0.6c12dev-r88846
# Required by:
# slapos.toolbox==0.34.0
slapos.core = 0.35.1
# Required by:
# slapos.core==0.35.1
supervisor = 3.0b1
# Required by:
# slapos.core==0.35.1
unittest2 = 0.5.1
# Required by:
# slapos.toolbox==0.34.0
xml-marshaller = 0.9.7
# Required by:
# slapos.core==0.35.1
zope.interface = 4.0.5
# Apache static configuration
# Automatically generated
# Basic server configuration
PidFile "${:pid_file}"
Listen ${:ip}:${:port}
ServerAdmin someone@email
TypesConfig conf/mime.types
AddType application/x-compress .Z
AddType application/x-gzip .gz .tgz
# Log configuration
ErrorLog "${:error_log}"
LogLevel warn
LogFormat "%h %{REMOTE_USER}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %{REMOTE_USER}i %l %u %t \"%r\" %>s %b" common
CustomLog "${:access_log}" common
ScriptSock "${:cgid-sock}"
SetEnv REMOTE_USER=$REDIRECT_REMOTE_USER
# Directory protection
<Directory />
Options FollowSymLinks
AllowOverride None
Require all denied
</Directory>
WSGIScriptAlias / ${:wsgi_location}/trac.wsgi
<Directory ${:wsgi_location}>
WSGIApplicationGroup %{GLOBAL}
AllowOverride All
Require all granted
</Directory>
<Location /login>
AuthType Basic
AuthName "Trac Administrator Access"
AuthUserFile ${:document_root}/.htpasswd
Require valid-user
</Location>
<Location /svn>
ErrorDocument 404 default
DAV svn
SVNParentPath ${:document_root}/svn/
AuthType Basic
AuthName "SVN Repository Access"
AuthUserFile ${:document_root}/.htpasswd
SVNAdvertiseV2Protocol Off
<LimitExcept GET PROPFIND OPTIONS REPORT>
Require valid-user
</LimitExcept>
</Location>
Alias "/static/" "${:gitweb-static-dir}"
<Directory "${:gitweb-static-dir}">
Options FollowSymLinks
Require all granted
</Directory>
# This is Static Accelerated git pull
AliasMatch "^/git/(.*/objects/[0-9a-f]{2}/[0-9a-f]{38})$" "${:document_root}/git/$1"
AliasMatch "^/git/(.*/objects/pack/pack-[0-9a-f]{40}.(pack|idx))$" "${:document_root}/git/$1"
# When it can't be statically delivered, we rely on git-http-backend
ScriptAliasMatch \
"(?x)^/git/(.*/(HEAD | \
info/refs | \
objects/(info/[^/]+ | \
[0-9a-f]{2}/[0-9a-f]{38} | \
pack/pack-[0-9a-f]{40}\.(pack|idx)) | \
git-(upload|receive)-pack))$" \
"${:git-http-backend}/$1"
# Everything else is gitweb interface
ScriptAlias "/git" "${:gitweb-script}"
RewriteEngine On
RewriteCond %{QUERY_STRING} service=git-receive-pack
RewriteRule ^/git/.*/info/refs$ - [E=git_receive_pack:1]
<Location /git>
Order deny,allow
Deny from env=git_receive_pack
AuthType Basic
AuthName "Git Push Access"
AuthBasicProvider file
AuthUserFile ${:document_root}/.htpasswd
Require valid-user
Satisfy any
</Location>
<LocationMatch "^/git/.*/git-receive-pack$">
AuthType Basic
AuthName "Git Push Access"
AuthBasicProvider file
AuthUserFile ${:document_root}/.htpasswd
Require valid-user
SetEnv REMOTE_USER $REDIRECT_REMOTE_USER
</LocationMatch>
# List of modules
LoadModule unixd_module modules/mod_unixd.so
LoadModule access_compat_module modules/mod_access_compat.so
LoadModule authz_host_module modules/mod_authz_host.so
LoadModule log_config_module modules/mod_log_config.so
LoadModule setenvif_module modules/mod_setenvif.so
LoadModule version_module modules/mod_version.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule mime_module modules/mod_mime.so
LoadModule cgid_module modules/mod_cgid.so
LoadModule env_module modules/mod_env.so
LoadModule dav_module modules/mod_dav.so
LoadModule dav_fs_module modules/mod_dav_fs.so
LoadModule negotiation_module modules/mod_negotiation.so
LoadModule rewrite_module modules/mod_rewrite.so
LoadModule headers_module modules/mod_headers.so
LoadModule dir_module modules/mod_dir.so
LoadModule alias_module modules/mod_alias.so
LoadModule wsgi_module modules/mod_wsgi.so
LoadModule dav_svn_module modules/mod_dav_svn.so
LoadModule authz_svn_module modules/mod_authz_svn.so
LoadModule auth_basic_module modules/mod_auth_basic.so
LoadModule authn_core_module modules/mod_authn_core.so
LoadModule authn_file_module modules/mod_authn_file.so
LoadModule authz_core_module modules/mod_authz_core.so
LoadModule authz_user_module modules/mod_authz_user.so
LoadModule autoindex_module modules/mod_autoindex.so
\ No newline at end of file
#!/bin/sh
export PATH=${:trac_admin}:${:svn_bin}:$PATH
export PYTHONPATH=${:svn_python}:$PYTHONPATH
export LD_LIBRARY_PATH=${:python_lib}:$LD_LIBRARY_PATH
ENV="$1"
REPO="$2"
REALM="$3"
if [ -z "$ENV" -o -z "$REPO" ]; then
echo "Usage: $0 ENV REPO"
exit 2
fi
RPATH="$ENV/svn/$REPO"
PASSWD="$ENV/svnpasswd"
svnadmin create $RPATH
trac-admin $ENV repository add $REPO $RPATH svn
trac-admin $ENV repository resync $REPO
echo "[general]
anon-access = read
auth-access = write
password-db = $PASSWD
realm = $REALM" > $RPATH/conf/svnserve.conf
#!/bin/sh
## This is a very dirty hack
export PATH_INFO="$${REDIRECT_URL:-$PATH_INFO}"
GIT_PROJECT_ROOT='${:base-directory}' GIT_HTTP_EXPORT_ALL= exec '${:githttpbackend}' $@
#!/bin/sh
GITWEB_CONFIG='${gitweb-conf:output}' exec '${:perl}' '${:gitweb}' $@
\ No newline at end of file
$projectroot = '${:base-directory}';
$site_name = '${slap-parameter:project-name}';
our @git_base_url_list = qw(${:url-list});
# Beautiful URLs
$feature{'pathinfo'}{'default'} = [1];
$feature{'blame'}{'default'} = [1];
#!/bin/sh
if [ "$PROPNAME" = "svn:log" -o "$PROPNAME" = "svn:author" ]; then
${:trac_svn_hook} $REPOS $REV $USER $PROPNAME
fi
\ No newline at end of file
#!/bin/sh
REV=$(${:git_bin} rev-parse HEAD)
${:trac_admin} ${:trac_env} added "$1" $REV
\ No newline at end of file
#!/bin/sh
export TRAC_ENV=${:trac_env}
export PATH=${:trac_admin}:${:python_bin}:$PATH
export LD_LIBRARY_PATH=${:python_lib}:$LD_LIBRARY_PATH
export PYTHONPATH=${:svn_python}:$PYTHONPATH
REPOS="$1"
REV="$2"
USER="$3"
PROPNAME="$4"
# -- Foolproofing
if [ -z "$REPOS" -o -z "$REV" ]; then
echo "Usage: $0 REPOS REV"
exit 2
fi
if ! python -V 2>/dev/null; then
echo "python is not in the PATH ($PATH), check PATH and LD_LIBRARY_PATH."
exit 2
fi
if [ -z "$TRAC_ENV" ]; then
echo "TRAC_ENV is not set."
exit 2
fi
# -- Feedback
echo "----"
if [ -z "$USER" -a -z "$PROPNAME" ]; then
EVENT="added"
echo "Changeset $REV was added in $REPOS"
else
EVENT="modified"
echo "Changeset $REV was modified by $USER in $REPOS"
fi
# -- Call "trac-admin ... changeset ... $$REPOS $$REV" for each Trac environment
ifs=$IFS
IFS=:
if [ -n "$BASH_VERSION" ]; then # we can use Bash syntax
if [[ $${BASH_VERSINFO[5]} = *cygwin ]]; then
IFS=";"
fi
fi
for env in $TRAC_ENV; do
if [ -r "$env/VERSION" ]; then
log=$env/log/svn-hooks-`basename $REPOS`.log
nohup sh <<EOF >> $log 2>&1 &
echo "Changeset $REV $EVENT"
trac-admin $env changeset $EVENT $REPOS $REV && \
echo "OK" || echo "FAILED: see the Trac log"
EOF
else
echo "$env doesn't seem to be a Trac environment, skipping..."
fi
done
IFS=$ifs
# -*- coding: utf-8 -*-
[attachment]
max_size = 262144
max_zip_size = 2097152
render_unsafe_content = false
[browser]
color_scale = True
downloadable_paths = /trunk, /branches/*, /tags/*
hide_properties = svk:merge
intermediate_color =
intermediate_point =
newest_color = (255, 136, 136)
oldest_color = (136, 136, 255)
oneliner_properties = trac:summary
render_unsafe_content = false
wiki_properties = trac:description
[changeset]
max_diff_bytes = 10000000
max_diff_files = 0
wiki_format_messages = true
[header_logo]
alt = (please configure the [header_logo] section in trac.ini)
height = -1
link =
src = site/your_project_logo.png
width = -1
[git]
cached_repository = false
git_bin = ${:git_bin}
git_fs_encoding = utf-8
persistent_cache = false
projects_base = ${:git_project_base}
projects_list = ${:git_project_list}
projects_url = ${:git_url}
shortrev_len = 7
trac_user_rlookup = false
use_committer_id = true
use_committer_time = true
wikishortrev_len = 40
[svn]
branches = trunk, branches/*
tags = tags/*
[components]
webadmin.* = enabled
tracopt.versioncontrol.svn.* = enabled
tracopt.versioncontrol.git.* = enabled
tracopt.ticket.commit_updater.* = enabled
[inherit]
htdocs_dir =
plugins_dir = ${:trac_plugins}
templates_dir =
[logging]
log_file = trac.log
# log_format = <inherited>
log_level = DEBUG
log_type = none
[milestone]
stats_provider = DefaultTicketGroupStatsProvider
[mimeviewer]
max_preview_size = 262144
mime_map = text/x-dylan:dylan, text/x-idl:ice, text/x-ada:ads:adb
mime_map_patterns = text/plain:README|INSTALL|COPYING.*
pygments_default_style = trac
pygments_modes =
tab_width = 8
treat_as_binary = application/octet-stream, application/pdf, application/postscript, application/msword,application/rtf,
[notification]
admit_domains =
always_notify_owner = false
always_notify_reporter = false
always_notify_updater = true
ambiguous_char_width = single
batch_subject_template = $prefix Batch modify: $tickets_descr
email_sender = SmtpEmailSender
ignore_domains =
mime_encoding = none
sendmail_path = sendmail
smtp_always_bcc =
smtp_always_cc =
smtp_default_domain =
smtp_enabled = false
smtp_from = trac@localhost
smtp_from_author = false
smtp_from_name =
smtp_password =
smtp_port = 25
smtp_replyto = trac@localhost
smtp_server = localhost
smtp_subject_prefix = __default__
smtp_user =
ticket_subject_template = $prefix #$ticket.id: $summary
use_public_cc = false
use_short_addr = false
use_tls = false
[project]
admin = ${:admin_email}
admin_trac_url = .
descr = ${:project_description}
footer = ${:project_footer}
icon = common/trac.ico
name = ${:project_name}
url = ${:project_url}
[query]
default_anonymous_query = status!=closed&cc~=$USER
default_query = status!=closed&owner=$USER
items_per_page = 100
ticketlink_query = ?status=!closed
[report]
items_per_page = 100
items_per_page_rss = 0
[revisionlog]
default_log_limit = 100
graph_colors = ['#cc0', '#0c0', '#0cc', '#00c', '#c0c', '#c00']
[roadmap]
stats_provider = DefaultTicketGroupStatsProvider
[search]
# default_disabled_filters = <inherited>
min_query_length = 3
[sqlite]
# extensions = <inherited>
[ticket]
default_cc =
default_component =
default_description =
default_keywords =
default_milestone =
default_owner = < default >
default_priority = major
default_resolution = fixed
default_severity =
default_summary =
default_type = defect
default_version =
max_comment_size = 262144
max_description_size = 262144
preserve_newlines = default
restrict_owner = false
workflow = ConfigurableTicketWorkflow
[ticket-workflow]
accept = new,assigned,accepted,reopened -> accepted
accept.operations = set_owner_to_self
accept.permissions = TICKET_MODIFY
leave = * -> *
leave.default = 1
leave.operations = leave_status
reassign = new,assigned,accepted,reopened -> assigned
reassign.operations = set_owner
reassign.permissions = TICKET_MODIFY
reopen = closed -> reopened
reopen.operations = del_resolution
reopen.permissions = TICKET_CREATE
resolve = new,assigned,accepted,reopened -> closed
resolve.operations = set_resolution
resolve.permissions = TICKET_MODIFY
[ticket-custom]
project = ${:project_name}
project.label = Project
project.value =
[timeline]
abbreviated_messages = True
changeset_collapse_events = false
changeset_long_messages = false
changeset_show_files = 0
default_daysback = 30
max_daysback = 90
newticket_formatter = oneliner
ticket_show_details = false
[trac]
auth_cookie_lifetime = 0
auth_cookie_path =
authz_file =
authz_module_name =
auto_preview_timeout = 2.0
auto_reload = False
backup_dir = db
base_url = ${:project_url}
check_auth_ip = false
database = mysql://${:mysql_username}:${:mysql_password}@${:mysql_host}:${:mysql_port}/${:mysql_database}
debug_sql = False
default_charset = utf-8
default_dateinfo_format = relative
genshi_cache_size = 128
htdocs_location =
ignore_auth_case = false
jquery_location =
jquery_ui_location =
jquery_ui_theme_location =
mainnav = wiki, timeline, roadmap, browser, tickets, newticket, search
metanav = login, logout, prefs, help, about
mysqldump_path = mysqldump
never_obfuscate_mailto = false
permission_policies = DefaultPermissionPolicy, LegacyAttachmentPolicy
permission_store = DefaultPermissionStore
pg_dump_path = pg_dump
repository_dir =
repository_sync_per_request = (default)
repository_type = svn
resizable_textareas = true
secure_cookies = False
show_email_addresses = false
show_ip_addresses = false
timeout = 20
use_base_url_for_redirect = False
[versioncontrol]
allowed_repository_dir_prefixes =
[wiki]
ignore_missing_pages = false
max_size = 262144
render_unsafe_content = false
safe_schemes = cvs, file, ftp, git, irc, http, https, news, sftp, smb, ssh, svn, svn+ssh
split_page_names = false
#!${:python_bin}
# -*- coding: utf-8 -*-
import os
def application(environ, start_request):
if not 'trac.env_parent_dir' in environ:
environ.setdefault('trac.env_path', '${:trac_env}')
if 'PYTHON_EGG_CACHE' in environ:
os.environ['PYTHON_EGG_CACHE'] = environ['PYTHON_EGG_CACHE']
elif 'trac.env_path' in environ:
os.environ['PYTHON_EGG_CACHE'] = \
os.path.join(environ['trac.env_path'], '.egg-cache')
elif 'trac.env_parent_dir' in environ:
os.environ['PYTHON_EGG_CACHE'] = \
os.path.join(environ['trac.env_parent_dir'], '.egg-cache')
from trac.web.main import dispatch_request
return dispatch_request(environ, start_request)
\ No newline at end of file
# Exactly the same as software.cfg, but fetch the slapos.cookbook and
# slapos.toolbox from git repository instead of fetching stable version,
# allowing to play with bleeding edge environment.
# You'll need to run buildout twice for this profile.
[buildout]
extends =
../../component/git/buildout.cfg
software.cfg
parts +=
# Development parts
slapos.cookbook-repository
slapos.core-repository
slapos.toolbox-repository
check-recipe
develop =
${:parts-directory}/slapos.cookbook-repository
${:parts-directory}/slapos.core-repository
${:parts-directory}/slapos.toolbox-repository
[slapos.toolbox-repository]
recipe = slapos.recipe.build:gitclone
repository = http://git.erp5.org/repos/slapos.toolbox.git
branch = master
git-executable = ${git:location}/bin/git
[slapos.cookbook-repository]
recipe = slapos.recipe.build:gitclone
repository = http://git.erp5.org/repos/slapos.git
branch = tt-rss
git-executable = ${git:location}/bin/git
[slapos.core-repository]
recipe = slapos.recipe.build:gitclone
repository = http://git.erp5.org/repos/slapos.core.git
branch = master
git-executable = ${git:location}/bin/git
[check-recipe]
recipe = plone.recipe.command
stop-on-error = true
update-command = ${:command}
command =
grep parts ${buildout:develop-eggs-directory}/slapos.cookbook.egg-link &&
grep parts ${buildout:develop-eggs-directory}/slapos.core.egg-link &&
grep parts ${buildout:develop-eggs-directory}/slapos.toolbox.egg-link
[versions]
slapos.cookbook =
slapos.toolbox =
slapos.core =
......@@ -14,3 +14,8 @@ mysql-host = $${apache-php:mysql-host}
mysql-port = $${apache-php:mysql-port}
configureinstall-location = $${basedirectory:scripts}/configureInstall
sql-script = ${sql-script:location}/${sql-script:filename}
# Give the correct information to apache recipe to put the hostname in the
# tt-rss config file
[apache-php]
application-url = $${request-frontend:connection-site_url}
......@@ -2,10 +2,13 @@
extends =
../../stack/lamp/buildout.cfg
[versions]
slapos.cookbook =
[application]
recipe = slapos.recipe.build:download-unpacked
url = https://github.com/gothfox/Tiny-Tiny-RSS/archive/1.7.5.tar.gz
#md5sum = a81cea71701404cebf64c07b7ac6c948
url = https://github.com/gothfox/Tiny-Tiny-RSS/archive/1.7.8.tar.gz
md5sum = efd7eec1629db379896fb7e74bba400e
strip-top-level-dir = true
[application-template]
......
......@@ -17,8 +17,7 @@
// *** Basic settings (important!) ***
// ***********************************
//FIXME set frontend URL
define('SELF_URL_PATH', 'http://%(ip)s:%(port)s');
define('SELF_URL_PATH', '%(url)s');
// Full URL of your tt-rss installation. This should be set to the
// location of tt-rss directory, e.g. http://yourserver/tt-rss/
// You need to set this option correctly otherwise several features
......
Zabbix Agent
============
This Software Release allows to deploy a Zabbix Agent that will connect
to an existing Zabbix Server.
How to request
==============
Just request a new instance of it, with the following parameters::
<?xml version="1.0" encoding="utf-8"?>
<instance>
<parameter id="server">REPLACE BY IP(v6) OF ZABBIX SERVER</parameter>
<parameter id="hostname">REPLACE BY DESIRED HOSTNAME OF MACHINE</parameter>
</instance>
[buildout]
parts =
slapos-cookbook
instance-egg
apache-php
template-mariadb
template-boinc
template-httpd-conf
extends =
../../component/boinc/buildout.cfg
../../component/mysql-python/buildout.cfg
../../component/gzip/buildout.cfg
../../component/apache/buildout.cfg
../../component/apache-php/buildout.cfg
../../component/mariadb/buildout.cfg
../../component/dash/buildout.cfg
../../component/logrotate/buildout.cfg
../../component/lxml-python/buildout.cfg
../../component/stunnel/buildout.cfg
../../component/dcron/buildout.cfg
../slapos.cfg
[instance-egg]
recipe = zc.recipe.egg
eggs =
${mysql-python:egg}
slapos.toolbox
#Because Boinc deamon and Boinc sheduler(with apache) work side by side, we deploy
#Boinc and apache-php in the same partition.
[template-boinc]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/instance-boinc.cfg
output = ${buildout:directory}/template-boinc.cfg
md5sum = 6642942dde15ab5195d8d8533690ef29
mode = 0644
#Template for deploying MySQL Database Server
[template-mariadb]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/../lamp/mariadb/instance-mariadb.cfg.in
output = ${buildout:directory}/template-mariadb.cfg
#md5sum = 8142244a3087a23e002a08225579528a
mode = 0644
[template-httpd-conf]
recipe = slapos.recipe.download
url = ${:_profile_base_location_}/template/${:filename}
mode = 0644
filename = apache.in
md5sum = 5d5f49331debc4e3d2a02d8525064f8e
location = ${buildout:parts-directory}/${:_buildout_section_name_}
[boinc-default]
template-result =
template-wu =
extension =
platform = x86_64-pc-linux-gnu
[boinc-application]
app-list = {}
[networkcache]
# signature certificates of the following uploaders.
# Romain Courteaud
# Sebastien Robin
# Kazuhiko Shiozaki
# Cedric de Saint Martin
# Yingjie Xu
# Gabriel Monnerat
# Łukasz Nowak
# Test Agent (Automatic update from tests)
signature-certificate-list =
-----BEGIN CERTIFICATE-----
MIIB4DCCAUkCADANBgkqhkiG9w0BAQsFADA5MQswCQYDVQQGEwJGUjEZMBcGA1UE
CBMQRGVmYXVsdCBQcm92aW5jZTEPMA0GA1UEChMGTmV4ZWRpMB4XDTExMDkxNTA5
MDAwMloXDTEyMDkxNTA5MDAwMlowOTELMAkGA1UEBhMCRlIxGTAXBgNVBAgTEERl
ZmF1bHQgUHJvdmluY2UxDzANBgNVBAoTBk5leGVkaTCBnzANBgkqhkiG9w0BAQEF
AAOBjQAwgYkCgYEApYZv6OstoqNzxG1KI6iE5U4Ts2Xx9lgLeUGAMyfJLyMmRLhw
boKOyJ9Xke4dncoBAyNPokUR6iWOcnPHtMvNOsBFZ2f7VA28em3+E1JRYdeNUEtX
Z0s3HjcouaNAnPfjFTXHYj4um1wOw2cURSPuU5dpzKBbV+/QCb5DLheynisCAwEA
ATANBgkqhkiG9w0BAQsFAAOBgQBCZLbTVdrw3RZlVVMFezSHrhBYKAukTwZrNmJX
mHqi2tN8tNo6FX+wmxUUAf3e8R2Ymbdbn2bfbPpcKQ2fG7PuKGvhwMG3BlF9paEC
q7jdfWO18Zp/BG7tagz0jmmC4y/8akzHsVlruo2+2du2freE8dK746uoMlXlP93g
QUUGLQ==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB8jCCAVugAwIBAgIJAPu2zchZ2BxoMA0GCSqGSIb3DQEBBQUAMBIxEDAOBgNV
BAMMB3RzeGRldjMwHhcNMTExMDE0MTIxNjIzWhcNMTIxMDEzMTIxNjIzWjASMRAw
DgYDVQQDDAd0c3hkZXYzMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrPbh+
YGmo6mWmhVb1vTqX0BbeU0jCTB8TK3i6ep3tzSw2rkUGSx3niXn9LNTFNcIn3MZN
XHqbb4AS2Zxyk/2tr3939qqOrS4YRCtXBwTCuFY6r+a7pZsjiTNddPsEhuj4lEnR
L8Ax5mmzoi9nE+hiPSwqjRwWRU1+182rzXmN4QIDAQABo1AwTjAdBgNVHQ4EFgQU
/4XXREzqBbBNJvX5gU8tLWxZaeQwHwYDVR0jBBgwFoAU/4XXREzqBbBNJvX5gU8t
LWxZaeQwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQA07q/rKoE7fAda
FED57/SR00OvY9wLlFEF2QJ5OLu+O33YUXDDbGpfUSF9R8l0g9dix1JbWK9nQ6Yd
R/KCo6D0sw0ZgeQv1aUXbl/xJ9k4jlTxmWbPeiiPZEqU1W9wN5lkGuLxV4CEGTKU
hJA/yXa1wbwIPGvX3tVKdOEWPRXZLg==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB7jCCAVegAwIBAgIJAJWA0jQ4o9DGMA0GCSqGSIb3DQEBBQUAMA8xDTALBgNV
BAMMBHg2MXMwIBcNMTExMTI0MTAyNDQzWhgPMjExMTEwMzExMDI0NDNaMA8xDTAL
BgNVBAMMBHg2MXMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANdJNiFsRlkH
vq2kHP2zdxEyzPAWZH3CQ3Myb3F8hERXTIFSUqntPXDKXDb7Y/laqjMXdj+vptKk
3Q36J+8VnJbSwjGwmEG6tym9qMSGIPPNw1JXY1R29eF3o4aj21o7DHAkhuNc5Tso
67fUSKgvyVnyH4G6ShQUAtghPaAwS0KvAgMBAAGjUDBOMB0GA1UdDgQWBBSjxFUE
RfnTvABRLAa34Ytkhz5vPzAfBgNVHSMEGDAWgBSjxFUERfnTvABRLAa34Ytkhz5v
PzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAFLDS7zNhlrQYSQO5KIj
z2RJe3fj4rLPklo3TmP5KLvendG+LErE2cbKPqnhQ2oVoj6u9tWVwo/g03PMrrnL
KrDm39slYD/1KoE5kB4l/p6KVOdeJ4I6xcgu9rnkqqHzDwI4v7e8/D3WZbpiFUsY
vaZhjNYKWQf79l6zXfOvphzJ
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB9jCCAV+gAwIBAgIJAO4V/jiMoICoMA0GCSqGSIb3DQEBBQUAMBMxETAPBgNV
BAMMCENPTVAtMjMyMCAXDTEyMDIxNjExMTAyM1oYDzIxMTIwMTIzMTExMDIzWjAT
MREwDwYDVQQDDAhDT01QLTIzMjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
wi/3Z8W9pUiegUXIk/AiFDQ0UJ4JFAwjqr+HSRUirlUsHHT+8DzH/hfcTDX1I5BB
D1ADk+ydXjMm3OZrQcXjn29OUfM5C+g+oqeMnYQImN0DDQIOcUyr7AJc4xhvuXQ1
P2pJ5NOd3tbd0kexETa1LVhR6EgBC25LyRBRae76qosCAwEAAaNQME4wHQYDVR0O
BBYEFMDmW9aFy1sKTfCpcRkYnP6zUd1cMB8GA1UdIwQYMBaAFMDmW9aFy1sKTfCp
cRkYnP6zUd1cMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAskbFizHr
b6d3iIyN+wffxz/V9epbKIZVEGJd/6LrTdLiUfJPec7FaxVCWNyKBlCpINBM7cEV
Gn9t8mdVQflNqOlAMkOlUv1ZugCt9rXYQOV7rrEYJBWirn43BOMn9Flp2nibblby
If1a2ZoqHRxoNo2yTmm7TSYRORWVS+vvfjY=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB9jCCAV+gAwIBAgIJAIlBksrZVkK8MA0GCSqGSIb3DQEBBQUAMBMxETAPBgNV
BAMMCENPTVAtMzU3MCAXDTEyMDEyNjEwNTUyOFoYDzIxMTIwMTAyMTA1NTI4WjAT
MREwDwYDVQQDDAhDT01QLTM1NzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
ts+iGUwi44vtIfwXR8DCnLtHV4ydl0YTK2joJflj0/Ws7mz5BYkxIU4fea/6+VF3
i11nwBgYgxQyjNztgc9u9O71k1W5tU95yO7U7bFdYd5uxYA9/22fjObaTQoC4Nc9
mTu6r/VHyJ1yRsunBZXvnk/XaKp7gGE9vNEyJvPn2bkCAwEAAaNQME4wHQYDVR0O
BBYEFKuGIYu8+6aEkTVg62BRYaD11PILMB8GA1UdIwQYMBaAFKuGIYu8+6aEkTVg
62BRYaD11PILMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAMoTRpBxK
YLEZJbofF7gSrRIcrlUJYXfTfw1QUBOKkGFFDsiJpEg4y5pUk1s5Jq9K3SDzNq/W
it1oYjOhuGg3al8OOeKFrU6nvNTF1BAvJCl0tr3POai5yXyN5jlK/zPfypmQYxE+
TaqQSGBJPVXYt6lrq/PRD9ciZgKLOwEqK8w=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB9jCCAV+gAwIBAgIJAPHoWu90gbsgMA0GCSqGSIb3DQEBBQUAMBQxEjAQBgNV
BAMMCXZpZmlibm9kZTAeFw0xMjAzMTkyMzIwNTVaFw0xMzAzMTkyMzIwNTVaMBQx
EjAQBgNVBAMMCXZpZmlibm9kZTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
ozBijpO8PS5RTeKTzA90vi9ezvv4vVjNaguqT4UwP9+O1+i6yq1Y2W5zZxw/Klbn
oudyNzie3/wqs9VfPmcyU9ajFzBv/Tobm3obmOqBN0GSYs5fyGw+O9G3//6ZEhf0
NinwdKmrRX+d0P5bHewadZWIvlmOupcnVJmkks852BECAwEAAaNQME4wHQYDVR0O
BBYEFF9EtgfZZs8L2ZxBJxSiY6eTsTEwMB8GA1UdIwQYMBaAFF9EtgfZZs8L2ZxB
JxSiY6eTsTEwMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAc43YTfc6
baSemaMAc/jz8LNLhRE5dLfLOcRSoHda8y0lOrfe4lHT6yP5l8uyWAzLW+g6s3DA
Yme/bhX0g51BmI6gjKJo5DoPtiXk/Y9lxwD3p7PWi+RhN+AZQ5rpo8UfwnnN059n
yDuimQfvJjBFMVrdn9iP6SfMjxKaGk6gVmI=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB9jCCAV+gAwIBAgIJAMNZBmoIOXPBMA0GCSqGSIb3DQEBBQUAMBMxETAPBgNV
BAMMCENPTVAtMTMyMCAXDTEyMDUwMjEyMDQyNloYDzIxMTIwNDA4MTIwNDI2WjAT
MREwDwYDVQQDDAhDT01QLTEzMjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
6peZQt1sAmMAmSG9BVxxcXm8x15kE9iAplmANYNQ7z2YO57c10jDtlYlwVfi/rct
xNUOKQtc8UQtV/fJWP0QT0GITdRz5X/TkWiojiFgkopza9/b1hXs5rltYByUGLhg
7JZ9dZGBihzPfn6U8ESAKiJzQP8Hyz/o81FPfuHCftsCAwEAAaNQME4wHQYDVR0O
BBYEFNuxsc77Z6/JSKPoyloHNm9zF9yqMB8GA1UdIwQYMBaAFNuxsc77Z6/JSKPo
yloHNm9zF9yqMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAl4hBaJy1
cgiNV2+Z5oNTrHgmzWvSY4duECOTBxeuIOnhql3vLlaQmo0p8Z4c13kTZq2s3nhd
Loe5mIHsjRVKvzB6SvIaFUYq/EzmHnqNdpIGkT/Mj7r/iUs61btTcGUCLsUiUeci
Vd0Ozh79JSRpkrdI8R/NRQ2XPHAo+29TT70=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB9jCCAV+gAwIBAgIJAKRvzcy7OH0UMA0GCSqGSIb3DQEBBQUAMBMxETAPBgNV
BAMMCENPTVAtNzcyMCAXDTEyMDgxMDE1NDI1MVoYDzIxMTIwNzE3MTU0MjUxWjAT
MREwDwYDVQQDDAhDT01QLTc3MjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
o7aipd6MbnuGDeR1UJUjuMLQUariAyQ2l2ZDS6TfOwjHiPw/mhzkielgk73kqN7A
sUREx41eTcYCXzTq3WP3xCLE4LxLg1eIhd4nwNHj8H18xR9aP0AGjo4UFl5BOMa1
mwoyBt3VtfGtUmb8whpeJgHhqrPPxLoON+i6fIbXDaUCAwEAAaNQME4wHQYDVR0O
BBYEFEfjy3OopT2lOksKmKBNHTJE2hFlMB8GA1UdIwQYMBaAFEfjy3OopT2lOksK
mKBNHTJE2hFlMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAaNRx6YN2
M/p3R8/xS6zvH1EqJ3FFD7XeAQ52WuQnKSREzuw0dsw12ClxjcHiQEFioyTiTtjs
5pW18Ry5Ie7iFK4cQMerZwWPxBodEbAteYlRsI6kePV7Gf735Y1RpuN8qZ2sYL6e
x2IMeSwJ82BpdEI5niXxB+iT0HxhmR+XaMI=
-----END CERTIFICATE-----
[versions]
pycrypto = 2.6
lxml = 3.2.1
setuptools = 0.6c12dev-r88846
Jinja2 = 2.7
MarkupSafe = 0.18
MySQL-python = 1.2.4
Werkzeug = 0.8.3
apache-libcloud = 0.12.4
async = 0.6.1
buildout-versions = 1.7
gitdb = 0.5.4
inotifyx = 0.2.0-1
meld3 = 0.6.10
netaddr = 0.7.10
plone.recipe.command = 1.1
pytz = 2013b
slapos.recipe.cmmi = 0.1.1
slapos.recipe.download = 1.0.dev-r4053
slapos.recipe.template = 2.4.2
slapos.toolbox = 0.34.0
smmap = 0.8.2
slapos.cookbook=0.78.1
# Required by:
# slapos.core==0.35.1
# slapos.toolbox==0.34.0
Flask = 0.9
# Required by:
# slapos.toolbox==0.34.0
GitPython = 0.3.2.RC1
# Required by:
# slapos.toolbox==0.34.0
atomize = 0.1.1
# Required by:
# slapos.toolbox==0.34.0
feedparser = 5.1.3
# Required by:
# slapos.cookbook==0.78.1
lock-file = 2.0
# Required by:
# slapos.core==0.35.1
netifaces = 0.8-1
# Required by:
# slapos.toolbox==0.34.0
paramiko = 1.10.1
# Required by:
# slapos.toolbox==0.34.0
psutil = 0.7.1
# Required by:
# slapos.core==0.35.1
pyflakes = 0.7.2
# Required by:
# slapos.toolbox==0.34.0
slapos.core = 0.35.1
# Required by:
# slapos.core==0.35.1
supervisor = 3.0b1
# Required by:
# slapos.core==0.35.1
unittest2 = 0.5.1
# Required by:
# slapos.toolbox==0.34.0
xml-marshaller = 0.9.7
# Required by:
# slapos.core==0.35.1
zope.interface = 4.0.5
\ No newline at end of file
[buildout]
parts =
boinc-server
boinc-app
certificate-authority
ca-stunnel
logrotate
logrotate-entry-apache
logrotate-entry-stunnel
cron
cron-entry-logrotate
cron-entry-boinc
promise
slapmonitor
frontend-promise
content-promise
publish-connection-informations
eggs-directory = ${buildout:eggs-directory}
develop-eggs-directory = ${buildout:develop-eggs-directory}
#temporary solution
newest = false
offline = false
# Creation of all needed directories
[rootdirectory]
recipe = slapos.cookbook:mkdirectory
etc = $${buildout:directory}/etc/
var = $${buildout:directory}/var/
srv = $${buildout:directory}/srv/
bin = $${buildout:directory}/bin/
tmp = $${buildout:directory}/tmp/
project = $${buildout:directory}/projects/
[basedirectory]
recipe = slapos.cookbook:mkdirectory
log = $${rootdirectory:var}/log/
services = $${rootdirectory:etc}/service/
scripts = $${rootdirectory:etc}/run/
run = $${rootdirectory:var}/run/
backup = $${rootdirectory:srv}/backup/
promises = $${rootdirectory:etc}/promise/
application = $${rootdirectory:tmp}/application
boinc = $${rootdirectory:tmp}/boinc
[directory]
recipe = slapos.cookbook:mkdirectory
ca-dir = $${rootdirectory:srv}/ssl/
httpd-log = $${basedirectory:log}/apache/
php-ini-dir = $${rootdirectory:etc}/php/
tmp-php = $${rootdirectory:tmp}/php/
logrotate-entries = $${rootdirectory:etc}/logrotate.d/
logrotate-backup = $${basedirectory:backup}/logrotate/
stunnel-conf = $${rootdirectory:etc}/stunnel/
cronstamps = $${rootdirectory:etc}/cronstamps/
cron-entries = $${rootdirectory:etc}/cron.d/
crontabs = $${rootdirectory:etc}/crontabs/
[cadirectory]
recipe = slapos.cookbook:mkdirectory
requests = $${directory:ca-dir}/requests/
private = $${directory:ca-dir}/private/
certs = $${directory:ca-dir}/certs/
newcerts = $${directory:ca-dir}/newcerts/
crl = $${directory:ca-dir}/crl/
# Deploy stunnel
[stunnel]
recipe = slapos.cookbook:stunnel
client = true
stunnel-binary = ${stunnel:location}/bin/stunnel
remote-host = $${mariadb-urlparse:host}
remote-port = $${mariadb-urlparse:port}
local-host = $${slap-network-information:local-ipv4}
local-port = 3306
log-file = $${basedirectory:log}/stunnel.log
config-file = $${directory:stunnel-conf}/stunnel.conf
key-file = $${directory:stunnel-conf}/stunnel.key
cert-file = $${directory:stunnel-conf}/stunnel.crt
pid-file = $${basedirectory:run}/stunnel.pid
wrapper = $${rootdirectory:bin}/raw_stunnel
post-rotate-script = $${rootdirectory:bin}/stunnel_post_rotate
# Certificate stuffs
[certificate-authority]
recipe = slapos.cookbook:certificate_authority
openssl-binary = ${openssl:location}/bin/openssl
ca-dir = $${directory:ca-dir}
requests-directory = $${cadirectory:requests}
wrapper = $${basedirectory:services}/ca
ca-private = $${cadirectory:private}
ca-certs = $${cadirectory:certs}
ca-newcerts = $${cadirectory:newcerts}
ca-crl = $${cadirectory:crl}
[ca-stunnel]
<= certificate-authority
recipe = slapos.cookbook:certificate_authority.request
executable = $${stunnel:wrapper}
wrapper = $${basedirectory:services}/stunnel
key-file = $${stunnel:key-file}
cert-file = $${stunnel:cert-file}
# Request MariaDB instance and parse its URL
[request-mariadb]
<= slap-connection
recipe = slapos.cookbook:request
name = MariaDB
software-url = $${slap-connection:software-release-url}
software-type = mariadb
return = url
[mariadb-urlparse]
recipe = slapos.cookbook:urlparse
url = $${request-mariadb:connection-url}
[httpd-conf]
recipe = slapos.recipe.template
url = ${template-httpd-conf:location}/${template-httpd-conf:filename}
output = $${rootdirectory:etc}/apache.conf
document_root = $${rootdirectory:srv}/www/
pid_file = $${basedirectory:run}/apache.pid
lock_file = $${basedirectory:run}/apache.lock
cgid_sock = $${basedirectory:run}/cgid.sock
ip = $${slap-network-information:global-ipv6}
port = 8080
error_log = $${directory:httpd-log}/error.log
access_log = $${directory:httpd-log}/access.log
php_ini_dir = $${directory:php-ini-dir}
niceprojectname = $${slap-parameter:project}@HOME
project = $${slap-parameter:project}
installroot = $${rootdirectory:project}/$${slap-parameter:project}
result_dir = $${rootdirectory:project}/$${slap-parameter:project}/sample_results/
[environment]
PATH = $${rootdirectory:bin}:${subversion:location}/bin:${perl:location}/bin:%(PATH)s
# Deploy Apache + PHP application
[apache-php]
recipe = slapos.cookbook:apachephp
source = $${basedirectory:application}
default-conf = false
httpd-conf = $${httpd-conf:output}
pid-file = $${basedirectory:run}/apache.pid
lock-file = $${basedirectory:run}/apache.lock
error-log = $${directory:httpd-log}/error.log
access-log = $${directory:httpd-log}/access.log
wrapper = $${basedirectory:services}/apache
ip = $${httpd-conf:ip}
port = $${httpd-conf:port}
url = http://[$${:ip}]:$${:port}/
httpd-binary = ${apache:location}/bin/httpd
htdocs = $${rootdirectory:srv}/www/
tmp-dir = $${directory:tmp-php}
php-ini-dir = $${directory:php-ini-dir}
mysql-username = $${mariadb-urlparse:username}
mysql-password = $${mariadb-urlparse:password}
mysql-database = $${mariadb-urlparse:path}
mysql-host = $${stunnel:local-host}
mysql-port = $${stunnel:local-port}
#send environment variable for apache process
environment-section =
environment
template =
configuration =
[boinc-passwd]
recipe = slapos.cookbook:generate.password
storage-path = $${rootdirectory:etc}/.boincpasswd
bytes = 4
#deploy boinc server instance now
#Boinc server depend on apache-php instance
[boinc-server]
recipe = slapos.cookbook:boinc
home = $${buildout:directory}
project = $${slap-parameter:project}
#url-base = http://[$${apache-php:ip}]:$${apache-php:port}/
url-base = $${request-frontend:connection-site_url}
fullname = $${slap-parameter:full-name}
copyright = $${slap-parameter:copyright-holder}
boinc = ${boinc:location}
installroot = $${rootdirectory:project}/$${slap-parameter:project}
wrapper-dir = $${basedirectory:scripts}
source = ${boinc:source}
passwd = $${boinc-passwd:storage-path}
#Manualy add develop-egg and boinc-egg to pythonpath
develop-egg = ${buildout:develop-eggs-directory}
#Other binary path
svn-binary = ${subversion:location}/bin
perl-binary = ${perl:location}/bin
python-binary = ${buildout:executable}
dash = ${dash:location}/bin/dash
#Apache and php
htpasswd = ${apache:location}/bin/htpasswd
apache-pid = $${httpd-conf:pid_file}
php-ini = $${apache-php:php-ini-dir}/php.ini
php-bin = ${apache-php:location}/bin/php
php-wrapper = $${rootdirectory:bin}php
#Mysql Informations
mysql-username = $${mariadb-urlparse:username}
mysql-password = $${mariadb-urlparse:password}
mysql-database = $${mariadb-urlparse:path}
mysql-host = $${stunnel:local-host}
mysql-port = $${stunnel:local-port}
#This allow to deploy or to update Boinc application using only slapparameters from
#vifib BOINC instance parameters
[boinc-app]
<= boinc-server
recipe = slapos.cookbook:boinc.app
#appname and version is require to update any existing application
#otherwise, the recipe would try to install a new one
boinc-app-list = $${slap-parameter:boinc-app-list}
default-template-result = $${slap-parameter:default-template-result}
default-template-wu = $${slap-parameter:default-template-wu}
default-extension = $${slap-parameter:default-extension}
default-platform = $${slap-parameter:default-platform}
# Deploy logrotate, cron, configure it
[logrotate]
recipe = slapos.cookbook:logrotate
# Binaries
logrotate-binary = ${logrotate:location}/usr/sbin/logrotate
gzip-binary = ${gzip:location}/bin/gzip
gunzip-binary = ${gzip:location}/bin/gunzip
# Directories
wrapper = $${rootdirectory:bin}/logrotate
conf = $${rootdirectory:etc}/logrotate.conf
logrotate-entries = $${directory:logrotate-entries}
backup = $${directory:logrotate-backup}
state-file = $${rootdirectory:srv}/logrotate.status
[logrotate-entry-apache]
<= logrotate
recipe = slapos.cookbook:logrotate.d
name = apache
log = $${httpd-conf:error_log} $${httpd-conf:access_log}
frequency = daily
rotate-num = 30
sharedscripts = true
notifempty = true
create = true
[logrotate-entry-stunnel]
<= logrotate
recipe = slapos.cookbook:logrotate.d
name = stunnel
log = $${stunnel:log-file}
frequency = daily
rotate-num = 30
notifempty = true
create = true
post = $${stunnel:post-rotate-script}
[cron-simplelogger]
recipe = slapos.cookbook:simplelogger
wrapper = $${rootdirectory:bin}/cron_simplelogger
log = $${basedirectory:log}/crond.log
[cron]
recipe = slapos.cookbook:cron
dcrond-binary = ${dcron:location}/sbin/crond
cron-entries = $${directory:cron-entries}
crontabs = $${directory:crontabs}
cronstamps = $${directory:cronstamps}
catcher = $${cron-simplelogger:wrapper}
binary = $${basedirectory:services}/crond
[cron-entry-logrotate]
<= cron
recipe = slapos.cookbook:cron.d
name = logrotate
frequency = 0 0 * * *
command = $${logrotate:wrapper}
[cron-entry-boinc]
<= cron
recipe = slapos.cookbook:cron.d
name = cronjob
frequency = 0,5,10,15,20,25,30,35,40,45,50,55 * * * *
command = PATH=$${rootdirectory:bin}:$PATH $${boinc-server:installroot}/bin/start --cron
# Request frontend
[request-frontend]
<= slap-connection
recipe = slapos.cookbook:requestoptional
name = Frontend
# XXX We have hardcoded SR URL here.
software-url = http://git.erp5.org/gitweb/slapos.git/blob_plain/HEAD:/software/apache-frontend/software.cfg
slave = true
config = url custom_domain
config-url = http://[$${apache-php:ip}]:$${apache-php:port}/
return = site_url
config-custom_domain = $${slap-parameter:domain}
# Deploy slapmonitor
[slapmonitor]
recipe = slapos.cookbook:slapmonitor
pid-file = $${basedirectory:run}/apache.pid
database-path = $${basedirectory:log}/slapmonitor.db
shell-path = ${dash:location}/bin/dash
slapmonitor-path = ${buildout:bin-directory}/slapmonitor
path = $${basedirectory:scripts}/slapmonitor
# Publish all instance parameters (url of instance)
[publish-connection-informations]
recipe = slapos.cookbook:publish
boinc_admin_page = $${boinc-server:admin_page}
boinc_result_url = $${boinc-server:result_page}
boinc_home_page = $${boinc-server:home_page}
boinc_user = $${boinc-server:user}
boinc_passwd = $${boinc-passwd:passwd}
# Deploy promises scripts
[promise]
recipe = slapos.cookbook:check_port_listening
path = $${basedirectory:promises}/apache
hostname = $${apache-php:ip}
port = $${apache-php:port}
[frontend-promise]
recipe = slapos.cookbook:check_url_available
path = $${basedirectory:promises}/frontend
url = $${request-frontend:connection-site_url}/$${slap-parameter:project}
dash_path = ${dash:location}/bin/dash
curl_path = ${curl:location}/bin/curl
[content-promise]
recipe = slapos.cookbook:check_page_content
path = $${basedirectory:promises}/content
url = $${request-frontend:connection-site_url}/$${slap-parameter:project}
match = $${slap-parameter:full-name}
dash_path = ${dash:location}/bin/dash
curl_path = ${curl:location}/bin/curl
[slap-parameter]
#Default config value for boinc
project = boinc_test
full-name = Boinc Project SAMPLE
copyright-holder = REPLACE WITH COPYRIGHT HOLDER
#definition of BOINC parameter
#boinc-app-list is a Json data for all application to deploy
# boinc-app-list = {"MY_APP1":{VERSION1:{
# use_default:true, "binary":"MY_BINARY",
# "platform":"", "extension":"", "template-result":"",
# "template-wu":"", "wu-number":1, "input-file":"INPUT"},
# "VERSION2":{use_default:false, ...}}}
# "app-name" parameter is now boinc-app-list[key]
boinc-app-list = ${boinc-application:app-list}
default-template-result = ${boinc-default:template-result}
default-template-wu = ${boinc-default:template-wu}
default-extension = ${boinc-default:extension}
default-platform = ${boinc-default:platform}
# Default value if no domain is specified
domain =
# Apache static configuration
# Automatically generated
# Basic server configuration
PidFile "${:pid_file}"
Listen ${:ip}:${:port}
PHPINIDir ${:php_ini_dir}
ServerAdmin someone@email
TypesConfig conf/mime.types
ScriptSock ${:cgid_sock}
AddType application/x-compress .Z
AddType application/x-gzip .gz .tgz
AddType application/x-httpd-php .php .phtml .php5 .php4
AddType application/x-httpd-php-source .phps
# Log configuration
ErrorLog "${:error_log}"
LogLevel warn
LogFormat "%h %{REMOTE_USER}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %{REMOTE_USER}i %l %u %t \"%r\" %>s %b" common
CustomLog "${:access_log}" common
# Directory protection
<Directory />
Options FollowSymLinks
AllowOverride None
Require all denied
</Directory>
<Directory ${:document_root}>
Options FollowSymLinks
AllowOverride All
Require all granted
</Directory>
DocumentRoot ${:document_root}
DirectoryIndex index.html index.php
# List of modules
LoadModule unixd_module modules/mod_unixd.so
LoadModule access_compat_module modules/mod_access_compat.so
LoadModule authz_core_module modules/mod_authz_core.so
LoadModule authz_host_module modules/mod_authz_host.so
LoadModule log_config_module modules/mod_log_config.so
LoadModule setenvif_module modules/mod_setenvif.so
LoadModule version_module modules/mod_version.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule mime_module modules/mod_mime.so
LoadModule dav_module modules/mod_dav.so
LoadModule dav_fs_module modules/mod_dav_fs.so
LoadModule negotiation_module modules/mod_negotiation.so
LoadModule rewrite_module modules/mod_rewrite.so
LoadModule headers_module modules/mod_headers.so
LoadModule dir_module modules/mod_dir.so
LoadModule php5_module modules/libphp5.so
LoadModule alias_module modules/mod_alias.so
LoadModule auth_basic_module modules/mod_auth_basic.so
LoadModule authz_user_module modules/mod_authz_user.so
LoadModule authn_file_module modules/mod_authn_file.so
LoadModule authn_core_module modules/mod_authn_core.so
LoadModule cgid_module modules/mod_cgid.so
LoadModule autoindex_module modules/mod_autoindex.so
## Settings for BOINC project ${:niceprojectname}
Alias /${:project} ${:installroot}/html/user
Alias /${:project}_ops ${:installroot}/html/ops
Alias /${:project}_result/ ${:installroot}/sample_results/
ScriptAlias /${:project}_cgi ${:installroot}/cgi-bin
# Note: projects/*/keys/ should NOT be readable!
<Directory "${:installroot}/html">
Options Indexes FollowSymlinks MultiViews
AllowOverride AuthConfig
Require all granted
</Directory>
<Directory "${:installroot}/cgi-bin">
Options ExecCGI
AllowOverride AuthConfig
Require all granted
</Directory>
Alias /${:project}_result/ ${:result_dir}
<Directory "${:result_dir}">
Options +Indexes
AuthName "${:project}"
AuthType Basic
AuthUserFile ${:installroot}/html/ops/.htpasswd
require valid-user
</Directory>
\ No newline at end of file
......@@ -64,6 +64,7 @@ extends =
../../component/wget/buildout.cfg
../../component/aspell/buildout.cfg
../../component/cloudooo/buildout.cfg
../../component/jsl/buildout.cfg
parts =
rdiff-backup
......@@ -74,6 +75,7 @@ parts =
file
graphviz
haproxy
jsl
varnish-3.0
w3m
poppler
......@@ -196,7 +198,7 @@ extra-context =
[template-zope]
recipe = slapos.recipe.build:download
url = ${:_profile_base_location_}/instance-zope.cfg.in
md5sum = 918b972679d5c06082363d41483324a7
md5sum = 69556ddc9773fb95896b7762e998bb9b
mode = 640
[template-kumofs]
......@@ -213,7 +215,7 @@ extra-context =
[template-tidstorage]
recipe = slapos.recipe.build:download
url = ${:_profile_base_location_}/instance-tidstorage.cfg.in
md5sum = bd5872108f812c6823a8915670e51c4c
md5sum = 5572d10b343bd2de90deeaf55dd0fdc7
mode = 640
[template-cloudooo]
......@@ -233,7 +235,7 @@ mode = 640
# XXX: "template.cfg" is hardcoded in instanciation recipe
filename = template.cfg
template = ${:_profile_base_location_}/instance.cfg.in
md5sum = 2576de300d1a74fd1a99388af9723d42
md5sum = fbb7ea50d7ea6d4e25725801cc3fd5f9
extra-context =
key apache_location apache:location
key aspell_location aspell:location
......@@ -254,6 +256,7 @@ extra-context =
key gzip_location gzip:location
key haproxy_location haproxy:location
key imagemagick_location imagemagick:location
key jsl_location jsl:location
key libICE_location libICE:location
key libSM_location libSM:location
key libX11_location libX11:location
......@@ -392,6 +395,7 @@ initialization =
sys.path[:0] = sum((
glob.glob(os.path.join(x, 'Products', '*', 'tests'))
for x in os.getenv('INSERT_PRODUCTS_PATH', '').split(os.pathsep)), [])
os.environ['PATH'] = '${jsl:location}/bin:%s' % os.environ['PATH']
os.environ['CGI_PATH'] = '${w3-validator:location}/httpd/cgi-bin'
[test_suite_runner]
......
......@@ -466,12 +466,14 @@ post = {{ bin_directory }}/killpidfromfile ${apache-{{ backend_name }}:pid-file}
recipe = slapos.cookbook:haproxy
name = {{ backend_name }}
conf-path = ${directory:etc}/haproxy-{{ backend_name }}.cfg
socket-path = ${directory:run}/haproxy-{{ backend_name }}.sock
ip = {{ ipv4 }}
port = {{ current_haproxy_port }}
maxconn = {{ backend_configuration['maxconn'] }}
server-check-path = /{{ site_id }}/getId
wrapper-path = ${directory:services}/haproxy-{{ backend_name }}
binary-path = {{ parameter_dict['haproxy'] }}/sbin/haproxy
ctl-path = ${directory:bin}/haproxy-{{ backend_name }}-ctl
backend-list = {{ haproxy_backend_list | join(' ')}}
{%- endif %}
{% endfor -%}
......
......@@ -207,6 +207,7 @@ link-binary =
{{ poppler_location }}/bin/pdfunite
{{ dmtx_utils_location }}/bin/dmtxwrite
{{ aspell_location }}/bin/aspell
{{ jsl_location }}/bin/jsl
[certificate-authority]
recipe = slapos.cookbook:certificate_authority
openssl-binary = {{ openssl_location }}/bin/openssl
......
......@@ -47,6 +47,7 @@ poppler = {{ poppler_location }}
dmtx-utils = {{ dmtx_utils_location }}
buildout-bin-directory = {{ buildout_bin_directory }}
zope-conf-template = {{ template_zope_conf }}
jsl = {{ jsl_location }}
[dynamic-template-tidstorage]
< = jinja2-template-base
......@@ -132,6 +133,7 @@ poppler = {{ poppler_location }}
sed = {{ sed_location }}
tesseract = {{ tesseract_location }}
w3m = {{ w3m_location }}
jsl = {{ jsl_location }}
[dynamic-template-zope]
< = jinja2-template-base
......@@ -161,6 +163,7 @@ extra-context =
key sed_location dynamic-template-zope-parameters:sed
key tesseract_location dynamic-template-zope-parameters:tesseract
key w3m_location dynamic-template-zope-parameters:w3m
key jsl_location dynamic-template-zope-parameters:jsl
[template-erp5-single-parameters]
bin-directory = {{ bin_directory }}
......
......@@ -187,6 +187,15 @@ recipe = slapos.cookbook:urlparse
url = $${request-mariadb:connection-url}
#----------------
#--
#-- Common network parameters
[apache-network-configuration]
listening-ip = $${slap-network-information:global-ipv6}
listening-port = 8080
#----------------
#--
#-- Deploy Apache + PHP application.
......@@ -200,8 +209,8 @@ configuration = ${application-configuration:location}
htdocs = $${directory:www}
pid-file = $${basedirectory:run}/apache.pid
lock-file = $${basedirectory:run}/apache.lock
ip = $${slap-network-information:global-ipv6}
port = 8080
ip = $${apache-network-configuration:listening-ip}
port = $${apache-network-configuration:listening-port}
url = http://[$${:ip}]:$${:port}/
error-log = $${directory:httpd-log}/error.log
access-log = $${directory:httpd-log}/access.log
......@@ -242,7 +251,7 @@ name = Frontend
software-url = http://git.erp5.org/gitweb/slapos.git/blob_plain/HEAD:/software/apache-frontend/software.cfg
slave = true
config = url custom_domain
config-url = http://[$${apache-php:ip}]:$${apache-php:port}/
config-url = http://[$${apache-network-configuration:listening-ip}]:$${apache-network-configuration:listening-port}/
return = site_url
config-custom_domain = $${slap-parameter:domain}
......
......@@ -74,7 +74,7 @@ mode = 0644
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/apache/instance-apache-php.cfg.in
output = ${buildout:directory}/instance-apache-php.cfg
md5sum = 296ba845c8ffe75fbc6352dd0e8ce836
md5sum = 3e2d71d3684aac3e52d2f55794df96bf
mode = 0644
[instance-apache-import]
......@@ -326,7 +326,7 @@ netaddr = 0.7.10
pycrypto = 2.6
pytz = 2013b
rdiff-backup = 1.0.5
slapos.cookbook = 0.76.0
slapos.cookbook = 0.78.0
slapos.recipe.build = 0.11.6
slapos.recipe.download = 1.0.dev-r4053
slapos.recipe.template = 2.4.2
......@@ -368,7 +368,7 @@ pyflakes = 0.6.1
# Required by:
# hexagonit.recipe.download==1.6nxd002
# slapos.cookbook==0.76.0
# slapos.cookbook==0.78.0
# slapos.core==0.35.1
# slapos.toolbox==0.34.0
# supervisor==3.0b1
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment