Commit 01314c95 authored by Antoine Catton's avatar Antoine Catton

Merge branch 'wprtubackup'

This is the work I did during my internship in order
to implement backup and wordpress with a pseudo-replicating
MariaDB ready to be used.

This branch name stands for 'WordPress Ready To Use BACKUP'.

This work will be cleaned up, and improved by merging
skynet branch.

Conflicts:
	setup.py
	slapos/recipe/davstorage/__init__.py
	software/wordpress/software.cfg
parents b3cf1cbb 01ff400c
[buildout]
parts = boa
[boa-patch-ENOSYS]
recipe = hexagonit.recipe.download
url = http://sources.gentoo.org/cgi-bin/viewvc.cgi/gentoo-x86/www-servers/boa/files/boa-0.94.14_rc21-ENOSYS.patch?revision=1.1
filename = boa-0.94.14_rc21-ENOSYS.patch
md5sum = 7206b342195961501ed1eae38486e5db
download-only = true
[boa]
recipe = slapos.recipe.build
url = http://www.boa.org/boa-0.94.14rc21.tar.gz
md5sum = e24b570bd767a124fcfb40a34d148ba9
patches =
${boa-patch-ENOSYS:location}/${boa-patch-ENOSYS:filename}
slapos_promise =
directory:bin/
file:bin/boa
file:bin/boa_indexer
script =
import shutil
import os
url = self.download(self.options['url'], self.options['md5sum'])
extract_dir = self.extract(url)
workdir = guessworkdir(extract_dir)
self.applyPatchList(self.options.get('patches'), '-p1', cwd=workdir)
call(['./configure'], cwd=workdir)
call(['make'], cwd=workdir)
# Installation of boa. Manually, no make install
os.makedirs('%(location)s/bin/')
shutil.copyfile(workdir + '/src/boa', '%(location)s/bin/boa')
os.chmod('%(location)s/bin/boa', 0755)
shutil.copyfile(workdir + '/src/boa_indexer', '%(location)s/bin/boa_indexer')
os.chmod('%(location)s/bin/boa_indexer', 0755)
[buildout]
parts = dash
[dash]
recipe = hexagonit.recipe.cmmi
url = http://gondor.apana.org.au/~herbert/dash/files/dash-0.5.7.tar.gz
md5sum = f6cedb10ae7258adb5ab17a10ae80d51
configure-options =
--disable-static
--disable-fnmatch
--disable-glob
...@@ -13,7 +13,7 @@ parts = ...@@ -13,7 +13,7 @@ parts =
[dropbear-userspace-patch] [dropbear-userspace-patch]
recipe = hexagonit.recipe.download recipe = hexagonit.recipe.download
md5sum = 89f575b9a9586b04ef9073c9c3af13ae md5sum = 3d934c2c90e8c57536a4fa2cf8ad216d
url = ${:_profile_base_location_}/${:filename} url = ${:_profile_base_location_}/${:filename}
filename = userspace.patch filename = userspace.patch
download-only = true download-only = true
...@@ -25,6 +25,13 @@ url = ${:_profile_base_location_}/${:filename} ...@@ -25,6 +25,13 @@ url = ${:_profile_base_location_}/${:filename}
filename = ipv6-support.patch filename = ipv6-support.patch
download-only = true download-only = true
[dropbear-no-shell-check-patch]
recipe = hexagonit.recipe.download
md5sum = bb2ac410bd4cb2b07c23bfcc712e45f7
url = ${:_profile_base_location_}/${:filename}
filename = no-shell-checking.patch
download-only = true
[dropbear] [dropbear]
recipe = hexagonit.recipe.cmmi recipe = hexagonit.recipe.cmmi
md5sum = 0284ea239083f04c8b874e08e1aca243 md5sum = 0284ea239083f04c8b874e08e1aca243
...@@ -35,7 +42,7 @@ url = http://matt.ucc.asn.au/dropbear/releases/dropbear-0.53.1.tar.bz2 ...@@ -35,7 +42,7 @@ url = http://matt.ucc.asn.au/dropbear/releases/dropbear-0.53.1.tar.bz2
configure-options = configure-options =
--prefix=${buildout:parts-directory}/${:_buildout_section_name_} --prefix=${buildout:parts-directory}/${:_buildout_section_name_}
--with-zlib=${zlib:location} --with-zlib=${zlib:location}
CFLAGS="-DENABLE_SINGLEUSER " CFLAGS="-DENABLE_SINGLEUSER -D__DIRTY_NO_SHELL_CHECKING"
environment = environment =
CPPFLAGS =-I${zlib:location}/include CPPFLAGS =-I${zlib:location}/include
...@@ -44,6 +51,7 @@ environment = ...@@ -44,6 +51,7 @@ environment =
patches= patches=
${dropbear-userspace-patch:location}/${dropbear-userspace-patch:filename} ${dropbear-userspace-patch:location}/${dropbear-userspace-patch:filename}
${dropbear-ipv6-patch:location}/${dropbear-ipv6-patch:filename} ${dropbear-ipv6-patch:location}/${dropbear-ipv6-patch:filename}
${dropbear-no-shell-check-patch:location}/${dropbear-no-shell-check-patch:filename}
patch-options= patch-options=
-p1 -p1
diff --git a/svr-auth.c b/svr-auth.c
index 87e3c5e..8b93a22 100644
--- a/svr-auth.c
+++ b/svr-auth.c
@@ -267,6 +267,7 @@ static int checkusername(unsigned char *username, unsigned int userlen) {
usershell = "/bin/sh";
}
+#ifndef __DIRTY_NO_SHELL_CHECKING
/* check the shell is valid. If /etc/shells doesn't exist, getusershell()
* should return some standard shells like "/bin/sh" and "/bin/csh" (this
* is platform-specific) */
@@ -288,6 +289,7 @@ static int checkusername(unsigned char *username, unsigned int userlen) {
goodshell:
endusershell();
+#endif
TRACE(("matching shell"))
TRACE(("uid = %d", ses.authstate.pw_uid))
...@@ -48,7 +48,7 @@ index 87e3c5e..adb2e8b 100644 ...@@ -48,7 +48,7 @@ index 87e3c5e..adb2e8b 100644
+ if (svr_opts.singleuser) { + if (svr_opts.singleuser) {
+ m_free(username); + m_free(username);
+ /* Get the current login of the user running dropbear */ + /* Get the current login of the user running dropbear */
+ username = m_strdup(getlogin()); + username = m_strdup(getpwuid(getuid())->pw_name);
+ } + }
+#endif /* ifdef ENABLE_SINGLEUSER */ +#endif /* ifdef ENABLE_SINGLEUSER */
servicename = buf_getstring(ses.payload, &servicelen); servicename = buf_getstring(ses.payload, &servicelen);
......
[buildout]
extends =
../cmake/buildout.cfg
../glib/buildout.cfg
../pcre/buildout.cfg
../mariadb/buildout.cfg
parts = mydumper
# XXX-Antoine:
# This is really dirty, but it's the only way to install
# mydumper that works
[mydumper]
recipe = slapos.recipe.build
url = http://launchpad.net/mydumper/0.2/0.2.3/+download/mydumper-0.2.3.tar.gz
md5sum = 36e6a1c97a9634a6882ddaac5e2697d5
buildout-bin-dir = ${buildout:bin-directory}
cmake-command = ${cmake:location}/bin/cmake
mysql-config = ${mariadb:location}/bin/mysql_config
doc-dependency = ${mydumper-doc:eggs}
mysqllib = ${mariadb:location}/lib
pkg-config-path = ${glib:location}/lib/pkgconfig/:${pcre:location}/lib/pkgconfig/
libraries = ${zlib:location}/lib/:${glib:location}/lib/:${pcre:location}/lib/:${mariadb:location}/lib/mysql/
includes = ${zlib:location}/include/:${glib:location}/include/:${pcre:location}/include/:${mariadb:location}/include/mysql/
cflags = -I${zlib:location}/include/ -I${glib:location}/include/ -I${pcre:location}/include/ -I${mariadb:location}/include/mysql/
mydumper-patches =
${:_profile_base_location_}/mydumper-remove-warnings-errors.patch 917fea16b5ddea195cfa33fbd9827f57 -p1
slapos_promise =
directory:bin
file:bin/mydumper
file:bin/myloader
script =
import os
url = self.download(self.options['url'], self.options.get('md5sum'))
extract_dir = self.extract(url)
workdir = guessworkdir(extract_dir)
self.applyPatchList(self.options['mydumper-patches'], cwd=workdir)
env['PATH'] = self.options['buildout-bin-dir'] + ':' + env.get('PATH', '')
env['PKG_CONFIG_PATH'] = self.options['pkg-config-path'] + ':' + \
env.get('PKG_CONFIG_PATH', '')
env['CMAKE_INCLUDE_PATH'] = self.options['includes']
env['CMAKE_LIBRARY_PATH'] = self.options['libraries']
env['CFLAGS'] = self.options['cflags']
command_line = [self.options['cmake-command'],
'-DCMAKE_INSTALL_PREFIX=%%s' %% self.options['location'],
'-DMYSQL_CONFIG=%%s' %% self.options['mysql-config'],
'-DCMAKE_C_FLAGS=%%s' %% self.options['cflags'],
'-DCMAKE_INSTALL_RPATH=%%s' %% self.options['libraries'],
'.']
call(command_line, cwd=workdir, env=env)
call(['make'], cwd=workdir, env=env)
call(['make', 'install'], cwd=workdir, env=env)
[mydumper-doc]
recipe = zc.recipe.egg
eggs =
Sphinx
dependent-scripts = true
# XXX-Antoine: here's what I did using hexagonit.recipe.cmmi.
# and it wasn't working !
#[mydumper]
#recipe = hexagonit.recipe.cmmi
#url = http://launchpad.net/mydumper/0.2/0.2.3/+download/mydumper-0.2.3.tar.gz
#md5sum = 36e6a1c97a9634a6882ddaac5e2697d5
#strip-top-level-dir = true
#location = ${buildout:parts-directory}/${:_buildout_section_name_}
#configure-command =
# ${cmake:location}/bin/cmake \
# -DCMAKE_INSTALL_PREFIX=${:location} \
# -DMYSQL_CONFIG=${mariadb:location}/bin/mysql_config \
# -DCMAKE_INCLUDE_PATH=${zlib:location}/include \
# -DCMAKE_LIBRARY_PATH=${zlib:location}/lib \
# .
#environment=
# PATH=$PATH:${buildout:bin-directory}
# PKG_CONFIG_PATH=${glib:location}/lib/pkgconfig/:${pcre:location}/lib/pkgconfig/
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -12,7 +12,7 @@
add_subdirectory(docs)
-set(CMAKE_C_FLAGS "-Wall -Wunused -Wwrite-strings -Wno-strict-aliasing -Wextra -Wshadow -Werror -O3 -g ${MYSQL_CFLAGS}")
+set(CMAKE_C_FLAGS "-Wall -Wunused -Wwrite-strings -Wno-strict-aliasing -Wextra -Wshadow -O3 -g ${MYSQL_CFLAGS}")
include_directories(${MYDUMPER_SOURCE_DIR} ${MYSQL_INCLUDE_DIR} ${GLIB2_INCLUDE_DIR} ${PCRE_INCLUDE_DIR} ${ZLIB_INCLUDE_DIRS})
...@@ -30,6 +30,7 @@ setup(name=name, ...@@ -30,6 +30,7 @@ setup(name=name,
'lxml', # for full blown python interpreter 'lxml', # for full blown python interpreter
'netaddr', # to manipulate on IP addresses 'netaddr', # to manipulate on IP addresses
'setuptools', # namespaces 'setuptools', # namespaces
'inotifyx', # to watch filesystem changes (used in lockfile)
'slapos.core', # uses internally 'slapos.core', # uses internally
# 'slapos.toolbox', # needed for libcloud, cloudmgr, disabled for now # 'slapos.toolbox', # needed for libcloud, cloudmgr, disabled for now
'xml_marshaller', # need to communication with slapgrid 'xml_marshaller', # need to communication with slapgrid
...@@ -39,14 +40,20 @@ setup(name=name, ...@@ -39,14 +40,20 @@ setup(name=name,
zip_safe=True, zip_safe=True,
entry_points={ entry_points={
'zc.buildout': [ 'zc.buildout': [
'apachephp = slapos.recipe.apachephp:Recipe',
'apacheproxy = slapos.recipe.apacheproxy:Recipe',
'apache.zope.backend = slapos.recipe.apache_zope_backend:Recipe', 'apache.zope.backend = slapos.recipe.apache_zope_backend:Recipe',
'certificate_authority = slapos.recipe.certificate_authority:Recipe', 'certificate_authority = slapos.recipe.certificate_authority:Recipe',
'certificate_authority.request = slapos.recipe.certificate_authority:Request', 'certificate_authority.request = slapos.recipe.certificate_authority:Request',
'cron = slapos.recipe.dcron:Recipe', 'cron = slapos.recipe.dcron:Recipe',
'cron.d = slapos.recipe.dcron:Part', 'cron.d = slapos.recipe.dcron:Part',
'davstorage = slapos.recipe.davstorage:Recipe', 'davstorage = slapos.recipe.davstorage:Recipe',
'dropbear = slapos.recipe.dropbear:Recipe',
'dropbear.add_authorized_key = slapos.recipe.dropbear:AddAuthorizedKey',
'dropbear.client = slapos.recipe.dropbear:Client',
'duplicity = slapos.recipe.duplicity:Recipe', 'duplicity = slapos.recipe.duplicity:Recipe',
'erp5scalabilitytestbed = slapos.recipe.erp5scalabilitytestbed:Recipe', 'erp5scalabilitytestbed = slapos.recipe.erp5scalabilitytestbed:Recipe',
'equeue = slapos.recipe.equeue:Recipe',
'erp5testnode = slapos.recipe.erp5testnode:Recipe', 'erp5testnode = slapos.recipe.erp5testnode:Recipe',
'helloworld = slapos.recipe.helloworld:Recipe', 'helloworld = slapos.recipe.helloworld:Recipe',
'generic.cloudooo = slapos.recipe.generic_cloudooo:Recipe', 'generic.cloudooo = slapos.recipe.generic_cloudooo:Recipe',
...@@ -58,19 +65,25 @@ setup(name=name, ...@@ -58,19 +65,25 @@ setup(name=name,
'kvm = slapos.recipe.kvm:Recipe', 'kvm = slapos.recipe.kvm:Recipe',
'libcloud = slapos.recipe.libcloud:Recipe', 'libcloud = slapos.recipe.libcloud:Recipe',
'libcloudrequest = slapos.recipe.libcloudrequest:Recipe', 'libcloudrequest = slapos.recipe.libcloudrequest:Recipe',
'lockfile = slapos.recipe.lockfile:Recipe',
'memcached = slapos.recipe.memcached:Recipe', 'memcached = slapos.recipe.memcached:Recipe',
'generic.memcached = slapos.recipe.generic_memcached:Recipe', 'generic.memcached = slapos.recipe.generic_memcached:Recipe',
'mysql = slapos.recipe.mysql:Recipe', 'mysql = slapos.recipe.mysql:Recipe',
'mydumper = slapos.recipe.mydumper:Recipe',
'generic.mysql = slapos.recipe.generic_mysql:Recipe', 'generic.mysql = slapos.recipe.generic_mysql:Recipe',
'mkdirectory = slapos.recipe.mkdirectory:Recipe', 'mkdirectory = slapos.recipe.mkdirectory:Recipe',
'nbdserver = slapos.recipe.nbdserver:Recipe', 'nbdserver = slapos.recipe.nbdserver:Recipe',
'nosqltestbed = slapos.recipe.nosqltestbed:NoSQLTestBed', 'nosqltestbed = slapos.recipe.nosqltestbed:NoSQLTestBed',
'notifier = slapos.recipe.notifier:Recipe',
'notifier.callback = slapos.recipe.notifier:Callback',
'notifier.notify = slapos.recipe.notifier:Notify',
'lamp = slapos.recipe.lamp:Request', 'lamp = slapos.recipe.lamp:Request',
'lamp.request = slapos.recipe.lamp:Request', 'lamp.request = slapos.recipe.lamp:Request',
'lamp.static = slapos.recipe.lamp:Static', 'lamp.static = slapos.recipe.lamp:Static',
'lamp.simple = slapos.recipe.lamp:Simple', 'lamp.simple = slapos.recipe.lamp:Simple',
'logrotate = slapos.recipe.logrotate:Recipe', 'logrotate = slapos.recipe.logrotate:Recipe',
'logrotate.d = slapos.recipe.logrotate:Part', 'logrotate.d = slapos.recipe.logrotate:Part',
'pbs = slapos.recipe.pbs:Recipe',
'publish = slapos.recipe.publish:Recipe', 'publish = slapos.recipe.publish:Recipe',
'publishurl = slapos.recipe.publishurl:Recipe', 'publishurl = slapos.recipe.publishurl:Recipe',
'proactive = slapos.recipe.proactive:Recipe', 'proactive = slapos.recipe.proactive:Recipe',
...@@ -81,10 +94,14 @@ setup(name=name, ...@@ -81,10 +94,14 @@ setup(name=name,
'siptester = slapos.recipe.siptester:SipTesterRecipe', 'siptester = slapos.recipe.siptester:SipTesterRecipe',
'simplelogger = slapos.recipe.simplelogger:Recipe', 'simplelogger = slapos.recipe.simplelogger:Recipe',
'slaprunner = slapos.recipe.slaprunner:Recipe', 'slaprunner = slapos.recipe.slaprunner:Recipe',
'sshkeys_authority = slapos.recipe.sshkeys_authority:Recipe',
'sshkeys_authority.request = slapos.recipe.sshkeys_authority:Request',
'sphinx= slapos.recipe.sphinx:Recipe', 'sphinx= slapos.recipe.sphinx:Recipe',
'stunnel = slapos.recipe.stunnel:Recipe', 'stunnel = slapos.recipe.stunnel:Recipe',
'testnode = slapos.recipe.testnode:Recipe', 'testnode = slapos.recipe.testnode:Recipe',
'urlparse = slapos.recipe._urlparse:Recipe',
'vifib = slapos.recipe.vifib:Recipe', 'vifib = slapos.recipe.vifib:Recipe',
'waitfor = slapos.recipe.waitfor:Recipe',
'xwiki = slapos.recipe.xwiki:Recipe', 'xwiki = slapos.recipe.xwiki:Recipe',
'zabbixagent = slapos.recipe.zabbixagent:Recipe', 'zabbixagent = slapos.recipe.zabbixagent:Recipe',
'generic.zope = slapos.recipe.generic_zope:Recipe', 'generic.zope = slapos.recipe.generic_zope:Recipe',
......
##############################################################################
#
# 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 urlparse import urlparse
from slapos.recipe.librecipe import GenericBaseRecipe
class Recipe(GenericBaseRecipe):
def _options(self, options):
url = urlparse(options['url'])
def to_str(data):
if data is None:
return ''
return str(data)
options.update(scheme=url.scheme,
username=to_str(url.username),
password=to_str(url.password),
host=to_str(url.hostname),
port=to_str(url.port),
path=url.path.strip('/'),
params=url.params,
query=url.query,
fragment=url.fragment)
def install(self):
return []
##############################################################################
#
# 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 shutil
import os
import signal
from binascii import b2a_uu as uuencode
from slapos.recipe.librecipe import GenericBaseRecipe
class Recipe(GenericBaseRecipe):
def install(self):
path_list = []
# Copy application
shutil.rmtree(self.options['htdocs'])
shutil.copytree(self.options['source'],
self.options['htdocs'])
# Install php.ini
php_ini = self.createFile(os.path.join(self.options['php-ini-dir'],
'php.ini'),
self.substituteTemplate(self.getTemplateFilename('php.ini.in'),
dict(tmp_directory=self.options['tmp-dir']))
)
path_list.append(php_ini)
# Install apache
apache_config = dict(
pid_file=self.options['pid-file'],
lock_file=self.options['lock-file'],
ip=self.options['ip'],
port=self.options['port'],
error_log=self.options['error-log'],
access_log=self.options['access-log'],
document_root=self.options['htdocs'],
php_ini_dir=self.options['php-ini-dir'],
)
httpd_conf = self.createFile(self.options['httpd-conf'],
self.substituteTemplate(self.getTemplateFilename('apache.in'),
apache_config)
)
path_list.append(httpd_conf)
wrapper = self.createPythonScript(self.options['wrapper'],
'slapos.recipe.librecipe.execute.execute',
[self.options['httpd-binary'], '-f', self.options['httpd-conf'],
'-DFOREGROUND']
)
path_list.append(wrapper)
secret_key_filename = os.path.join(self.buildout['buildout']['directory'],
'.php_secret_key')
if not os.path.exists(secret_key_filename):
secret_key = uuencode(os.urandom(45)).strip()
# Remove unsafe characters
secret_key = secret_key.translate(None, '"\'')
with open(secret_key_filename, 'w') as secret_key_file:
secret_key_file.write(secret_key)
else:
with open(secret_key_filename, 'r') as secret_key_file:
secret_key = secret_key_file.read()
application_conf = dict(mysql_database=self.options['mysql-database'],
mysql_user=self.options['mysql-username'],
mysql_password=self.options['mysql-password'],
mysql_host='%s:%s' % (self.options['mysql-host'],
self.options['mysql-port']),
secret_key=secret_key,
)
directory, file_ = os.path.split(self.options['configuration'])
path = self.options['htdocs']
if directory:
path = os.path.join(path, directory)
if not os.path.exists(path):
os.makedirs(path)
if not os.path.isdir(path):
raise OSError("Cannot create %r." % path)
destination = os.path.join(path, file_)
config = self.createFile(destination,
self.substituteTemplate(self.options['template'], application_conf))
path_list.append(config)
if os.path.exists(self.options['pid-file']):
# Reload apache configuration
with open(self.options['pid-file']) as pid_file:
pid = int(pid_file.read().strip(), 10)
os.kill(pid, signal.SIGUSR1) # Graceful restart
return path_list
# Apache static configuration
# Automatically generated
# Basic server configuration
PidFile "%(pid_file)s"
LockFile "%(lock_file)s"
Listen %(ip)s:%(port)s
PHPINIDir %(php_ini_dir)s
ServerAdmin someone@email
DefaultType text/plain
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)s"
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)s" common
# Directory protection
<Directory />
Options FollowSymLinks
AllowOverride None
Order deny,allow
Deny from all
</Directory>
<Directory %(document_root)s>
Options FollowSymLinks
AllowOverride All
Order allow,deny
Allow from all
</Directory>
DocumentRoot %(document_root)s
DirectoryIndex index.html index.php
# List of modules
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
[PHP]
engine = On
safe_mode = Off
expose_php = Off
error_reporting = E_ALL & ~(E_DEPRECATED|E_NOTICE|E_WARNING)
display_errors = On
display_startup_errors = Off
log_errors = On
log_errors_max_len = 1024
ignore_repeated_errors = Off
ignore_repeated_source = Off
session.save_path = "%(tmp_directory)s"
session.auto_start = 0
date.timezone = Europe/Paris
file_uploads = On
upload_max_filesize = 8M
post_max_size = 8M
magic_quotes_gpc=0ff
##############################################################################
#
# 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 signal
from slapos.recipe.librecipe import GenericBaseRecipe
class Recipe(GenericBaseRecipe):
def install(self):
path_list = []
# Install apache
apache_config = dict(
pid_file=self.options['pid-file'],
lock_file=self.options['lock-file'],
ip=self.options['ip'],
port=self.options['port'],
error_log=self.options['error-log'],
access_log=self.options['access-log'],
backend_url=self.options['url'],
)
httpd_conf = self.createFile(self.options['httpd-conf'],
self.substituteTemplate(self.getTemplateFilename('apache.in'),
apache_config)
)
path_list.append(httpd_conf)
wrapper = self.createPythonScript(self.options['wrapper'],
'slapos.recipe.librecipe.execute.execute',
[self.options['httpd-binary'], '-f', self.options['httpd-conf'],
'-DFOREGROUND']
)
path_list.append(wrapper)
if os.path.exists(self.options['pid-file']):
# Reload apache configuration
with open(self.options['pid-file']) as pid_file:
pid = int(pid_file.read().strip(), 10)
os.kill(pid, signal.SIGUSR1) # Graceful restart
return path_list
# Apache static configuration
# Automatically generated
# Basic server configuration
PidFile "%(pid_file)s"
LockFile "%(lock_file)s"
Listen %(ip)s:%(port)s
ServerAdmin someone@email
DefaultType text/plain
TypesConfig conf/mime.types
AddType application/x-compress .Z
AddType application/x-gzip .gz .tgz
# Log configuration
ErrorLog "%(error_log)s"
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)s" common
# Directory protection
<Directory />
Options FollowSymLinks
AllowOverride None
Order deny,allow
Deny from all
</Directory>
ProxyPass / %(backend_url)s
# List of modules
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 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
...@@ -117,7 +117,7 @@ class Request(Recipe): ...@@ -117,7 +117,7 @@ class Request(Recipe):
if os.path.islink(link): if os.path.islink(link):
os.unlink(link) os.unlink(link)
elif os.path.exists(link): elif os.path.exists(link):
raise OSError("%r file should be a symbolic link.") raise OSError("%r file should be a symbolic link." % link)
os.symlink(key, key_file) os.symlink(key, key_file)
os.symlink(certificate, cert_file) os.symlink(certificate, cert_file)
......
...@@ -2,6 +2,7 @@ import os ...@@ -2,6 +2,7 @@ import os
import subprocess import subprocess
import time import time
import ConfigParser import ConfigParser
import uuid
def popenCommunicate(command_list, input=None): def popenCommunicate(command_list, input=None):
...@@ -44,7 +45,7 @@ class CertificateAuthority: ...@@ -44,7 +45,7 @@ class CertificateAuthority:
popenCommunicate([self.openssl_binary, 'req', '-nodes', '-config', popenCommunicate([self.openssl_binary, 'req', '-nodes', '-config',
self.openssl_configuration, '-new', '-x509', '-extensions', self.openssl_configuration, '-new', '-x509', '-extensions',
'v3_ca', '-keyout', self.key, '-out', self.certificate, 'v3_ca', '-keyout', self.key, '-out', self.certificate,
'-days', '10950'], 'Automatic Certificate Authority\n') '-days', '10950'], 'Certificate Authority %s\n' % uuid.uuid1())
except: except:
try: try:
for f in file_list: for f in file_list:
......
...@@ -24,106 +24,88 @@ ...@@ -24,106 +24,88 @@
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# #
############################################################################## ##############################################################################
from slapos.recipe.librecipe import BaseSlapRecipe
import os
import subprocess import subprocess
import pkg_resources import httplib
import zc.buildout import base64
import zc.recipe.egg
import sys
class Recipe(BaseSlapRecipe):
def getTemplateFilename(self, template_name):
return pkg_resources.resource_filename(__name__,
'template/%s' % template_name)
def _install(self):
self.path_list = []
self.requirements, self.ws = self.egg.working_set()
document_root = self.createDataDirectory('www')
apache_config = self.installApache(document_root)
self.setConnectionUrl(scheme='webdavs',
host=apache_config['ip'],
port=apache_config['port'],
auth=(apache_config['user'],
apache_config['password']))
return self.path_list
def installApache(self, document_root, ip=None, port=None):
if ip is None:
ip=self.getGlobalIPv6Address()
if port is None:
port = '9080'
htpasswd_config = self.createHtpasswd()
ssl_config = self.createCertificate(size=2048)
apache_config = dict( from slapos.recipe.librecipe import GenericBaseRecipe
pid_file=os.path.join(self.run_directory, 'httpd.pid'),
lock_file=os.path.join(self.run_directory, 'httpd.lock'), class Recipe(GenericBaseRecipe):
davlock_db=os.path.join(self.run_directory, 'davdb.lock'),
ip=ip, def _options(self, options):
port=port, options['password'] = self.generatePassword()
error_log=os.path.join(self.log_directory, 'httpd-error.log'),
access_log=os.path.join(self.log_directory, 'httpd-access.log'), def install(self):
document_root=document_root, path_list = []
modules_dir=self.options['apache_modules_dir'],
mime_types=self.options['apache_mime_file'], htpasswd_file = self.options['htpasswd-file']
server_root=self.work_directory, # Create or empty the file
email_address='admin@vifib.net', open(htpasswd_file, 'w').close()
htpasswd_file=htpasswd_config['htpasswd_file'], path_list.append(htpasswd_file)
ssl_certificate=ssl_config['certificate'],
ssl_key=ssl_config['key'], user = self.options['user']
) password = self.options['password']
httpd_config_file = self.createConfigurationFile('httpd.conf', subprocess.check_call([self.options['apache-htpasswd'],
self.substituteTemplate(self.getTemplateFilename('httpd.conf.in'), '-bc', htpasswd_file,
apache_config))
self.path_list.append(httpd_config_file)
apache_runner = zc.buildout.easy_install.scripts(
[('httpd', 'slapos.recipe.librecipe.execute', 'execute')],
self.ws, sys.executable, self.wrapper_directory,
arguments=[self.options['apache_binary'],
'-f', httpd_config_file,
'-DFOREGROUND',
]
)[0]
self.path_list.append(apache_runner)
return dict(ip=apache_config['ip'],
port=apache_config['port'],
user=htpasswd_config['user'],
password=htpasswd_config['password']
)
def createHtpasswd(self):
htpasswd = self.createConfigurationFile('htpasswd', '')
self.path_list.append(htpasswd)
password = self.generatePassword()
user = 'user'
subprocess.check_call([self.options['apache_htpasswd'],
'-bc', htpasswd,
user, password user, password
]) ])
return dict(htpasswd_file=htpasswd,
user=user,
password=password) apache_config = dict(
pid_file=self.options['pid-file'],
def createCertificate(self, size=1024, subject='/C=FR/L=Marcq-en-Baroeul/O=Nexedi'): lock_file=self.options['lock-file'],
key_file = os.path.join(self.etc_directory, 'httpd.key') davlock_db=self.options['davdb-lock'],
certificate_file = os.path.join(self.etc_directory, 'httpd.crt') ip=self.options['ip'],
port=self.options['port'],
files = [key_file, certificate_file, ] error_log=self.options['error-log'],
if not all([os.path.exists(f) for f in files]): access_log=self.options['access-log'],
for f in files: document_root=self.options['htdocs'],
if os.path.exists(f): modules_dir=self.options['apache-modules-dir'],
os.unlink(f) mime_types=self.options['apache-mime-file'],
server_root=self.options['root'],
subprocess.check_call([self.options['openssl_binary'], email_address=self.options['email-address'],
'req', '-x509', '-nodes', htpasswd_file=htpasswd_file,
'-newkey', 'rsa:%s' % size, ssl_certificate=self.options['cert-file'],
'-subj', str(subject), ssl_key=self.options['key-file'],
'-out', certificate_file, )
'-keyout', key_file
]) # Create logfiles
for log in [self.options['error-log'], self.options['access-log']]:
return dict(key=key_file, open(log, 'a').close()
certificate=certificate_file)
config_file = self.createFile(self.options['conf-file'],
self.substituteTemplate(self.getTemplateFilename('httpd.conf.in'),
apache_config)
)
path_list.append(config_file)
wrapper = self.createPythonScript(self.options['wrapper'],
'slapos.recipe.librecipe.execute.execute',
[self.options['apache-binary'], '-f', config_file, '-DFOREGROUND'])
path_list.append(wrapper)
promise = self.createPythonScript(self.options['promise'],
__name__ + '.promise',
dict(host=self.options['ip'], port=int(self.options['port']),
user=self.options['user'], password=self.options['password'])
)
path_list.append(promise)
return path_list
def promise(args):
host = args['host']
port = args['port']
user = args['user']
password = args['password']
connection = httplib.HTTPSConnection(host, port)
auth = base64.b64encode('%s:%s' % (user, password))
connection.request('OPTIONS', '/',
headers=dict(
Authorization='Basic %s' % auth,
)
)
connection.getresponse()
return 0
##############################################################################
#
# 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 itertools
from slapos.recipe.librecipe import GenericBaseRecipe
class KnownHostsFile(dict):
def __init__(self, filename):
self._filename = filename
def _load(self):
if os.path.exists(self._filename):
with open(self._filename, 'r') as keyfile:
for line in keyfile:
host, key = [column.strip() for column in line.split(' ', 1)]
self[host] = key
def _dump(self):
with open(self._filename, 'w') as keyfile:
for key, value in self.items():
if key is not None and value is not None:
keyfile.write('%(host)s %(key)s\n' % {'host': key,
'key': value})
def __enter__(self):
self._load()
def __exit__(self, exc_type, exc_value, traceback):
self._dump()
class AuthorizedKeysFile(object):
def __init__(self, filename):
self.filename = filename
def append(self, key):
"""Append the key to the file if the key's not in the file
"""
# Create the file it it does not exist
try:
file_ = os.open(self.filename, os.O_CREAT | os.O_EXCL)
os.close(file_)
except:
pass
with open(self.filename, 'r') as keyfile:
# itertools.imap avoid loading all the authorized_keys file in
# memory which would be counterproductive.
present = (key.strip() in itertools.imap(lambda k: k.strip(),
keyfile))
try:
keyfile.seek(-1, os.SEEK_END)
ended_by_newline = (keyfile.read() == '\n')
except IOError:
ended_by_newline = True
if not present:
with open(self.filename, 'a') as keyfile:
if not ended_by_newline:
keyfile.write('\n')
keyfile.write(key.strip())
class Recipe(GenericBaseRecipe):
def install(self):
path_list = []
dropbear_cmd = [self.options['dropbear-binary']]
# Don't fork into background
dropbear_cmd.append('-F')
# Log on stderr
dropbear_cmd.append('-E')
# Don't display motd
dropbear_cmd.append('-m')
# Disable password login
dropbear_cmd.extend(['-s', '-g'])
# Disable port forwarding
dropbear_cmd.extend(['-j', '-k'])
host = self.options['host']
if ':' in host:
host = '[%s]' % host
port = self.options['port']
binding_address = '%s:%s' % (host, port)
dropbear_cmd.extend(['-p', binding_address])
# Single user mode
dropbear_cmd.append('-n')
if 'dss-keyfile' in self.options:
dropbear_cmd.extend(['-d', self.options['dss-keyfile']])
else:
dropbear_cmd.extend(['-r', self.options['rsa-keyfile']])
env = {}
if 'home' in self.options:
env['DROPBEAR_OVERRIDE_HOME'] = self.options['home']
if 'shell' in self.options:
env['DROPBEAR_OVERRIDE_SHELL'] = self.options['shell']
wrapper = self.createPythonScript(
self.options['wrapper'],
'slapos.recipe.librecipe.execute.executee',
(dropbear_cmd, env, )
)
path_list.append(wrapper)
return path_list
class Client(GenericBaseRecipe):
def install(self):
env = dict()
if 'home' in self.options:
env['HOME'] = self.options['home']
self.createDirectory(self.options['home'], '.ssh')
dropbear_cmd = [self.options['dbclient-binary'], '-T']
if self.optionIsTrue('force-host-key', default=False):
dropbear_cmd.extend(['-y'])
if 'identity-file' in self.options:
dropbear_cmd.extend(['-i', self.options['identity-file']])
wrapper = self.createPythonScript(
self.options['wrapper'],
'slapos.recipe.librecipe.execute.executee',
(dropbear_cmd, env, )
)
return [wrapper]
class AddAuthorizedKey(GenericBaseRecipe):
def install(self):
path_list = []
ssh = self.createDirectory(self.options['home'], '.ssh')
path_list.append(ssh)
authorized_keys = AuthorizedKeysFile(os.path.join(ssh, 'authorized_keys'))
authorized_keys.append(self.options['key'])
return path_list
...@@ -30,15 +30,23 @@ class Recipe(GenericBaseRecipe): ...@@ -30,15 +30,23 @@ class Recipe(GenericBaseRecipe):
def install(self): def install(self):
remote_url = self.options['remote_backup'] remote_url = self.options['remote-backup']
backup_directory = self.options['directory'] backup_directory = self.options['local-directory']
wrapper = self.createPythonScript( cmd = [self.options['duplicity-binary'],]
self.options['wrapper'], options = ['--no-encryption', '--archive-dir', self.options['cache']]
'slapos.recipe.librecipe.execute.execute',
[self.options['duplicity_binary'], '--no-encryption', if self.optionIsTrue('recover', False):
backup_directory, remote_url] options.append('--force')
) # duplicity [options] remote backup
return [wrapper] cmd.extend(options)
cmd.extend([remote_url, backup_directory])
else:
# duplicity [options] local remote
cmd.extend(options)
cmd.extend([backup_directory, remote_url])
wrapper = self.createPythonScript(self.options['wrapper'],
'slapos.recipe.librecipe.execute.execute', cmd)
return [wrapper]
##############################################################################
#
# 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
class Recipe(GenericBaseRecipe):
def install(self):
commandline = [self.options['equeue-binary']]
commandline.extend(['--database', self.options['database']])
commandline.extend(['-l', self.options['log']])
if 'loglevel' in self.options:
commandline.extend(['--loglevel', self.options['loglevel']])
commandline.append(self.options['socket'])
return [self.createPythonScript(
self.options['wrapper'],
'slapos.recipe.librecipe.execute.execute',
commandline,
)]
...@@ -39,6 +39,7 @@ import urlparse ...@@ -39,6 +39,7 @@ import urlparse
# Use to do from slapos.recipe.librecipe import GenericBaseRecipe # Use to do from slapos.recipe.librecipe import GenericBaseRecipe
from generic import GenericBaseRecipe from generic import GenericBaseRecipe
from genericslap import GenericSlapRecipe from genericslap import GenericSlapRecipe
from filehash import filehash
class BaseSlapRecipe: class BaseSlapRecipe:
"""Base class for all slap.recipe.*""" """Base class for all slap.recipe.*"""
......
...@@ -4,6 +4,46 @@ import signal ...@@ -4,6 +4,46 @@ import signal
import subprocess import subprocess
import time import time
import inotifyx
def _wait_files_creation(file_list):
# Etablish a list of directory and subfiles
directories = dict()
for dirname, filename in [os.path.split(f) for f in file_list]:
directories.setdefault(dirname, dict())
directories[dirname][filename] = False
def all_files_exists():
return all([all(files.values()) for files in directories.values()])
fd = inotifyx.init()
try:
# Watch every directories where the file are
watchdescriptors = dict()
for dirname in directories.keys():
wd = inotifyx.add_watch(fd,
dirname,
inotifyx.IN_CREATE | inotifyx.IN_DELETE)
watchdescriptors[wd] = dirname
# Set to True the file wich exists
for dirname, filename in [os.path.split(f) for f in file_list]:
directories[dirname][filename] = os.path.exists(os.path.join(dirname,
filename))
# Let's wait for every file creation
while not all_files_exists():
events_list = inotifyx.get_events(fd)
for event in events_list:
dirname = watchdescriptors[event.wd]
if event.name in directories[dirname]:
# One of watched file was created or deleted
if event.mask & inotifyx.IN_DELETE:
directories[dirname][event.name] = False
else:
directories[dirname][event.name] = True
finally:
os.close(fd)
def execute(args): def execute(args):
"""Portable execution with process replacement""" """Portable execution with process replacement"""
...@@ -14,18 +54,7 @@ def execute_wait(args): ...@@ -14,18 +54,7 @@ def execute_wait(args):
"""Execution but after all files in args[1] exists""" """Execution but after all files in args[1] exists"""
exec_list = list(args[0]) exec_list = list(args[0])
file_list = list(args[1]) file_list = list(args[1])
sleep = 60 _wait_files_creation(file_list)
while True:
ready = True
for f in file_list:
if not os.path.exists(f):
print 'File %r does not exists, sleeping for %s' % (f, sleep)
ready = False
if ready:
break
# XXX: It's the same as ../ca/certificate_authoritiy.py
# We should use pyinotify as well. Or select() on socket.
time.sleep(sleep)
os.execv(exec_list[0], exec_list + sys.argv[1:]) os.execv(exec_list[0], exec_list + sys.argv[1:])
...@@ -49,16 +78,7 @@ def executee_wait(args): ...@@ -49,16 +78,7 @@ def executee_wait(args):
env = os.environ.copy() env = os.environ.copy()
for k,v in environment.iteritems(): for k,v in environment.iteritems():
env[k] = v env[k] = v
sleep = 60 _wait_files_creation(file_list)
while True:
ready = True
for f in file_list:
if not os.path.exists(f):
print 'File %r does not exists, sleeping for %s' % (f, sleep)
ready = False
if ready:
break
time.sleep(sleep)
os.execve(exec_list[0], exec_list + sys.argv[1:], env) os.execve(exec_list[0], exec_list + sys.argv[1:], env)
def sig_handler(signal, frame): def sig_handler(signal, frame):
......
##############################################################################
#
# 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 hashlib
import shutil
import os
DEFAULT_HASH = 'sha512'
class Hash(object):
def __init__(self, name):
self._hash = hashlib.new(name)
def write(self, data):
self._hash.update(data)
def read(self):
return self._hash.hexdigest()
def filehash(filename, type_=DEFAULT_HASH):
if not os.path.isfile(filename):
raise ValueError("%r isn't a file" % filename)
digest = Hash(type_)
with open(filename, 'r') as file_:
shutil.copyfileobj(file_, digest)
return digest.read()
# Home made hashdeep <http://md5deep.sourceforge.net/>
def dirhash(dirname, type_=DEFAULT_HASH):
"""Walk into a directory an return a unique hash for
the directory structure and its files content."""
if not os.path.isdir(dirname):
raise ValueError("%r isn't a directory" % dirname)
digest = Hash(type_)
# List the directory structure
path_list = []
for dirname, dirlist, filelist in os.walk(dirname, followlinks=False):
for filename in filelist:
path_list.append(os.path.join(dirname, filename))
path_list.sort()
for path in path_list:
# Change the hash even if the file or the directory is empty
digest.write(path)
# Update the hash with file content
if os.path.isfile(path):
with open(path, 'r') as file_:
shutil.copyfileobj(file_, digest)
return digest.read()
def pathhash(path, type_=DEFAULT_HASH):
if os.path.isdir(path):
return dirhash(path, type_)
elif os.path.isfile(path):
return filehash(path, type_)
raise ValueError("%r isn't a directory nor a file" % path)
# you can use python -m slapos.recipe.librecipe.filehash [hash] path
if __name__ == '__main__':
import sys
if len(sys.argv) == 1:
raise ValueError("Not enough command line arguments")
if len(sys.argv) == 2:
print sys.argv[1], '-', pathhash(sys.argv[1])
else:
print sys.argv[2], '-', pathhash(sys.argv[2], sys.argv[1])
...@@ -28,6 +28,9 @@ import logging ...@@ -28,6 +28,9 @@ import logging
import os import os
import sys import sys
import inspect import inspect
import re
import urllib
import urlparse
import pkg_resources import pkg_resources
import zc.buildout import zc.buildout
...@@ -39,11 +42,12 @@ class GenericBaseRecipe(object): ...@@ -39,11 +42,12 @@ class GenericBaseRecipe(object):
def __init__(self, buildout, name, options): def __init__(self, buildout, name, options):
"""Recipe initialisation""" """Recipe initialisation"""
self.name = name self.name = name
self.options = options
self.buildout = buildout self.buildout = buildout
self.logger = logging.getLogger(name) self.logger = logging.getLogger(name)
self.options = options.copy() # If _options use self.optionIsTrue
self._options(options) # Options Hook self._options(options) # Options Hook
self.options = options.copy() # Updated options dict
self._ws = self.getWorkingSet() self._ws = self.getWorkingSet()
...@@ -98,9 +102,17 @@ class GenericBaseRecipe(object): ...@@ -98,9 +102,17 @@ class GenericBaseRecipe(object):
path, arguments=arguments)[0] path, arguments=arguments)[0]
return script return script
def createDirectory(self, parent, name, mode=0700):
path = os.path.join(parent, name)
if not os.path.exists(path):
os.mkdir(path, mode)
elif not os.path.isdir(path):
raise OSError("%r exists but is not a directory." % name)
return path
def substituteTemplate(self, template_location, mapping_dict): def substituteTemplate(self, template_location, mapping_dict):
"""Read from file template_location an substitute content with """Read from file template_location an substitute content with
mapping_dict douing a dummy python format.""" mapping_dict doing a dummy python format."""
with open(template_location, 'r') as template: with open(template_location, 'r') as template:
return template.read() % mapping_dict return template.read() % mapping_dict
...@@ -123,3 +135,35 @@ class GenericBaseRecipe(object): ...@@ -123,3 +135,35 @@ class GenericBaseRecipe(object):
if default is not None and optionname not in self.options: if default is not None and optionname not in self.options:
return default return default
return self.isTrueValue(self.options[optionname]) return self.isTrueValue(self.options[optionname])
def unparseUrl(self, scheme, host, path='', params='', query='',
fragment='', port=None, auth=None):
"""Join a url with auth, host, and port.
* auth can be either a login string or a tuple (login, password).
* if the host is an ipv6 address, brackets will be added to surround it.
"""
# XXX-Antoine: I didn't find any standard module to join an url with
# login, password, ipv6 host and port.
# So instead of copy and past in every recipe I factorized it right here.
netloc = ''
if auth is not None:
auth = tuple(auth)
netloc = urllib.quote(str(auth[0])) # Login
if len(auth) > 1:
netloc += ':%s' % urllib.quote(auth[1]) # Password
netloc += '@'
# host is an ipv6 address whithout brackets
if ':' in host and not re.match(r'^\[.*\]$', host):
netloc += '[%s]' % host
else:
netloc += str(host)
if port is not None:
netloc += ':%s' % port
url = urlparse.urlunparse((scheme, netloc, path, params, query, fragment))
return url
...@@ -26,8 +26,6 @@ ...@@ -26,8 +26,6 @@
############################################################################## ##############################################################################
from slapos import slap from slapos import slap
import time import time
import re
import urlparse
from generic import GenericBaseRecipe from generic import GenericBaseRecipe
...@@ -49,15 +47,6 @@ class GenericSlapRecipe(GenericBaseRecipe): ...@@ -49,15 +47,6 @@ class GenericSlapRecipe(GenericBaseRecipe):
self.key_file = slap_connection.get('key-file') self.key_file = slap_connection.get('key-file')
self.cert_file = slap_connection.get('cert-file') self.cert_file = slap_connection.get('cert-file')
# setup auto uninstall/install
self._setupAutoInstallUninstall()
def _setupAutoInstallUninstall(self):
"""By default SlapOS recipes are reinstalled each time"""
# Note: It is possible to create in future subclass which will do no-op in
# this method
self.options['slapos-timestamp'] = str(time.time())
def install(self): def install(self):
self.slap.initializeConnection(self.server_url, self.key_file, self.slap.initializeConnection(self.server_url, self.key_file,
self.cert_file) self.cert_file)
...@@ -80,37 +69,5 @@ class GenericSlapRecipe(GenericBaseRecipe): ...@@ -80,37 +69,5 @@ class GenericSlapRecipe(GenericBaseRecipe):
raise NotImplementedError('Shall be implemented by subclass') raise NotImplementedError('Shall be implemented by subclass')
def setConnectionUrl(self, *args, **kwargs): def setConnectionUrl(self, *args, **kwargs):
url = self._unparseUrl(*args, **kwargs) url = self.unparseUrl(*args, **kwargs)
self.setConnectionDict(dict(url=url)) self.setConnectionDict(dict(url=url))
def _unparseUrl(self, scheme, host, path='', params='', query='',
fragment='', port=None, auth=None):
"""Join a url with auth, host, and port.
* auth can be either a login string or a tuple (login, password).
* if the host is an ipv6 address, brackets will be added to surround it.
"""
# XXX-Antoine: I didn't find any standard module to join an url with
# login, password, ipv6 host and port.
# So instead of copy and past in every recipe I factorized it right here.
netloc = ''
if auth is not None:
auth = tuple(auth)
netloc = str(auth[0]) # Login
if len(auth) > 1:
netloc += ':%s' % auth[1] # Password
netloc += '@'
# host is an ipv6 address whithout brackets
if ':' in host and not re.match(r'^\[.*\]$', host):
netloc += '[%s]' % host
else:
netloc += str(host)
if port is not None:
netloc += ':%s' % port
url = urlparse.urlunparse((scheme, netloc, path, params, query, fragment))
return url
##############################################################################
#
# 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 inotifyx
def subfiles(directory):
"""Return the list of subfiles of a directory, and wait for the newly created
ones.
CAUTION : *DONT TRY TO CONVERT THE RESULT OF THIS FUNCTION INTO A LIST !
ALWAYS ITERATE OVER IT !!!*"""
watchfd = inotifyx.init()
inotifyx.add_watch(watchfd, directory, inotifyx.IN_CREATE)
try:
subfiles = set(os.listdir(directory))
subfiles |= set([file_.name for file_ in inotifyx.get_events(watchfd, 0)])
while True:
for file_ in subfiles:
yield os.path.join(directory, file_)
subfiles = [file_.name for file_ in inotifyx.get_events(watchfd)]
finally:
os.close(watchfd)
##############################################################################
#
# 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 inotifyx
from slapos.recipe.librecipe import GenericBaseRecipe
class LockFile(object):
class LockException(Exception):
pass
def __init__(self, filename, wait=True, exit=False):
self.filename = filename
if wait:
self.callback = lambda: self.waitDeletion()
elif not exit:
self.callback = lambda: self.raiseException()
else:
self.callback = lambda: sys.exit(1)
def raiseException(self):
raise LockFile.LockException("Not able to lock the file")
def waitDeletion(self):
inotify_fd = inotifyx.init()
try:
inotifyx.add_watch(inotify_fd, self.filename, inotifyx.IN_DELETE)
inotifyx.get_events(inotify_fd)
except IOError: # add_watch failed
pass
finally:
os.close(inotify_fd)
self.__enter__()
def __enter__(self):
try:
# Atomic file acquisition
self._fd = os.open(self.filename, os.O_CREAT | os.O_EXCL)
except OSError:
self.callback()
def __exit__(self, exc_type, exc_value, traceback):
os.close(self._fd)
os.unlink(self.filename)
def locked_run(args):
with LockFile(args['filename'], wait=args['wait'], exit=True):
subprocess.check_call([args['binary']])
class Recipe(GenericBaseRecipe):
def install(self):
wrapper = self.createPythonScript(self.options['wrapper'],
__name__ + '.locked_run',
dict(
filename=self.options['lock-file'],
wait=self.optionIsTrue('wait', False),
binary=self.options['binary'],
)
)
return [wrapper]
##############################################################################
#
# 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 subprocess
from slapos.recipe.librecipe import GenericBaseRecipe
def dump(args):
mydumper_cmd = [args['mydumper']]
mydumper_cmd.extend(['-B', args['database']])
if args['socket'] is not None:
mydumper_cmd.extend(['-S', args['socket']])
else:
mydumper_cmd.extend(['-h', args['host']])
mydumper_cmd.etxned(['-P', args['port']])
mydumper_cmd.extend(['-u', args['user']])
if args['password'] is not None:
mydumper_cmd.extend(['-p', args['password']])
if args['compression']:
mydumper_cmd.append('--compress')
if args['rows'] is not None:
mydumper_cmd.extend(['-r', args['rows']])
mydumper_cmd.extend(['-o', args['directory']])
subprocess.check_call(mydumper_cmd)
def do_import(args):
mydumper_cmd = [args['mydumper']]
mydumper_cmd.extend(['-B', args['database']])
if args['socket'] is not None:
mydumper_cmd.extend(['-S', args['socket']])
else:
mydumper_cmd.extend(['-h', args['host']])
mydumper_cmd.etxned(['-P', args['port']])
mydumper_cmd.extend(['-u', args['user']])
if args['password'] is not None:
mydumper_cmd.extend(['-p', args['password']])
mydumper_cmd.append('--overwrite-tables')
mydumper_cmd.extend(['-d', args['directory']])
subprocess.check_call(mydumper_cmd)
class Recipe(GenericBaseRecipe):
def install(self):
# Host or socket should be defined
try:
self.options['host']
except:
self.options['socket']
config = dict(database=self.options['database'],
socket=self.options.get('socket'),
host=self.options.get('host'),
port=self.options.get('port', 3306),
directory=self.options['backup-directory'],
user=self.options['user'],
password=self.options.get('password'),
)
name = __name__
if self.optionIsTrue('import', False):
config.update(mydumper=self.options['myloader-binary'])
name += '.do_import'
else:
config.update(mydumper=self.options['mydumper-binary'],
compression=self.optionIsTrue('compression', default=False),
rows=self.options.get('rows'),
)
name += '.dump'
wrapper = self.createPythonScript(self.options['wrapper'],
name,
config)
return [wrapper]
...@@ -24,8 +24,12 @@ ...@@ -24,8 +24,12 @@
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# #
############################################################################## ##############################################################################
from slapos.recipe.librecipe import GenericBaseRecipe
import os import os
import sys
import subprocess
from slapos.recipe.librecipe import GenericBaseRecipe
from slapos.recipe.librecipe import filehash
class Recipe(GenericBaseRecipe): class Recipe(GenericBaseRecipe):
...@@ -44,7 +48,6 @@ class Recipe(GenericBaseRecipe): ...@@ -44,7 +48,6 @@ class Recipe(GenericBaseRecipe):
pid_file=self.options['pid-file'], pid_file=self.options['pid-file'],
socket=self.options['socket'], socket=self.options['socket'],
error_log=self.options['error-log'], error_log=self.options['error-log'],
slow_query_log=self.options['slow-query-log'],
mysql_database=self.options['database'], mysql_database=self.options['database'],
mysql_user=self.options['user'], mysql_user=self.options['user'],
mysql_password=self.options['password'], mysql_password=self.options['password'],
...@@ -109,36 +112,24 @@ class Recipe(GenericBaseRecipe): ...@@ -109,36 +112,24 @@ class Recipe(GenericBaseRecipe):
path_list.append(mysqld) path_list.append(mysqld)
# backup configuration # backup configuration
mysqldump_binary = self.options['mysqldump-binary'] if self.optionIsTrue('backup', default=False):
backup_directory = self.options['backup-directory'] backup_script = self.createPythonScript(
pending_backup_dir = self.options['backup-pending-directory'] self.options['backup-script'],
dump_filename = self.options['dumpname'] '%s.do_backup' % __name__,
dict(
mysqldump_cmd = [mysqldump_binary, mydumper_binary=self.options['mydumper-binary'],
mysql_conf['mysql_database'], database=mysql_conf['mysql_database'],
'-u', 'root', socket=mysql_conf['socket'],
'-S', mysql_conf['socket'].strip(), backup_directory=self.options['backup-directory']
'--single-transaction', '--opt', ),
] )
dump_file = os.path.join(backup_directory, dump_filename) path_list.append(backup_script)
tmpdump_file = os.path.join(pending_backup_dir, dump_filename)
backup_script = self.createPythonScript(
self.options['backup-script'],
'%s.backup.do_backup' % __name__,
{
'mysqldump': mysqldump_cmd,
'gzip': self.options['gzip-binary'],
'tmpdump': tmpdump_file,
'dumpfile': dump_file,
},
)
path_list.append(backup_script)
# Recovering backup # Recovering backup
if self.optionIsTrue('recovering', default=False): if self.optionIsTrue('recovering', default=False):
recovering_script = self.createPythonScript( recovering_script = self.createPythonScript(
self.options['recovering-wrapper'], self.options['recovering-wrapper'],
'%s.recover.import_remote_dump' % __name__, '%s.import_dump' % __name__,
{ {
'lock_file': os.path.join(self.work_directory, 'lock_file': os.path.join(self.work_directory,
'import_done'), 'import_done'),
...@@ -156,3 +147,47 @@ class Recipe(GenericBaseRecipe): ...@@ -156,3 +147,47 @@ class Recipe(GenericBaseRecipe):
return path_list return path_list
# Replace zcat dump.sql.gz | mysql
def import_dump(args):
# Get data from kwargs
cache_file = args['cache_file']
database = args['database']
mysql_binary = args['mysql_binary']
mysql_socket = args['mysql_socket']
dump_file = args['dump_file']
zcat_binary = args['zcat_binary']
sha512sum = filehash(dump_file)
with open(cache_file, 'r') as cache_fileobj:
last_sha512sum = cache_fileobj.read().strip()
if sha512sum != last_sha512sum:
zcat = subprocess.Popen([zcat_binary, dump_file], stdout=subprocess.PIPE)
mysql = subprocess.Popen([mysql_binary, '--socket=%s' % mysql_socket, '-D',
database, '-u', 'root'], stdin=zcat.stdout)
zcat.stdout.close()
returncode = mysql.wait()
if returncode == 0:
with open(cache_file, 'w') as cache_fileobj:
cache_fileobj.write(sha512sum)
sys.exit(returncode)
def promise(args):
# This is not a dependency of slapos.cookbook, because it shall be runned
# in a python environment having mysql-python
import MySQLdb
user = args['user']
password = args['password']
db = args['db']
host = args['host']
port = args['port']
db = MySQLdb.connect(host=host, port=port, user=user, passwd=password,
db=db)
cursor = db.cursor()
cursor.close()
import subprocess import subprocess
import os import os
# Replace mysqldump | gzip > tmpdump && mv -f tmpdump dumpfile
def do_backup(kwargs):
mysqldump_cmd = kwargs['mysqldump']
gzip_bin = kwargs['gzip']
tmpdump = kwargs['tmpdump']
dumpfile = kwargs['dumpfile']
# mysqldump | gzip > tmpdump
with open(tmpdump, 'w') as output:
mysqldump = subprocess.Popen(mysqldump_cmd,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
gzip = subprocess.Popen([gzip_bin],
stdin=mysqldump.stdout,
stdout=output,
stderr=subprocess.STDOUT)
mysqldump.stdout.close()
if gzip.wait() != 0:
raise ValueError("Gzip return a non zero value.")
os.rename(tmpdump, dumpfile)
import os
import sys
import time
def catdatefile(args):
directory = args[0]
try:
suffix = args[1]
except IndexError:
suffix = '.log'
f = open(os.path.join(directory,
time.strftime('%Y-%m-%d.%H:%M.%s') + suffix), 'aw')
for line in sys.stdin.read():
f.write(line)
f.close()
import sys
import os
import time
import subprocess
def import_remote_dump(kwargs):
# Get data from kwargs
lock_file = kwargs['lock_file']
database = kwargs['database']
mysql_binary = kwargs['mysql_binary']
mysql_socket = kwargs['mysql_socket']
duplicity_binary = kwargs['duplicity_binary']
remote_backup = kwargs['remote_backup']
local_directory = kwargs['local_directory']
dump_name = kwargs['dump_name']
zcat_binary = kwargs['zcat_binary']
# The script start really here
if os.path.exists(lock_file):
sys.exit(127)
while subprocess.call([mysql_binary, '--socket=%s' % mysql_socket,
'-u', 'root', '-e', 'use %s;' % database]) != 0:
time.sleep(10)
subprocess.check_call([duplicity_binary, 'restore', '--no-encryption',
remote_backup, local_directory])
zcat = subprocess.Popen([zcat_binary, os.path.join(local_directory,
dump_name)],
stdout=subprocess.PIPE)
mysql = subprocess.Popen([mysql_binary, '--socket=%s' % mysql_socket,
'-D', database, '-u', 'root'],
stdin=zcat.stdout)
zcat.stdout.close()
returncode = mysql.poll()
if returncode == 0:
open(lock_file, 'w').close() # Just a touch
sys.exit(returncode)
...@@ -15,8 +15,6 @@ socket = %(socket)s ...@@ -15,8 +15,6 @@ socket = %(socket)s
datadir = %(data_directory)s datadir = %(data_directory)s
pid-file = %(pid_file)s pid-file = %(pid_file)s
log-error = %(error_log)s log-error = %(error_log)s
slow_query_log
slow_query_log_file = %(slow_query_log)s
long_query_time = 5 long_query_time = 5
max_allowed_packet = 128M max_allowed_packet = 128M
query_cache_size = 32M query_cache_size = 32M
......
##############################################################################
#
# 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 hashlib import sha512
from slapos.recipe.librecipe import GenericBaseRecipe
class Recipe(GenericBaseRecipe):
def install(self):
commandline = [self.options['server-binary']]
commandline.extend(['--callbacks', self.options['callbacks']])
commandline.extend(['--feeds', self.options['feeds']])
commandline.extend(['--equeue-socket', self.options['equeue-socket']])
commandline.append(self.options['host'])
commandline.append(self.options['port'])
return [self.createPythonScript(self.options['wrapper'],
'slapos.recipe.librecipe.execute.execute',
commandline)]
class Callback(GenericBaseRecipe):
def createCallback(self, notification_id, callback):
callback_id = sha512(notification_id).hexdigest()
callback = self.createFile(os.path.join(self.options['callbacks'],
callback_id),
callback)
return callback
def install(self):
return [self.createCallback(self.options['on-notification-id'],
self.options['callback'])]
class Notify(GenericBaseRecipe):
def createNotifier(self, notifier_binary, executable, wrapper, **kwargs):
if not os.path.exists(kwargs['log']):
# Just a touch
open(kwargs['log'], 'w').close()
commandline = [notifier_binary,
'-l', kwargs['log'],
'--title', kwargs['title'],
'--feed', kwargs['feed_url'],
'--notification-url', kwargs['notification_url'],
executable]
return self.createPythonScript(wrapper,
'slapos.recipe.librecipe.execute.execute',
[str(i) for i in commandline])
def install(self):
feedurl = self.unparseUrl(scheme='http', host=self.options['host'],
port=self.options['port'],
path='/get/%s' % self.options['name'])
script = self.createNotifier(
self.options['notifier-binary'],
wrapper=self.options['wrapper'],
executable=self.options['executable'],
log=os.path.join(self.options['feeds'], self.options['name']),
title=self.options['title'],
notification_url=self.options['notify'],
feed_url=feedurl,
)
return [script]
##############################################################################
#
# 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 json import loads as unjson
from hashlib import sha512
from urlparse import urlparse
import os
import subprocess
import sys
import signal
import inspect
from slapos.recipe.librecipe import GenericSlapRecipe
from slapos.recipe.dropbear import KnownHostsFile
from slapos.recipe.notifier import Notify
from slapos.recipe.notifier import Callback
from slapos import slap as slapmodule
def promise(args):
def failed_ssh(partition, ssh):
# Bad python 2 syntax, looking forward python 3 to have print(file=)
print >> sys.stderr, "SSH Connection failed"
try:
ssh.terminate()
except:
pass
partition.bang("SSH Connection failed. rdiff-backup is unusable.")
def sigterm_handler(signum, frame):
# Walk up in the stack to get promise local
# variables
ssh = None
for upper_frame in inspect.getouterframes(frame):
# Use promise.func_name insteand of 'promise' in order to be
# detected by editor if promise func name change.
# Else, it's hard to debug this kind of error.
if upper_frame[3] == promise.func_name:
try:
partition = upper_frame[0].f_locals['partition']
ssh = upper_frame[0].f_locals['ssh']
except KeyError:
raise SystemExit("SIGTERM Send too soon.")
break
# If ever promise function wasn't found in the stack.
if ssh is None:
raise SystemExit
failed_ssh(partition, ssh)
signal.signal(signal.SIGTERM, sigterm_handler)
slap = slapmodule.slap()
slap.initializeConnection(args['server_url'],
key_file=args.get('key_file'), cert_file=args.get('cert_file'))
partition = slap.registerComputerPartition(args['computer_id'],
args['partition_id'])
# Rdiff Backup protocol quit command
quitcommand = 'q' + chr(255) + chr(0) * 7
ssh_cmdline = [args['ssh_client'], '%(user)s@%(host)s/%(port)s' % args]
ssh = subprocess.Popen(ssh_cmdline, stdin=subprocess.PIPE,
stdout=open(os.devnull), stderr=open(os.devnull))
ssh.stdin.write(quitcommand)
ssh.stdin.flush()
ssh.stdin.close()
ssh.wait()
if ssh.poll() is None:
return 1
if ssh.returncode != 0:
failed_ssh(partition, ssh)
return ssh.returncode
class Recipe(GenericSlapRecipe, Notify, Callback):
def add_slave(self, entry, known_hosts_file):
path_list = []
url = entry.get('url')
if url is None:
url = ''
# We assume that thanks to sha512 there's no collisions
url_hash = sha512(url).hexdigest()
name_hash = sha512(entry['name']).hexdigest()
promise_path = os.path.join(self.options['promises-directory'],
url_hash)
parsed_url = urlparse(url)
promise_dict = self.promise_base_dict.copy()
promise_dict.update(user=parsed_url.username,
host=parsed_url.hostname,
port=parsed_url.port)
promise = self.createPythonScript(promise_path,
__name__ + '.promise',
promise_dict)
path_list.append(promise)
host = parsed_url.hostname
known_hosts_file[host] = entry['server-key']
remote_schema = '%(ssh)s -p %%s %(user)s@%(host)s' % \
{
'ssh': self.options['sshclient-binary'],
'user': parsed_url.username,
'host': parsed_url.hostname,
}
command = [self.options['rdiffbackup-binary']]
command.extend(['--remote-schema', remote_schema])
remote_directory = '%(port)s::%(path)s' % {'port': parsed_url.port,
'path': parsed_url.path}
local_directory = self.createDirectory(self.options['directory'],
name_hash)
if entry['type'] == 'push':
command.extend(['--restore-as-of', 'now'])
command.append('--force')
command.extend([local_directory, remote_directory])
else:
command.extend([remote_directory, local_directory])
wrapper_basepath = os.path.join(self.options['wrappers-directory'],
url_hash)
wrapper_path = wrapper_basepath
if 'notify' in entry:
wrapper_path = '%s_raw' % wrapper_basepath
wrapper = self.createPythonScript(
wrapper_path,
'slapos.recipe.librecipe.execute.execute',
[str(i) for i in command]
)
path_list.append(wrapper)
if 'notify' in entry:
feed_url = '%s/get/%s' % (self.options['notifier-url'],
entry['notification-id'])
wrapper = self.createNotifier(
self.options['notifier-binary'],
wrapper=wrapper_basepath,
executable=wrapper_path,
log=os.path.join(self.options['feeds'], entry['notification-id']),
title=entry.get('title', 'Untitled'),
notification_url=entry['notify'],
feed_url=feed_url,
)
path_list.append(wrapper)
#self.setConnectionDict(dict(feed_url=feed_url), entry['slave_reference'])
if 'on-notification' in entry:
path_list.append(self.createCallback(str(entry['on-notification']),
wrapper))
else:
cron_entry = os.path.join(self.options['cron-entries'], url_hash)
with open(cron_entry, 'w') as cron_entry_file:
cron_entry_file.write('%s %s' % (entry['frequency'], wrapper))
path_list.append(cron_entry)
return path_list
def _install(self):
path_list = []
if self.optionIsTrue('client', True):
self.logger.info("Client mode")
slap_connection = self.buildout['slap-connection']
self.promise_base_dict = dict(
server_url=slap_connection['server-url'],
computer_id=slap_connection['computer-id'],
cert_file=slap_connection.get('cert-file'),
key_file=slap_connection.get('key-file'),
partition_id=slap_connection['partition-id'],
ssh_client=self.options['sshclient-binary'],
)
slaves = unjson(self.options['slave-instance-list'])
known_hosts = KnownHostsFile(self.options['known-hosts'])
with known_hosts:
for slave in slaves:
path_list.extend(self.add_slave(slave, known_hosts))
else:
command = [self.options['rdiffbackup-binary']]
self.logger.info("Server mode")
command.extend(['--restrict', self.options['path']])
command.append('--server')
wrapper = self.createPythonScript(
self.options['wrapper'],
'slapos.recipe.librecipe.execute.execute',
command)
path_list.append(wrapper)
return path_list
...@@ -31,8 +31,10 @@ from slapos.recipe.librecipe import GenericSlapRecipe ...@@ -31,8 +31,10 @@ from slapos.recipe.librecipe import GenericSlapRecipe
class Recipe(GenericSlapRecipe): class Recipe(GenericSlapRecipe):
def _install(self): def _install(self):
publish_dict = dict() publish_dict = dict()
for k, v in self.options.iteritems(): options = self.options.copy()
if k.startswith('url'): del options['recipe']
publish_dict[k] = v
for k, v in options.iteritems():
publish_dict[k] = v
self.setConnectionDict(publish_dict) self.setConnectionDict(publish_dict)
return [] return []
...@@ -56,10 +56,10 @@ class Recipe(GenericSlapRecipe): ...@@ -56,10 +56,10 @@ class Recipe(GenericSlapRecipe):
if option in self.options: if option in self.options:
self.urlparts[option] = self.options[option] self.urlparts[option] = self.options[option]
if 'user' in self.options: if 'username' in self.options:
self.urlparts.update(auth=(self.options['user'],)) self.urlparts.update(auth=(self.options['username'],))
if 'password' in self.options: if 'password' in self.options:
self.urlparts.update(auth=(self.options['user'], self.urlparts.update(auth=(self.options['username'],
self.options['password'])) self.options['password']))
self.setConnectionUrl(**self.urlparts) self.setConnectionUrl(**self.urlparts)
......
...@@ -25,7 +25,6 @@ ...@@ -25,7 +25,6 @@
# #
############################################################################## ##############################################################################
import logging import logging
import os
from slapos import slap as slapmodule from slapos import slap as slapmodule
...@@ -49,6 +48,10 @@ class Recipe(object): ...@@ -49,6 +48,10 @@ class Recipe(object):
if 'name' not in options: if 'name' not in options:
options['name'] = name options['name'] = name
self.isSlave = False
if 'slave' in options:
self.isSlave = options['slave'].lower() in ['y', 'yes', 'true', '1']
self.return_parameters = [] self.return_parameters = []
if 'return' in options: if 'return' in options:
self.return_parameters = [str(parameter).strip() self.return_parameters = [str(parameter).strip()
...@@ -73,16 +76,21 @@ class Recipe(object): ...@@ -73,16 +76,21 @@ class Recipe(object):
options['config-%s' % config_parameter] options['config-%s' % config_parameter]
instance = self.request(options['software-url'], software_type, instance = self.request(options['software-url'], software_type,
options['name'], partition_parameter_kw=partition_parameter_kw, name, partition_parameter_kw=partition_parameter_kw,
filter_kw=filter_kw) filter_kw=filter_kw, shared=self.isSlave)
self.failed = None
for param in self.return_parameters: for param in self.return_parameters:
try: try:
options['connection-%s' % param] = instance.getConnectionParameter(param) options['connection-%s' % param] = str(instance.getConnectionParameter(param))
except slapmodule.NotFoundError: except slapmodule.NotFoundError:
options['connection-%s' % param] = '' options['connection-%s' % param] = ''
if self.failed is None:
self.failed = param
def install(self): def install(self):
if self.failed is not None:
raise KeyError("Connection parameter %r not found." % self.failed)
return [] return []
update = install update = install
...@@ -24,31 +24,25 @@ ...@@ -24,31 +24,25 @@
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# #
############################################################################## ##############################################################################
import shutil
import os
import sys import sys
import time import time
from slapos.recipe.librecipe import GenericBaseRecipe from slapos.recipe.librecipe import GenericBaseRecipe
def log(args): def log(args):
directory, suffix = args prefix = time.strftime('%Y-%m-%d.%H:%M.%s:')
filename = time.strftime('%Y-%m-%d.%H:%M.%s') + suffix with open(args['filename'], 'aw') as logfile:
with open(os.path.join(directory, filename), 'aw') as logfile: for line in sys.stdin:
shutil.copyfileobj(sys.stdin, logfile) print >> logfile, prefix, line,
print >> logfile, prefix, '------------------------'
class Recipe(GenericBaseRecipe): class Recipe(GenericBaseRecipe):
def install(self): def install(self):
self.logger.info("Simple logger installation") wrapper = self.options['wrapper']
binary = self.options['binary'] log = self.options['log']
output = self.options['output']
suffix = self.options.get('suffix', '.log')
script = self.createPythonScript(binary,
'slapos.recipe.simplelogger.log',
arguments=[output, suffix])
self.logger.debug("Logger script created at : %r", script)
self.logger.info("Simple logger installed.")
script = self.createPythonScript(wrapper,
__name__ + '.log',
arguments=dict(filename=log))
return [script] return [script]
...@@ -29,6 +29,7 @@ import os ...@@ -29,6 +29,7 @@ import os
import sys import sys
import copy import copy
from ConfigParser import ConfigParser from ConfigParser import ConfigParser
import json
import subprocess import subprocess
import slapos.slap import slapos.slap
import netaddr import netaddr
...@@ -82,7 +83,7 @@ class Recipe: ...@@ -82,7 +83,7 @@ class Recipe:
if 'default' in self.options: if 'default' in self.options:
software_type = 'default' software_type = 'default'
else: else:
raise zc.buildout.UserError("This software type isn't mapped. And" raise zc.buildout.UserError("This software type isn't mapped. And "
"there's no default software type.") "there's no default software type.")
instance_file_path = self.options[software_type] instance_file_path = self.options[software_type]
...@@ -95,18 +96,20 @@ class Recipe: ...@@ -95,18 +96,20 @@ class Recipe:
with open(instance_file_path) as instance_path: with open(instance_file_path) as instance_path:
buildout.readfp(instance_path) buildout.readfp(instance_path)
buildout.set('buildout', 'installed', buildout.set('buildout', 'installed', '.installed-%s.cfg' % self.name)
'.installed-%s.cfg' % software_type)
if not buildout.has_section('slap-parameter'): if not buildout.has_section('slap-parameter'):
buildout.add_section('slap-parameter') buildout.add_section('slap-parameter')
for parameter, value in self.parameter_dict.items(): for parameter, value in self.parameter_dict.items():
buildout.set('slap-parameter', parameter, value) if isinstance(value, str):
buildout.set('slap-parameter', parameter, value)
else:
buildout.set('slap-parameter', parameter, json.dumps(value))
buildout.add_section('slap-network-information') buildout.add_section('slap-network-information')
buildout.set('slap-network-information', 'local-ipv4', buildout.set('slap-network-information', 'local-ipv4',
self.getLocalIPv4Address()) self.getLocalIPv4Address())
buildout.set('slap-network-information', 'global-ipv6', buildout.set('slap-network-information', 'global-ipv6',
self.getGlobalIPv6Address()) self.getGlobalIPv6Address())
# Copy/paste slap_connection # Copy/paste slap_connection
...@@ -118,7 +121,7 @@ class Recipe: ...@@ -118,7 +121,7 @@ class Recipe:
work_directory = os.path.abspath(self.buildout['buildout'][ work_directory = os.path.abspath(self.buildout['buildout'][
'directory']) 'directory'])
buildout_filename = os.path.join(work_directory, buildout_filename = os.path.join(work_directory,
'buildout-%s.cfg' % software_type) 'buildout-%s.cfg' % self.name)
with open(buildout_filename, 'w') as buildout_file: with open(buildout_filename, 'w') as buildout_file:
buildout.write(buildout_file) buildout.write(buildout_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 json
import hashlib
import os
import subprocess
import re
from slapos.recipe.librecipe import GenericBaseRecipe
from slapos.recipe.librecipe.inotify import subfiles
# This authority only works with dropbear sshkey generator
def sshkeys_authority(args):
requests_directory = args['requests']
keygen_binary = args['sshkeygen']
for request_filename in subfiles(requests_directory):
with open(request_filename) as request_file:
request = json.load(request_file)
key_type = request.get('type', 'rsa')
size = str(request.get('size', 2048))
try:
private_key = request['private_key']
public_key = request['public_key']
except KeyError:
break
if not os.path.exists(private_key):
if os.path.exists(public_key):
os.unlink(public_key)
keygen_cmd = [keygen_binary, '-t', key_type, '-f', private_key,
'-s', size]
# If the keygeneration return an non-zero status, it means there's a
# big problem. Let's exit in this case
subprocess.check_call(keygen_cmd, env=os.environ.copy())
if not os.path.exists(public_key):
keygen_cmd = [keygen_binary, '-f', private_key, '-y']
keygen = subprocess.Popen(keygen_cmd, stdout=subprocess.PIPE,
stdin=subprocess.PIPE,
stderr=subprocess.STDOUT,
env=os.environ.copy())
keygen.stdin.flush()
keygen.stdin.close()
# If the keygeneration return an non-zero status, it means there's a
# big problem. Let's exit in this case
if keygen.wait() != 0:
raise subprocess.CalledProcessError("%r returned a non-zero status" % \
' '.join(keygen_cmd))
public_key_value = ''
for line in keygen.stdout:
# Perl programming !
# Don't worry, just regex to detect the ssh public key line
matchresult = re.match(r'ssh-.*?=+', line)
if matchresult:
public_key_value = matchresult.group(0)
break
with open(public_key, 'w') as public_key_file:
public_key_file.write(public_key_value)
class Recipe(GenericBaseRecipe):
def install(self):
args = dict(
requests=self.options['request-directory'],
sshkeygen=self.options['keygen-binary'],
)
wrapper = self.createPythonScript(self.options['wrapper'],
__name__ + '.sshkeys_authority', args)
return [wrapper]
class Request(GenericBaseRecipe):
def _options(self, options):
if 'name' not in options:
options['name'] = self.name
keys_directory = options['keys-directory']
self.private_key = os.path.join(keys_directory,
hashlib.sha256(options['name']).hexdigest())
self.public_key = self.private_key + '.pub'
if os.path.exists(self.public_key):
with open(self.public_key) as key:
options['public-key-value'] = key.read()
else:
options['public-key-value'] = ''
def install(self):
requests_directory = self.options['request-directory']
request_file = os.path.join(requests_directory, self.options['name'])
request = dict(
private_key=self.private_key,
public_key=self.public_key,
)
if 'size' in self.options:
request.update(size=int(self.options['size'], 10))
if 'type' in self.options:
request.update(type=self.options['type'])
with open(request_file, 'w') as file_:
json.dump(request, file_)
public_key_link, private_key_link = (self.options['public-key'],
self.options['private-key'],
)
# XXX: Copy and past from certificate_authority/__init__.py:Request
# We should factorize that
for link in [public_key_link, private_key_link]:
if os.path.islink(link):
os.unlink(link)
elif os.path.exists(link):
raise OSError("%r should be a symbolic link." % link)
os.symlink(self.public_key, public_key_link)
os.symlink(self.private_key, private_key_link)
# end-XXX
wrapper = self.createPythonScript(
self.options['wrapper'],
'slapos.recipe.librecipe.execute.execute_wait',
[ [self.options['executable']],
[self.private_key, self.public_key] ])
return [request_file, wrapper, public_key_link, private_key_link]
...@@ -24,22 +24,24 @@ ...@@ -24,22 +24,24 @@
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# #
############################################################################## ##############################################################################
import itertools import os
import signal
import zc.buildout import errno
from slapos.recipe.librecipe import GenericBaseRecipe from slapos.recipe.librecipe import GenericBaseRecipe
def post_rotate(args):
pid_file = args['pid_file']
if os.path.exist(pid_file):
with open(pid_file, 'r') as file_:
pid = file_.read().strip()
os.kill(pid, signal.SIGUSR1)
class Recipe(GenericBaseRecipe): class Recipe(GenericBaseRecipe):
def _options(self, options): def install(self):
self.types = ['local', 'remote'] path_list = []
self.datas = ['address', 'port']
for type_ in self.types:
for data in self.datas:
opt = '%s-%s' % (type_, data)
if opt not in options:
raise zc.buildout.UserError("No %s for %s connections." % (data, type_))
self.isClient = self.optionIsTrue('client', default=False) self.isClient = self.optionIsTrue('client', default=False)
if self.isClient: if self.isClient:
...@@ -47,25 +49,15 @@ class Recipe(GenericBaseRecipe): ...@@ -47,25 +49,15 @@ class Recipe(GenericBaseRecipe):
else: else:
self.logger.info("Server mode") self.logger.info("Server mode")
if 'name' not in options:
options['name'] = self.name
def install(self):
path_list = []
conf = {} conf = {}
gathered_options = ['%s-%s' % option for type_ in ['remote', 'local']:
for option in itertools.product(self.types, for data in ['host', 'port']:
self.datas)] confkey, opt = ['%s%s%s' % (type_, i, data) for i in ['_', '-']]
for option in gathered_options: conf[confkey] = self.options[opt]
# XXX: Because the options are using dash and the template uses
# underscore
conf[option.replace('-', '_')] = self.options[option]
pid_file = self.options['pid-file'] pid_file = self.options['pid-file']
conf.update(pid_file=pid_file) conf.update(pid_file=pid_file)
path_list.append(pid_file)
log_file = self.options['log-file'] log_file = self.options['log-file']
conf.update(log=log_file) conf.update(log=log_file)
...@@ -91,4 +83,21 @@ class Recipe(GenericBaseRecipe): ...@@ -91,4 +83,21 @@ class Recipe(GenericBaseRecipe):
) )
path_list.append(wrapper) path_list.append(wrapper)
if os.path.exists(pid_file):
with open(pid_file, 'r') as file_:
pid = file_.read().strip()
# Reload configuration
try:
os.kill(int(pid, 10), signal.SIGHUP)
except OSError, e:
if e.errno == errno.ESRCH: # No such process
os.unlink(pid_file)
else:
raise e
if 'post-rotate-script' in self.options:
self.createPythonScript(self.options['post-rotate-script'],
__name__ + 'post_rotate',
dict(pid_file=pid_file))
return path_list return path_list
...@@ -6,5 +6,5 @@ key = %(key)s ...@@ -6,5 +6,5 @@ key = %(key)s
cert = %(cert)s cert = %(cert)s
[service] [service]
accept = %(remote_address)s:%(remote_port)s accept = %(remote_host)s:%(remote_port)s
connect = %(local_address)s:%(local_port)s connect = %(local_host)s:%(local_port)s
##############################################################################
#
# 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 shlex
from slapos.recipe.librecipe import GenericBaseRecipe
class Recipe(GenericBaseRecipe):
def install(self):
files = [f for f in self.options['files'].split('\n') if f]
command_line = shlex.split(self.options['command-line'])
wrapper = self.createPythonScript(
self.options['wrapper'],
'slapos.recipe.librecipe.execute.execute_wait',
[ command_line,
files ],
)
return [wrapper]
[buildout] [buildout]
parts = parts =
davstorage davstorage
url
certificate-authority
ca-davstorage
cron
cron-entry-logrotate
logrotate
logrotate-entry-davstorage
eggs-directory = ${buildout:eggs-directory} eggs-directory = ${buildout:eggs-directory}
develop-eggs-directory = ${buildout:develop-eggs-directory} develop-eggs-directory = ${buildout:develop-eggs-directory}
offline = true offline = true
[url]
recipe = slapos.cookbook:publishurl
scheme = webdavs
user = $${davstorage:user}
port = $${davstorage:port}
host = $${davstorage:ip}
password = $${davstorage:password}
[davstorage] [davstorage]
recipe = slapos.cookbook:davstorage recipe = slapos.cookbook:davstorage
user = user
port = 8080
ip = $${slap-network-information:global-ipv6}
# Path
wrapper = $${rootdirectory:bin}/davstorage
error-log = $${directory:davstorage-log}/error.log
access-log = $${directory:davstorage-log}/access.log
pid-file = $${basedirectory:run}/davstorage.pid
lock-file = $${basedirectory:run}/davstorage.lock
davdb-lock = $${basedirectory:run}/davdb.lock
key-file = $${ca-davstorage:key-file}
cert-file = $${ca-davstorage:cert-file}
conf-file = $${directory:davstorage-conf}/davstorage.conf
htdocs = $${directory:htdocs}
root = $${buildout:directory}
email-address = admin+davstorage@vifib.net
htpasswd-file = $${directory:davstorage-conf}/davstorage.htpasswd
promise = $${basedirectory:promises}/davstorage
# Binaries
apache-binary = ${apache:location}/bin/httpd
apache-modules-dir = ${apache:location}/modules/
apache-mime-file = ${apache:location}/conf/mime.types
apache-htpasswd = ${apache:location}/bin/htpasswd
[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}/certificate_authority
ca-private = $${cadirectory:private}
ca-certs = $${cadirectory:certs}
ca-newcerts = $${cadirectory:newcerts}
ca-crl = $${cadirectory:crl}
[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:binary}
binary = $${basedirectory:services}/crond
[logrotate]
recipe = slapos.cookbook:logrotate
# Binaries # Binaries
dcrond_binary = ${dcron:location}/sbin/crond logrotate-binary = ${logrotate:location}/usr/sbin/logrotate
logrotate_binary = ${logrotate:location}/usr/sbin/logrotate gzip-binary = ${gzip:location}/bin/gzip
apache_binary = ${apache:location}/bin/httpd gunzip-binary = ${gzip:location}/bin/gunzip
apache_modules_dir = ${apache:location}/modules/ # Directories
apache_mime_file = ${apache:location}/conf/mime.types wrapper = $${rootdirectory:bin}/logrotate
apache_htpasswd = ${apache:location}/bin/htpasswd conf = $${rootdirectory:etc}/logrotate.conf
# Real configuration logrotate-entries = $${directory:logrotate-entries}
key_file = $${certificate_authority:certificate_authority_dir}/davstorage.key backup = $${directory:logrotate-backup}
cert_file = $${certificate_authority:certificate_authority_dir}/davstorage.crt state-file = $${rootdirectory:srv}/logrotate.status
# [ca] [cron-entry-logrotate]
# recipe = slapos.cookbook:ca <= cron
# openssl_binary = ${openssl:location}/bin/openssl recipe = slapos.cookbook:cron.d
# certificate_authority_dir = $${directory:srv}/ssl/ name = logrotate
# frequency = 0 0 * * *
# [ca-davstorage] command = $${logrotate:wrapper}
# recipe = slapos.cookbook:part
# part = $${certificate_authority:part} [cron-simplelogger]
# parameters = recipe = slapos.cookbook:simplelogger
# key_file=$${davstorage:key_file} binary = $${rootdirectory:bin}/cron_simplelogger
# cert_file=$${davstorage:cert_file} output = $${directory:cronoutput}
[logrotate-entry-davstorage]
<= logrotate
recipe = slapos.cookbook:logrotate.d
name = davstorage
log = $${davstorage:error-log} $${davstorage:access-log}
frequency = daily
rotate-num = 30
sharedscripts = true
notifempty = true
create = true
[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-davstorage]
<= certificate-authority
recipe = slapos.cookbook:certificate_authority.request
key-file = $${directory:davstorage-conf}/davstorage.key
cert-file = $${directory:davstorage-conf}/davstorage.crt
executable = $${davstorage:wrapper}
wrapper = $${basedirectory:services}/davstorage
[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/
services = $${rootdirectory:etc}/run/
run = $${rootdirectory:var}/run/
backup = $${rootdirectory:srv}/backup/
promises = $${rootdirectory:etc}/promise/
[directory]
recipe = slapos.cookbook:mkdirectory
htdocs = $${rootdirectory:srv}/www/
davstorage-log = $${basedirectory:log}/davstorage/
logrotate-backup = $${basedirectory:backup}/logrotate/
logrotate-entries = $${rootdirectory:etc}/logrotate.d/
davstorage-conf = $${rootdirectory:etc}/davstorage/
ca-dir = $${rootdirectory:srv}/ssl/
cron-entries = $${rootdirectory:etc}/cron.d/
crontabs = $${rootdirectory:etc}/crontabs/
cronstamps = $${rootdirectory:etc}/cronstamps/
cronoutput = $${basedirectory:log}/cron/
...@@ -9,4 +9,4 @@ offline = true ...@@ -9,4 +9,4 @@ offline = true
[switch_softwaretype] [switch_softwaretype]
recipe = slapos.cookbook:softwaretype recipe = slapos.cookbook:softwaretype
default = ${instance_davstorage:output} default = ${instance-davstorage:output}
...@@ -8,10 +8,11 @@ versions = versions ...@@ -8,10 +8,11 @@ versions = versions
extends = extends =
../../component/apache/buildout.cfg ../../component/apache/buildout.cfg
../../component/dcron/buildout.cfg ../../component/dcron/buildout.cfg
../../component/logrotate/buildout.cfg ../../component/logrotate/buildout.cfg
../../stack/shacache-client.cfg ../../stack/shacache-client.cfg
../../component/lxml-python/buildout.cfg ../../component/lxml-python/buildout.cfg
../../component/python-2.7/buildout.cfg ../../component/python-2.7/buildout.cfg
../../component/gzip/buildout.cfg
# Use only quite well working sites. # Use only quite well working sites.
allow-hosts = allow-hosts =
...@@ -24,6 +25,7 @@ allow-hosts = ...@@ -24,6 +25,7 @@ allow-hosts =
peak.telecommunity.com peak.telecommunity.com
psutil.googlecode.com psutil.googlecode.com
www.dabeaz.com www.dabeaz.com
alastairs-place.net
parts = parts =
...@@ -33,9 +35,9 @@ parts = ...@@ -33,9 +35,9 @@ parts =
logrotate logrotate
dcron dcron
eggs eggs
gzip
instance-recipe-egg instance-recipe-egg
unzip= true unzip= true
[eggs] [eggs]
...@@ -55,14 +57,14 @@ eggs = ${instance-recipe:egg} ...@@ -55,14 +57,14 @@ eggs = ${instance-recipe:egg}
# Default template for the instance. # Default template for the instance.
recipe = slapos.recipe.template recipe = slapos.recipe.template
url = ${:_profile_base_location_}/instance.cfg url = ${:_profile_base_location_}/instance.cfg
md5sum = 4c79e2e42704a2ffe5eebfa0b2e70e28 md5sum = bed788dee6daf05349c4577e7a7f1299
output = ${buildout:directory}/template.cfg output = ${buildout:directory}/template.cfg
mode = 0644 mode = 0644
[instance_davstorage] [instance-davstorage]
recipe = slapos.recipe.template recipe = slapos.recipe.template
url = ${:_profile_base_location_}/instance-davstorage.cfg url = ${:_profile_base_location_}/instance-davstorage.cfg
md5sum = 009103c87c8d31fb758e7a0782e77723 md5sum = 49c8e049a78e233d3a553e64c8914592
output = ${buildout:directory}/template-davstorage.cfg output = ${buildout:directory}/template-davstorage.cfg
mode = 0644 mode = 0644
...@@ -103,7 +105,7 @@ netaddr = 0.7.6 ...@@ -103,7 +105,7 @@ netaddr = 0.7.6
# Required by: # Required by:
# slapos.core==0.14 # slapos.core==0.14
netifaces = 0.4 #netifaces = 0.4
# Required by: # Required by:
# slapos.cookbook==0.24 # slapos.cookbook==0.24
......
[buildout]
parts =
apache-php
request-mariadb
mkdir
eggs-directory = ${buildout:eggs-directory}
develop-eggs-directory = ${buildout:develop-eggs-directory}
offline = true
[apache-php]
recipe = slapos.cookbook:lamp.request
source = ${application:location}
template = ${application-template:location}/${application-template:filename}
configuration = ${application-configuration:location}
httpd_binary = ${apache:location}/bin/httpd
stunnel_binary = ${stunnel:location}/bin/stunnel
mysql-url = $${request-mariadb:connection-url}
[request-mariadb]
recipe = slapos.cookbook:request
name = MariaDB DataBase
software-url = $${slap_connection:software_release_url}
software-type = mariadb
return = url
[buildout] [buildout]
versions = versions versions = versions
parts =
apache-php
template
eggs
instance-recipe-egg
instance_wordpress
instance_mariadb
extends = extends =
../../component/gzip/buildout.cfg ../../stack/lamp/buildout.cfg
../../stack/apache-php.cfg
../../stack/shacache-client.cfg
# XXX: This is dirty, recipe trick shall be used.
develop =
/opt/slapdev
[application] [application]
url = http://wordpress.org/latest.tar.gz url = http://wordpress.org/latest.tar.gz
...@@ -33,51 +21,8 @@ location = ${buildout:parts-directory}/${:_buildout_section_name_} ...@@ -33,51 +21,8 @@ location = ${buildout:parts-directory}/${:_buildout_section_name_}
[application-configuration] [application-configuration]
location = wp-config.php location = wp-config.php
md5sum = 608dd9003a8edeb59c3aabc6cf43bbf9 md5sum = 3859841a4ad6ed23744d6bc5a01321e0
[instance-recipe]
egg = slapos.cookbook
module = lamp.request
[instance-recipe-egg]
recipe = zc.recipe.egg
eggs = ${instance-recipe:egg}
[template]
# Default template for the instance.
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/instance.cfg
md5sum = 817407b6bb7af1dce7588e259ead0d26
output = ${buildout:directory}/template.cfg
mode = 0644
[instance_mariadb]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/../mariadb/instance-mariadb.cfg
md5sum = 38aefa725d21988485c20ae9d58f9455
output = ${buildout:directory}/template-mariadb.cfg
mode = 0644
[instance_wordpress]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/instance-wordpress.cfg
md5sum = 220e14b7a46742b1fd83d699c352b888
output = ${buildout:directory}/template-wordpress.cfg
mode = 0644
[versions] [versions]
#slapos.cookbook = 0.12
# Required by slapos.cookbook==0.12
slapos.core = 0.8
collective.recipe.template = 1.8
netaddr = 0.7.5
xml-marshaller = 0.9.7
setuptools = 0.6c12dev-r88795
hexagonit.recipe.cmmi = 1.5.0
hexagonit.recipe.download = 1.5.0
plone.recipe.command = 1.1
# Use SlapOS patched zc.buildout # Use SlapOS patched zc.buildout
zc.buildout = 1.6.0-dev-SlapOS-002 zc.buildout = 1.6.0-dev-SlapOS-003
...@@ -42,14 +42,14 @@ define('DB_COLLATE', ''); ...@@ -42,14 +42,14 @@ define('DB_COLLATE', '');
* *
* @since 2.6.0 * @since 2.6.0
*/ */
define('AUTH_KEY', 'put your unique phrase here'); define('AUTH_KEY', '%(secret_key)s');
define('SECURE_AUTH_KEY', 'put your unique phrase here'); define('SECURE_AUTH_KEY', '%(secret_key)s');
define('LOGGED_IN_KEY', 'put your unique phrase here'); define('LOGGED_IN_KEY', '%(secret_key)s');
define('NONCE_KEY', 'put your unique phrase here'); define('NONCE_KEY', '%(secret_key)s');
define('AUTH_SALT', 'put your unique phrase here'); define('AUTH_SALT', '%(secret_key)s');
define('SECURE_AUTH_SALT', 'put your unique phrase here'); define('SECURE_AUTH_SALT', '%(secret_key)s');
define('LOGGED_IN_SALT', 'put your unique phrase here'); define('LOGGED_IN_SALT', '%(secret_key)s');
define('NONCE_SALT', 'put your unique phrase here'); define('NONCE_SALT', '%(secret_key)s');
/**#@-*/ /**#@-*/
......
[buildout]
find-links +=
http://www.nexedi.org/static/packages/source/slapos.buildout/
# Use only quite well working sites.
allow-hosts =
*.nexedi.org
*.python.org
*.sourceforge.net
dist.repoze.org
effbot.org
github.com
peak.telecommunity.com
psutil.googlecode.com
www.dabeaz.com
parts =
template
apache-php
mariadb
eggs
instance-recipe-egg
stunnel
extends =
../component/apache/buildout.cfg
../component/apache-php/buildout.cfg
../component/dcron/buildout.cfg
../component/git/buildout.cfg
../component/glib/buildout.cfg
../component/logrotate/buildout.cfg
../component/python-2.7/buildout.cfg
../component/lxml-python/buildout.cfg
../component/zlib/buildout.cfg
../component/stunnel/buildout.cfg
[application]
recipe = hexagonit.recipe.download
#If provided tarball does not containt top directory this option shall be changed to false
strip-top-level-dir = true
[eggs]
recipe = zc.recipe.egg
eggs =
${lxml-python:egg}
[buildout]
find-links +=
http://www.nexedi.org/static/packages/source/slapos.buildout/
parts =
apache-php
mariadb
mydumper
mysql-python
rdiff-backup
dropbear
eggs
instance-recipe-egg
template
template-apache-php
template-mariadb
template-mariadb-pbsready
template-mariadb-pbsready-import
template-mariadb-pbsready-export
allow-hosts =
*.nexedi.org
*.python.org
*.sourceforge.net
alastairs-place.net
dist.repoze.org
effbot.org
github.com
peak.telecommunity.com
psutil.googlecode.com
www.dabeaz.com
launchpad.net
extends =
../shacache-client.cfg
../../component/mariadb/buildout.cfg
../../component/apache/buildout.cfg
../../component/apache-php/buildout.cfg
../../component/dcron/buildout.cfg
../../component/git/buildout.cfg
../../component/glib/buildout.cfg
../../component/logrotate/buildout.cfg
../../component/python-2.7/buildout.cfg
../../component/perl/buildout.cfg
../../component/sqlite3/buildout.cfg
../../component/lxml-python/buildout.cfg
../../component/zlib/buildout.cfg
../../component/rdiff-backup/buildout.cfg
../../component/gzip/buildout.cfg
../../component/stunnel/buildout.cfg
../../component/mydumper/buildout.cfg
../../component/mysql-python/buildout.cfg
../../component/dropbear/buildout.cfg
versions = versions
[mariadb]
# Compile dir is for plugins, there's no plugin in LAMP
keep-compile-dir = false
[instance-recipe]
egg = slapos.cookbook
module = lamp.request
[instance-recipe-egg]
recipe = zc.recipe.egg
#python = python2.7
eggs = ${instance-recipe:egg}
[application]
recipe = hexagonit.recipe.download
#If provided tarball does not containt top directory this option shall be changed to false
strip-top-level-dir = true
[template]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/instance.cfg
output = ${buildout:directory}/template.cfg
md5sum = 8117f10e814a13c5376af4c01e6546d4
mode = 0644
[template-apache-php]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/instance-apache-php.cfg
output = ${buildout:directory}/template-apache-php.cfg
md5sum = 45bc82dc468e7f418d95c846d1a33d74
mode = 0644
[template-apache-backup]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/instance-apache-backup.cfg
output = ${buildout:directory}/template-apache-backup.cfg
md5sum = cfb77ac8785e0d125a785f69a5339014
mode = 0644
[template-backuped]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/instance-backuped.cfg
output = ${buildout:directory}/template-backuped.cfg
md5sum = f43d1c6412ea8dc83b75573dc00daf9e
mode = 0644
[template-mariadb]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/instance-mariadb.cfg
output = ${buildout:directory}/template-mariadb.cfg
md5sum = 70ab558c2e925c3627c39fbc20a7501c
mode = 0644
[template-mariadb-pbsready]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/instance-mariadb-pbsready.cfg
output = ${buildout:directory}/template-mariadb-pbsready.cfg
md5sum = d2a580dcd7efdd528be45c5ffadfe760
mode = 0644
[template-mariadb-pbsready-import]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/instance-mariadb-pbsready-import.cfg
output = ${buildout:directory}/template-mariadb-pbsready-import.cfg
md5sum = 4a96ff02da3898fef7077fa8baec81ac
mode = 0644
[template-mariadb-pbsready-export]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/instance-mariadb-pbsready-export.cfg
output = ${buildout:directory}/template-mariadb-pbsready-export.cfg
md5sum = 11a9e45e8bc590bc11bfdd304b07a4a5
mode = 0644
[template-pull-backup]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/instance-pull-backup.cfg
output = ${buildout:directory}/template-pull-backup.cfg
md5sum = 9aab30ba5aa23a37d4b507e7c414be00
mode = 0644
[eggs]
recipe = zc.recipe.egg
eggs =
${lxml-python:egg}
slapos.toolbox
[buildout]
parts =
urls
apache-proxy
logrotate
logrotate-entry-apache
cron
cron-entry-logrotate
sshkeys-authority
sshkeys-dropbear
dropbear-server
dropbear-server-pbs-authorized-key
eggs-directory = ${buildout:eggs-directory}
develop-eggs-directory = ${buildout:develop-eggs-directory}
offline = true
[urls]
recipe = slapos.cookbook:publish
url = http://[$${apache-proxy:ip}]:$${apache-proxy:port}/
ssh-public-key = $${sshkeys-dropbear:public-key-value}
ssh-url = ssh://nobody@[$${dropbear-server:host}]:$${dropbear-server:port}/$${rdiff-backup-server:path}
[apache-proxy]
recipe = slapos.cookbook:apacheproxy
url = $${slap-parameter:proxy-url}
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
httpd-conf = $${rootdirectory:etc}/apache.conf
wrapper = $${basedirectory:services}/apache
promise = $${basedirectory:promises}/apache
httpd-binary = ${apache:location}/bin/httpd
[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 = $${basedirectory:services}/sshkeys_authority
keygen-binary = ${dropbear:location}/bin/dropbearkey
[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 = $${basedirectory:services}/sshd
[dropbear-server]
recipe = slapos.cookbook:dropbear
host = $${slap-network-information:global-ipv6}
port = 2222
home = $${directory:ssh}
wrapper = $${rootdirectory:bin}/raw_sshd
shell = $${rdiff-backup-server:wrapper}
rsa-keyfile = $${directory:ssh}/server_key.rsa
dropbear-binary = ${dropbear:location}/sbin/dropbear
[dropbear-server-pbs-authorized-key]
<= dropbear-server
recipe = slapos.cookbook:dropbear.add_authorized_key
key = $${slap-parameter:authorized-key}
[rdiff-backup-server]
recipe = slapos.cookbook:pbs
client = false
path = $${directory:htdocs}
wrapper = $${rootdirectory:bin}/rdiffbackup-server
rdiffbackup-binary = ${buildout:bin-directory}/rdiff-backup
[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 = $${apache-proxy:error-log} $${apache-proxy:access-log}
frequency = daily
rotate-num = 30
sharedscripts = true
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}
[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/
[directory]
recipe = slapos.cookbook:mkdirectory
htdocs = $${rootdirectory:srv}/www/
logrotate-entries = $${rootdirectory:etc}/logrotate.d/
logrotate-backup = $${basedirectory:backup}/logrotate/
cronstamps = $${rootdirectory:etc}/cronstamps/
cron-entries = $${rootdirectory:etc}/cron.d/
crontabs = $${rootdirectory:etc}/crontabs/
ssh = $${rootdirectory:etc}/ssh/
sshkeys = $${rootdirectory:srv}/sshkeys
httpd-log = $${basedirectory:log}/apache/
[buildout]
parts =
url
request-mariadb
apache-php
stunnel
certificate-authority
ca-stunnel
logrotate
logrotate-entry-apache
logrotate-entry-stunnel
cron
cron-entry-logrotate
eggs-directory = ${buildout:eggs-directory}
develop-eggs-directory = ${buildout:develop-eggs-directory}
offline = true
[url]
recipe = slapos.cookbook:publishurl
url = http://[$${apache-php:ip}]:$${apache-php:port}/
[mariadb-urlparse]
recipe = slapos.cookbook:urlparse
url = $${request-mariadb:connection-url}
[apache-php]
recipe = slapos.cookbook:apachephp
source = ${application:location}
template = ${application-template:location}/${application-template:filename}
configuration = ${application-configuration:location}
htdocs = $${directory:htdocs}
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
php-ini-dir = $${directory:php-ini-dir}
tmp-dir = $${directory:tmp-php}
httpd-conf = $${rootdirectory:etc}/apache.conf
wrapper = $${basedirectory:services}/apache
promise = $${basedirectory:promises}/apache
httpd-binary = ${apache:location}/bin/httpd
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}
[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
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
[request-mariadb]
<= slap-connection
recipe = slapos.cookbook:request
name = MariaDB
software-url = $${slap-connection:software-release-url}
software-type = mariadb
return = url
[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 = $${apache-php:error-log} $${apache-php: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]
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}
[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/
[directory]
recipe = slapos.cookbook:mkdirectory
ca-dir = $${rootdirectory:srv}/ssl/
htdocs = $${rootdirectory:srv}/www/
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/
[buildout]
extends =
${template-apache-php:output}
parts =
request-mariadb
request-mariadb-pseudo-replicating
request-apache-backup
request-pull-backup-server
request-pull-backup-server-mariadb
request-pull-backup-server-mariadb-backup
request-pull-backup-server-apache
request-pull-backup-server-apache-backup
url
apache-php
stunnel
certificate-authority
ca-stunnel
logrotate
logrotate-entry-apache
logrotate-entry-stunnel
cron
cron-entry-logrotate
dropbear-server
sshkeys-authority
dropbear-server-pbs-authorized-key
[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 = $${basedirectory:services}/sshkeys_authority
keygen-binary = ${dropbear:location}/bin/dropbearkey
[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 = $${basedirectory:services}/sshd
[dropbear-server]
recipe = slapos.cookbook:dropbear
host = $${slap-network-information:global-ipv6}
port = 2222
home = $${directory:ssh}
wrapper = $${rootdirectory:bin}/raw_sshd
shell = $${rdiff-backup-server:wrapper}
rsa-keyfile = $${directory:ssh}/server_key.rsa
dropbear-binary = ${dropbear:location}/sbin/dropbear
[dropbear-server-pbs-authorized-key]
<= dropbear-server
recipe = slapos.cookbook:dropbear.add_authorized_key
key = $${request-pull-backup-server:connection-ssh-key}
[rdiff-backup-server]
recipe = slapos.cookbook:pbs
client = false
path = $${directory:htdocs}
wrapper = $${rootdirectory:bin}/rdiffbackup-server
rdiffbackup-binary = ${buildout:bin-directory}/rdiff-backup
[request-pull-backup-server]
<= slap-connection
recipe = slapos.cookbook:request
name = PBS (Pull Backup Server)
software-url = $${slap-connection:software-release-url}
software-type = pull-backup
return = ssh-key notification-url feeds-url
slave = false
[request-mariadb]
software-type = mariadb-pbsready-export
config = authorized-key notify
config-authorized-key = $${request-pull-backup-server:connection-ssh-key}
config-notify = $${request-pull-backup-server:connection-notification-url}
return = url ssh-public-key ssh-url notification-id
[request-mariadb-pseudo-replicating]
<= slap-connection
recipe = slapos.cookbook:request
name = MariaDB Backup
software-url = $${slap-connection:software-release-url}
software-type = mariadb-pbsready-import
return = url ssh-public-key ssh-url notification-url
config = authorized-key on-notification
config-authorized-key = $${request-pull-backup-server:connection-ssh-key}
pbs-notification-id = $${slap-connection:computer-id}-$${slap-connection:partition-id}-mariadb-push
config-on-notification = $${request-pull-backup-server:connection-feeds-url}$${:pbs-notification-id}
[request-apache-backup]
<= slap-connection
recipe = slapos.cookbook:request
name = Apache Backup
software-url = $${slap-connection:software-release-url}
software-type = apache-backup
return = url ssh-url ssh-public-key
config = authorized-key proxy-url
config-authorized-key = $${request-pull-backup-server:connection-ssh-key}
config-proxy-url = $${url:url}
[request-pull-backup-server-apache]
<= request-pull-backup-server
slap-connection
recipe = slapos.cookbook:request
name = PBS pulling from Apache
software-url = $${slap-connection:software-release-url}
config = url name type server-key notify notification-id frequency
config-url = ssh://nobody@[$${dropbear-server:host}]:$${dropbear-server:port}/$${rdiff-backup-server:path}
config-name = $${slap-connection:computer-id}-$${slap-connection:partition-id}-apache
config-type = pull
config-server-key = $${sshkeys-dropbear:public-key-value}
config-notify = $${request-pull-backup-server:connection-notification-url}
config-notification-id = $${slap-connection:computer-id}-$${slap-connection:partition-id}-apache-pull
config-frequency = 30 * * * *
slave = true
[request-pull-backup-server-apache-backup]
<= request-pull-backup-server
slap-connection
recipe = slapos.cookbook:request
name = PBS pushing to $${request-apache-backup:name}
software-url = $${slap-connection:software-release-url}
config = url name type server-key on-notification
config-url = $${request-apache-backup:connection-ssh-url}
config-name = $${request-pull-backup-server-apache:config-name}
config-type = push
config-server-key = $${request-apache-backup:connection-ssh-public-key}
config-on-notification = $${request-pull-backup-server:connection-feeds-url}$${request-pull-backup-server-apache:config-notification-id}
slave = true
[request-pull-backup-server-mariadb]
<= request-pull-backup-server
slap-connection
name = PBS pulling from $${request-mariadb:name}
config = url name type server-key on-notification notify notification-id title
config-url = $${request-mariadb:connection-ssh-url}
config-name = $${slap-connection:computer-id}-$${slap-connection:partition-id}-mariadb
config-type = pull
config-server-key = $${request-mariadb:connection-ssh-public-key}
config-on-notification = $${request-mariadb:connection-notification-id}
config-notify = $${request-pull-backup-server:connection-notification-url}
config-notification-id = $${slap-connection:computer-id}-$${slap-connection:partition-id}-mariadb-pull
config-title = Pulling from MariaDB
slave = true
[request-pull-backup-server-mariadb-backup]
<= request-pull-backup-server
slap-connection
name = PBS pushing on $${request-mariadb-pseudo-replicating:name}
config = url name type server-key on-notification notify notification-id title
config-url = $${request-mariadb-pseudo-replicating:connection-ssh-url}
config-name = $${request-pull-backup-server-mariadb:config-name}
config-type = push
config-server-key = $${request-mariadb-pseudo-replicating:connection-ssh-public-key}
config-on-notification = $${request-pull-backup-server:connection-feeds-url}$${request-pull-backup-server-mariadb:config-notification-id}
config-notify = $${request-mariadb-pseudo-replicating:connection-notification-url}
config-notification-id = $${request-mariadb-pseudo-replicating:pbs-notification-id}
config-title = Pushing to MariaDB backup
slave = true
[directory]
ssh = $${rootdirectory:etc}/ssh/
sshkeys = $${rootdirectory:srv}/sshkeys
[buildout]
extends = ${template-mariadb-pbsready:output}
parts += cron-entry-mariadb-backup
[urls]
notification-id = http://[$${notifier:host}]:$${notifier:port}/get/$${notifier-mydumper:name}
[mydumper]
recipe = slapos.cookbook:mydumper
wrapper = $${rootdirectory:bin}/raw_mydumper
backup-directory = $${directory:mariadb-backup}
socket = $${mariadb:socket}
user = root
mydumper-binary = ${mydumper:location}/bin/mydumper
database = $${mariadb:database}
import = false
[notifier-mydumper]
<= notifier
recipe = slapos.cookbook:notifier.notify
name = mydumper
title = Dumping MariaDB Database
executable = $${mydumper:wrapper}
wrapper = $${rootdirectory:bin}/mydumper
notify = $${slap-parameter:notify}
[cron-entry-mariadb-backup]
<= cron
recipe = slapos.cookbook:cron.d
name = backup
frequency = 0 * * * *
command = $${notifier-mydumper:wrapper}
[buildout]
extends = ${template-mariadb-pbsready:output}
parts += mariadb-import-on-notification
[urls]
notification-url = http://[$${notifier:host}]:$${notifier:port}/notify
[mydumper-import]
recipe = slapos.cookbook:mydumper
wrapper = $${rootdirectory:bin}/myloader
backup-directory = $${directory:mariadb-backup}
socket = $${mariadb:socket}
user = root
myloader-binary = ${mydumper:location}/bin/myloader
database = $${mariadb:database}
import = true
[mariadb-import-on-notification]
<= notifier
recipe = slapos.cookbook:notifier.callback
on-notification-id = $${slap-parameter:on-notification}
callback = $${mydumper-import:wrapper}
[buildout]
extends = ${template-mariadb:output}
parts =
urls
mariadb
stunnel
certificate-authority
ca-stunnel
logrotate
logrotate-entry-mariadb
logrotate-entry-stunnel
logrotate-entry-cron
logrotate-entry-equeue
cron
cron-entry-logrotate
sshkeys-authority
dropbear-server
sshkeys-dropbear
dropbear-server-pbs-authorized-key
notifier
[urls]
ssh-public-key = $${sshkeys-dropbear:public-key-value}
ssh-url = ssh://nobody@[$${dropbear-server:host}]:$${dropbear-server:port}/$${rdiff-backup-server:path}
[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 = $${basedirectory:services}/sshkeys_authority
keygen-binary = ${dropbear:location}/bin/dropbearkey
[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 = $${basedirectory:services}/sshd
[dropbear-server]
recipe = slapos.cookbook:dropbear
host = $${slap-network-information:global-ipv6}
port = 2222
home = $${directory:ssh}
wrapper = $${rootdirectory:bin}/raw_sshd
shell = $${rdiff-backup-server:wrapper}
rsa-keyfile = $${directory:ssh}/server_key.rsa
dropbear-binary = ${dropbear:location}/sbin/dropbear
[dropbear-server-pbs-authorized-key]
<= dropbear-server
recipe = slapos.cookbook:dropbear.add_authorized_key
key = $${slap-parameter:authorized-key}
[rdiff-backup-server]
recipe = slapos.cookbook:pbs
client = false
path = $${directory:mariadb-backup}
wrapper = $${rootdirectory:bin}/rdiffbackup-server
rdiffbackup-binary = ${buildout:bin-directory}/rdiff-backup
[logrotate-entry-equeue]
<= logrotate
recipe = slapos.cookbook:logrotate.d
name = equeue
log = $${equeue:log}
frequency = daily
rotate-num = 30
[equeue]
recipe = slapos.cookbook:equeue
socket = $${basedirectory:run}/equeue.sock
log = $${basedirectory:log}/equeue.log
database = $${rootdirectory:srv}/equeue.db
wrapper = $${basedirectory:services}/equeue
equeue-binary = ${buildout:bin-directory}/equeue
[notifier]
recipe = slapos.cookbook:notifier
feeds = $${directory:notifier-feeds}
callbacks = $${directory:notifier-callbacks}
id-file = $${rootdirectory:etc}/notifier.id
equeue-socket = $${equeue:socket}
host = $${slap-network-information:global-ipv6}
port = 8080
wrapper = $${basedirectory:services}/notifier
server-binary = ${buildout:bin-directory}/pubsubserver
notifier-binary = ${buildout:bin-directory}/pubsubnotifier
[basedirectory]
cache = $${rootdirectory:var}/cache/
notifier = $${rootdirectory:etc}/notifier/
[directory]
mariadb-backup = $${basedirectory:backup}/mariadb/
ssh = $${rootdirectory:etc}/ssh/
sshkeys = $${rootdirectory:srv}/sshkeys
notifier-feeds = $${basedirectory:notifier}/feeds/
notifier-callbacks = $${basedirectory:notifier}/callbacks/
[buildout]
parts =
urls
mariadb
stunnel
certificate-authority
ca-stunnel
logrotate
logrotate-entry-mariadb
logrotate-entry-stunnel
logrotate-entry-cron
cron
cron-entry-logrotate
gzip-binary = ${gzip:location}/bin/gzip
eggs-directory = ${buildout:eggs-directory}
develop-eggs-directory = ${buildout:develop-eggs-directory}
offline = true
[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 = user
port = 3306
ip = $${slap-network-information:local-ipv4}
database = db
# Paths
wrapper = $${basedirectory:services}/mariadb
update-wrapper = $${basedirectory:services}/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-binary = ${mariadb:location}/bin/mysql
mysql-install-binary = ${mariadb:location}/bin/mysql_install_db
mysql-upgrade-binary = ${mariadb:location}/bin/mysql_upgrade
mysqld-binary = ${mariadb:location}/libexec/mysqld
[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}
[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/
services = $${rootdirectory:etc}/run/
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/
[buildout]
parts =
connection-dict
pbs
cron
cron-entry-logrotate
logrotate
sshkeys-authority
sshkeys-dropbear
eggs-directory = ${buildout:eggs-directory}
develop-eggs-directory = ${buildout:develop-eggs-directory}
offline = true
[connection-dict]
recipe = slapos.cookbook:publish
ssh-key = $${sshkeys-dropbear:public-key-value}
notification-url = http://[$${notifier:host}]:$${notifier:port}/notify
feeds-url = http://[$${notifier:host}]:$${notifier:port}/get/
[equeue]
recipe = slapos.cookbook:equeue
socket = $${basedirectory:run}/equeue.sock
log = $${basedirectory:log}/equeue.log
database = $${rootdirectory:srv}/equeue.db
wrapper = $${basedirectory:services}/equeue
equeue-binary = ${buildout:bin-directory}/equeue
[notifier]
recipe = slapos.cookbook:notifier
feeds = $${directory:notifier-feeds}
callbacks = $${directory:notifier-callbacks}
id-file = $${rootdirectory:etc}/notifier.id
equeue-socket = $${equeue:socket}
host = $${slap-network-information:global-ipv6}
port = 8080
wrapper = $${basedirectory:services}/notifier
server-binary = ${buildout:bin-directory}/pubsubserver
notifier-binary = ${buildout:bin-directory}/pubsubnotifier
[dropbear-client]
recipe = slapos.cookbook:dropbear.client
dbclient-binary = ${dropbear:location}/bin/dbclient
wrapper = $${rootdirectory:bin}/ssh
home = $${basedirectory:ssh-home}
identity-file = $${basedirectory:ssh-home}/id_rsa
[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}
keygen-binary = ${dropbear:location}/bin/dropbearkey
wrapper = $${basedirectory:services}/sshkeys_authority
[sshkeys-dropbear]
<= sshkeys-authority
recipe = slapos.cookbook:sshkeys_authority.request
name = pbs
type = rsa
executable = $${dropbear-client:wrapper}
public-key = $${dropbear-client:identity-file}.pub
private-key = $${dropbear-client:identity-file}
wrapper = $${rootdirectory:bin}/do_backup
[pbs]
<= notifier
recipe = slapos.cookbook:pbs
client = true
rdiffbackup-binary = ${buildout:bin-directory}/rdiff-backup
sshclient-binary = $${dropbear-client:wrapper}
known-hosts = $${directory:dot-ssh}/known_hosts
promises-directory = $${basedirectory:promises}
directory = $${directory:pbs-backup}
cron-entries = $${cron:cron-entries}
wrappers-directory = $${directory:pbs-wrappers}
notifier-url = http://[$${notifier:host}]:$${notifier:port}/
slave-instance-list = $${slap-parameter:slave_instance_list}
[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}
[logrotate]
recipe = slapos.cookbook:logrotate
# Binaries
logrotate-binary = ${logrotate:location}/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-equeue]
<= logrotate
recipe = slapos.cookbook:logrotate.d
name = equeue
log = $${equeue:log}
frequency = daily
rotate-num = 30
[logrotate-entry-equeue]
<= logrotate
recipe = slapos.cookbook:logrotate.d
name = cron
log = $${cron-simplelogger:log}
frequency = daily
rotate-num = 30
[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/
[directory]
recipe = slapos.cookbook:mkdirectory
cronstamps = $${rootdirectory:etc}/cronstamps/
cron-entries = $${rootdirectory:etc}/cron.d/
crontabs = $${rootdirectory:etc}/crontabs/
cronoutput = $${basedirectory:log}/cron-ouput/
pbs-backup = $${basedirectory:backup}/pbs/
logrotate-entries = $${rootdirectory:etc}/logrotate.d/
logrotate-backup = $${basedirectory:backup}/logrotate/
sshkeys = $${rootdirectory:srv}/sshkeys
pbs-wrappers = $${rootdirectory:bin}/pbs/
dot-ssh = $${basedirectory:ssh-home}/.ssh/
notifier-feeds = $${basedirectory:notifier}/feeds/
notifier-callbacks = $${basedirectory:notifier}/callbacks/
[basedirectory]
ssh-home = $${rootdirectory:home}/ssh
notifier = $${rootdirectory:etc}/notifier/
[rootdirectory]
home = $${buildout:directory}/home/
...@@ -8,5 +8,10 @@ offline = true ...@@ -8,5 +8,10 @@ offline = true
[switch_softwaretype] [switch_softwaretype]
recipe = slapos.cookbook:softwaretype recipe = slapos.cookbook:softwaretype
default = ${instance_wordpress:output} default = ${template-apache-php:output}
mariadb = ${instance_mariadb:output} backuped = ${template-backuped:output}
mariadb = ${template-mariadb:output}
mariadb-pbsready-import = ${template-mariadb-pbsready-import:output}
mariadb-pbsready-export = ${template-mariadb-pbsready-export:output}
pull-backup = ${template-pull-backup:output}
apache-backup = ${template-apache-backup:output}
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