Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
slapos
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Labels
Merge Requests
103
Merge Requests
103
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Jobs
Commits
Open sidebar
nexedi
slapos
Commits
7a5346c6
Commit
7a5346c6
authored
Mar 26, 2013
by
Cédric de Saint Martin
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'example'
parents
627226ab
36f420ca
Changes
34
Show whitespace changes
Inline
Side-by-side
Showing
34 changed files
with
1454 additions
and
15 deletions
+1454
-15
component/nginx/buildout.cfg
component/nginx/buildout.cfg
+30
-3
setup.py
setup.py
+6
-0
slapos/recipe/check_page_content/__init__.py
slapos/recipe/check_page_content/__init__.py
+1
-0
slapos/recipe/check_page_content/template/check_page_content.in
.../recipe/check_page_content/template/check_page_content.in
+2
-1
slapos/recipe/configurationfile/__init__.py
slapos/recipe/configurationfile/__init__.py
+40
-0
slapos/recipe/downloader.py
slapos/recipe/downloader.py
+5
-0
slapos/recipe/lampgeneric/__init__.py
slapos/recipe/lampgeneric/__init__.py
+84
-0
slapos/recipe/lampgeneric/template/apache.in
slapos/recipe/lampgeneric/template/apache.in
+56
-0
slapos/recipe/lampgeneric/template/php.ini.in
slapos/recipe/lampgeneric/template/php.ini.in
+18
-0
slapos/recipe/librecipe/generic.py
slapos/recipe/librecipe/generic.py
+28
-0
slapos/recipe/publish.py
slapos/recipe/publish.py
+25
-0
slapos/recipe/request.py
slapos/recipe/request.py
+36
-1
slapos/recipe/softwaretype.py
slapos/recipe/softwaretype.py
+1
-1
slapos/recipe/wrapper.py
slapos/recipe/wrapper.py
+14
-7
slapos/recipe/zimbra_kvm/__init__.py
slapos/recipe/zimbra_kvm/__init__.py
+65
-0
slapos/recipe/zimbra_kvm/template/kvm_controller_run.in
slapos/recipe/zimbra_kvm/template/kvm_controller_run.in
+32
-0
slapos/recipe/zimbra_kvm/template/kvm_run.in
slapos/recipe/zimbra_kvm/template/kvm_run.in
+51
-0
software/apache-frontend/README.apache_frontend.txt
software/apache-frontend/README.apache_frontend.txt
+16
-1
software/helloworld/instance.cfg.in
software/helloworld/instance.cfg.in
+66
-0
software/helloworld/software.cfg
software/helloworld/software.cfg
+30
-0
software/lamp-generic/README.txt
software/lamp-generic/README.txt
+3
-0
software/lamp-generic/development.cfg
software/lamp-generic/development.cfg
+53
-0
software/lamp-generic/instance-apache-php.cfg.in
software/lamp-generic/instance-apache-php.cfg.in
+196
-0
software/lamp-generic/instance-edge.cfg.in
software/lamp-generic/instance-edge.cfg.in
+29
-0
software/lamp-generic/instance.cfg.in
software/lamp-generic/instance.cfg.in
+13
-0
software/lamp-generic/software.cfg
software/lamp-generic/software.cfg
+23
-0
software/zimbra-kvm/README.txt
software/zimbra-kvm/README.txt
+45
-0
software/zimbra-kvm/common.cfg
software/zimbra-kvm/common.cfg
+43
-0
software/zimbra-kvm/development.cfg
software/zimbra-kvm/development.cfg
+33
-0
software/zimbra-kvm/instance-kvm.cfg.in
software/zimbra-kvm/instance-kvm.cfg.in
+241
-0
software/zimbra-kvm/instance.cfg.in
software/zimbra-kvm/instance.cfg.in
+20
-0
software/zimbra-kvm/software.cfg
software/zimbra-kvm/software.cfg
+146
-0
stack/lamp/buildout.cfg
stack/lamp/buildout.cfg
+2
-1
stack/slapos.cfg
stack/slapos.cfg
+1
-0
No files found.
component/nginx/buildout.cfg
View file @
7a5346c6
...
@@ -4,14 +4,41 @@ extends =
...
@@ -4,14 +4,41 @@ extends =
../zlib/buildout.cfg
../zlib/buildout.cfg
../openssl/buildout.cfg
../openssl/buildout.cfg
parts = nginx
[nginx]
[nginx]
recipe = hexagonit.recipe.cmmi
recipe = hexagonit.recipe.cmmi
url = http://nginx.org/download/nginx-1.0.14.tar.gz
url = http://nginx.org/download/nginx-1.2.7.tar.gz
md5sum = d252f5c689a14a668e241c744ccf5f06
configure-options=
--with-ipv6
--with-http_ssl_module
--with-ld-opt="-L ${zlib:location}/lib -L ${openssl:location}/lib -L ${pcre:location}/lib -Wl,-rpath=${pcre:location}/lib -Wl,-rpath=${zlib:location}/lib -Wl,-rpath=${openssl:location}/lib"
--with-cc-opt="-I ${pcre:location}/include -I ${openssl:location}/include -I ${zlib:location}/include"
[nginx-unstable]
recipe = hexagonit.recipe.cmmi
url = http://nginx.org/download/nginx-1.3.14.tar.gz
md5sum = 9b13753c88ea682fddd1495cb36e5d39
configure-options=
configure-options=
--with-ipv6
--with-ipv6
--with-http_ssl_module
--with-http_ssl_module
--with-ld-opt="-L ${zlib:location}/lib -L ${openssl:location}/lib -L ${pcre:location}/lib -Wl,-rpath=${pcre:location}/lib -Wl,-rpath=${zlib:location}/lib -Wl,-rpath=${openssl:location}/lib"
--with-ld-opt="-L ${zlib:location}/lib -L ${openssl:location}/lib -L ${pcre:location}/lib -Wl,-rpath=${pcre:location}/lib -Wl,-rpath=${zlib:location}/lib -Wl,-rpath=${openssl:location}/lib"
--with-cc-opt="-I ${pcre:location}/include -I ${openssl:location}/include -I ${zlib:location}/include"
--with-cc-opt="-I ${pcre:location}/include -I ${openssl:location}/include -I ${zlib:location}/include"
[hexaglobe-nginx-module]
recipe = hexagonit.recipe.download
url = http://easicloud-p.cdn.hexaglobe.net/nginx-easicloud.tar.gz
md5sum = 57fe2ceb09740f22b5b1023f29889e0e
strip-top-level-dir = true
[nginx-enable-sub]
# Used by Hexaglobe for watermarking
<= nginx
configure-options=
--with-ipv6
--with-http_ssl_module
--with-ld-opt="-L ${zlib:location}/lib -L ${openssl:location}/lib -L ${pcre:location}/lib -Wl,-rpath=${pcre:location}/lib -Wl,-rpath=${zlib:location}/lib -Wl,-rpath=${openssl:location}/lib"
--with-cc-opt="-I ${pcre:location}/include -I ${openssl:location}/include -I ${zlib:location}/include"
--add-module=${hexaglobe-nginx-module:location}/sub_module
# --add-module=${hexaglobe-nginx-module:location}/nginx-upstream-fair
setup.py
View file @
7a5346c6
...
@@ -52,6 +52,7 @@ setup(name=name,
...
@@ -52,6 +52,7 @@ setup(name=name,
packages
=
find_packages
(),
packages
=
find_packages
(),
include_package_data
=
True
,
include_package_data
=
True
,
install_requires
=
[
install_requires
=
[
'hexagonit.recipe.download'
,
'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
...
@@ -80,6 +81,7 @@ setup(name=name,
...
@@ -80,6 +81,7 @@ setup(name=name,
'check_url_available = slapos.recipe.check_url_available:Recipe'
,
'check_url_available = slapos.recipe.check_url_available:Recipe'
,
'cloud9 = slapos.recipe.cloud9:Recipe'
,
'cloud9 = slapos.recipe.cloud9:Recipe'
,
'cloudooo.test = slapos.recipe.erp5_test:CloudoooRecipe'
,
'cloudooo.test = slapos.recipe.erp5_test:CloudoooRecipe'
,
'configurationfile = slapos.recipe.configurationfile:Recipe'
,
'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'
,
...
@@ -121,6 +123,7 @@ setup(name=name,
...
@@ -121,6 +123,7 @@ setup(name=name,
'kvm = slapos.recipe.kvm:Recipe'
,
'kvm = slapos.recipe.kvm:Recipe'
,
'kvm.frontend = slapos.recipe.kvm_frontend:Recipe'
,
'kvm.frontend = slapos.recipe.kvm_frontend:Recipe'
,
'lamp = slapos.recipe.lamp:Request'
,
'lamp = slapos.recipe.lamp:Request'
,
'lamp.generic = slapos.recipe.lampgeneric:Recipe'
,
'lamp.request = slapos.recipe.lamp:Request'
,
'lamp.request = slapos.recipe.lamp:Request'
,
'lamp.simple = slapos.recipe.lamp:Simple'
,
'lamp.simple = slapos.recipe.lamp:Simple'
,
'lamp.static = slapos.recipe.lamp:Static'
,
'lamp.static = slapos.recipe.lamp:Static'
,
...
@@ -151,11 +154,13 @@ setup(name=name,
...
@@ -151,11 +154,13 @@ setup(name=name,
'proactive = slapos.recipe.proactive:Recipe'
,
'proactive = slapos.recipe.proactive:Recipe'
,
'publish = slapos.recipe.publish:Recipe'
,
'publish = slapos.recipe.publish:Recipe'
,
'publish.serialised = slapos.recipe.publish:Serialised'
,
'publish.serialised = slapos.recipe.publish:Serialised'
,
'publishsection = slapos.recipe.publish:PublishSection'
,
'publishurl = slapos.recipe.publishurl:Recipe'
,
'publishurl = slapos.recipe.publishurl:Recipe'
,
'pwgen = slapos.recipe.pwgen:Recipe'
,
'pwgen = slapos.recipe.pwgen:Recipe'
,
'pwgen.stable = slapos.recipe.pwgen:StablePasswordGeneratorRecipe'
,
'pwgen.stable = slapos.recipe.pwgen:StablePasswordGeneratorRecipe'
,
'request = slapos.recipe.request:Recipe'
,
'request = slapos.recipe.request:Recipe'
,
'request.serialised = slapos.recipe.request:Serialised'
,
'request.serialised = slapos.recipe.request:Serialised'
,
'request.edge = slapos.recipe.request:RequestEdge'
,
'requestoptional = slapos.recipe.request:RequestOptional'
,
'requestoptional = slapos.recipe.request:RequestOptional'
,
'seleniumrunner = slapos.recipe.seleniumrunner:Recipe'
,
'seleniumrunner = slapos.recipe.seleniumrunner:Recipe'
,
'sheepdogtestbed = slapos.recipe.sheepdogtestbed:SheepDogTestBed'
,
'sheepdogtestbed = slapos.recipe.sheepdogtestbed:SheepDogTestBed'
,
...
@@ -188,6 +193,7 @@ setup(name=name,
...
@@ -188,6 +193,7 @@ setup(name=name,
'xvfb = slapos.recipe.xvfb:Recipe'
,
'xvfb = slapos.recipe.xvfb:Recipe'
,
'xwiki = slapos.recipe.xwiki:Recipe'
,
'xwiki = slapos.recipe.xwiki:Recipe'
,
'zabbixagent = slapos.recipe.zabbixagent:Recipe'
,
'zabbixagent = slapos.recipe.zabbixagent:Recipe'
,
'zimbra.kvm = slapos.recipe.zimbra_kvm:Recipe'
,
'zeo = slapos.recipe.zeo:Recipe'
,
'zeo = slapos.recipe.zeo:Recipe'
,
],
],
...
...
slapos/recipe/check_page_content/__init__.py
View file @
7a5346c6
...
@@ -38,6 +38,7 @@ class Recipe(GenericBaseRecipe):
...
@@ -38,6 +38,7 @@ class Recipe(GenericBaseRecipe):
'url'
:
self
.
options
[
'url'
],
'url'
:
self
.
options
[
'url'
],
'shell_path'
:
self
.
options
[
'dash_path'
],
'shell_path'
:
self
.
options
[
'dash_path'
],
'curl_path'
:
self
.
options
[
'curl_path'
],
'curl_path'
:
self
.
options
[
'curl_path'
],
'match'
:
self
.
options
.
get
(
'match'
,
self
.
options
[
'url'
])
}
}
# XXX-Cedric in this script, curl won't check certificate
# XXX-Cedric in this script, curl won't check certificate
...
...
slapos/recipe/check_page_content/template/check_page_content.in
View file @
7a5346c6
...
@@ -3,13 +3,14 @@
...
@@ -3,13 +3,14 @@
# BEWARE: It will be overwritten automatically
# BEWARE: It will be overwritten automatically
URL="%(url)s"
URL="%(url)s"
MATCH='%(match)s"
if [ -z $URL ]; then
if [ -z $URL ]; then
echo "No URL specified." >&2
echo "No URL specified." >&2
exit 3
exit 3
fi
fi
%(curl_path)s -k -sL $URL | grep "$
URL
" > /dev/null
%(curl_path)s -k -sL $URL | grep "$
MATCH
" > /dev/null
if [ $? != 0 ]; then
if [ $? != 0 ]; then
echo "Content at $URL seems to be corrupted" >&2
echo "Content at $URL seems to be corrupted" >&2
...
...
slapos/recipe/configurationfile/__init__.py
0 → 100644
View file @
7a5346c6
##############################################################################
#
# 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
):
configuration_file
=
self
.
createFile
(
self
.
options
[
'configuration-file-path'
],
self
.
substituteTemplate
(
self
.
options
[
'configuration-template-path'
],
self
.
options
)
)
return
configuration_file
slapos/recipe/downloader.py
View file @
7a5346c6
...
@@ -36,6 +36,11 @@ from slapos.recipe.librecipe import GenericBaseRecipe
...
@@ -36,6 +36,11 @@ from slapos.recipe.librecipe import GenericBaseRecipe
BUFFER_SIZE
=
1024
BUFFER_SIZE
=
1024
# XXX-Cedric: For god's sake, why do we always reinvent the wheel???
# DON'T use this and use h.r.download, except if you need the "confirm" feature.
# XXX-Cedric: implement "confirm" feature in h.r.download
def
service
(
args
):
def
service
(
args
):
environ
=
os
.
environ
.
copy
()
environ
=
os
.
environ
.
copy
()
environ
.
update
(
PATH
=
args
[
'path'
])
environ
.
update
(
PATH
=
args
[
'path'
])
...
...
slapos/recipe/lampgeneric/__init__.py
0 → 100644
View file @
7a5346c6
##############################################################################
#
# Copyright (c) 2013 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
zc.buildout
from
slapos.recipe.librecipe
import
GenericBaseRecipe
class
Recipe
(
GenericBaseRecipe
):
# XXX-Cedric: write docstring
def
install
(
self
):
path_list
=
[]
# Download and unpack application if not already existing
htdocs_location
=
self
.
options
[
'htdocs'
]
if
not
(
os
.
path
.
exists
(
htdocs_location
)
and
os
.
listdir
(
htdocs_location
)):
try
:
os
.
rmdir
(
htdocs_location
)
except
:
pass
self
.
download
(
htdocs_location
)
# 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
.
createWrapper
(
name
=
self
.
options
[
'wrapper'
],
command
=
self
.
options
[
'httpd-binary'
],
parameters
=
[
'-f'
,
self
.
options
[
'httpd-conf'
],
'-DFOREGROUND'
])
path_list
.
append
(
wrapper
)
return
path_list
slapos/recipe/lampgeneric/template/apache.in
0 → 100644
View file @
7a5346c6
# Apache static configuration
# Automatically generated
# Basic server configuration
PidFile "%(pid_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
Require all denied
</Directory>
<Directory %(document_root)s>
Options FollowSymLinks
AllowOverride All
Require all granted
</Directory>
DocumentRoot %(document_root)s
DirectoryIndex index.html index.php
# List of modules
LoadModule unixd_module modules/mod_unixd.so
LoadModule access_compat_module modules/mod_access_compat.so
LoadModule authz_core_module modules/mod_authz_core.so
LoadModule authz_host_module modules/mod_authz_host.so
LoadModule log_config_module modules/mod_log_config.so
LoadModule setenvif_module modules/mod_setenvif.so
LoadModule version_module modules/mod_version.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule mime_module modules/mod_mime.so
LoadModule dav_module modules/mod_dav.so
LoadModule dav_fs_module modules/mod_dav_fs.so
LoadModule negotiation_module modules/mod_negotiation.so
LoadModule rewrite_module modules/mod_rewrite.so
LoadModule headers_module modules/mod_headers.so
LoadModule dir_module modules/mod_dir.so
LoadModule php5_module modules/libphp5.so
LoadModule alias_module modules/mod_alias.so
slapos/recipe/lampgeneric/template/php.ini.in
0 → 100644
View file @
7a5346c6
[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=Off
slapos/recipe/librecipe/generic.py
View file @
7a5346c6
...
@@ -32,6 +32,7 @@ import os
...
@@ -32,6 +32,7 @@ import os
import
sys
import
sys
import
inspect
import
inspect
import
re
import
re
import
shutil
import
urllib
import
urllib
import
urlparse
import
urlparse
...
@@ -226,3 +227,30 @@ class GenericBaseRecipe(object):
...
@@ -226,3 +227,30 @@ class GenericBaseRecipe(object):
url
=
urlparse
.
urlunparse
((
scheme
,
netloc
,
path
,
params
,
query
,
fragment
))
url
=
urlparse
.
urlunparse
((
scheme
,
netloc
,
path
,
params
,
query
,
fragment
))
return
url
return
url
def
setLocationOption
(
self
):
if
not
self
.
options
.
get
(
'location'
):
self
.
options
[
'location'
]
=
os
.
path
.
join
(
self
.
buildout
[
'buildout'
][
'parts-directory'
],
self
.
name
)
def
download
(
self
,
destination
=
None
):
""" A simple wrapper around h.r.download, downloading to self.location"""
self
.
setLocationOption
()
import
hexagonit.recipe.download
if
not
destination
:
destination
=
self
.
location
if
os
.
path
.
exists
(
destination
):
# leftovers from a previous failed attempt, removing it.
log
.
warning
(
'Removing already existing directory %s'
%
destination
)
shutil
.
rmtree
(
destination
)
os
.
mkdir
(
destination
)
try
:
options
=
self
.
options
.
copy
()
options
[
'destination'
]
=
destination
hexagonit
.
recipe
.
download
.
Recipe
(
self
.
buildout
,
self
.
name
,
options
).
install
()
except
:
shutil
.
rmtree
(
destination
)
raise
slapos/recipe/publish.py
View file @
7a5346c6
...
@@ -28,6 +28,8 @@ import zc.buildout
...
@@ -28,6 +28,8 @@ import zc.buildout
from
slapos.recipe.librecipe
import
wrap
from
slapos.recipe.librecipe
import
wrap
from
slapos.recipe.librecipe
import
GenericSlapRecipe
from
slapos.recipe.librecipe
import
GenericSlapRecipe
CONNECTION_PARAMETER_STRING
=
'connection-'
class
Recipe
(
GenericSlapRecipe
):
class
Recipe
(
GenericSlapRecipe
):
def
_install
(
self
):
def
_install
(
self
):
publish_dict
=
dict
()
publish_dict
=
dict
()
...
@@ -47,3 +49,26 @@ SERIALISED_MAGIC_KEY = '_'
...
@@ -47,3 +49,26 @@ SERIALISED_MAGIC_KEY = '_'
class
Serialised
(
Recipe
):
class
Serialised
(
Recipe
):
def
_setConnectionDict
(
self
,
publish_dict
):
def
_setConnectionDict
(
self
,
publish_dict
):
return
super
(
Serialised
,
self
).
_setConnectionDict
(
wrap
(
publish_dict
))
return
super
(
Serialised
,
self
).
_setConnectionDict
(
wrap
(
publish_dict
))
class
PublishSection
(
GenericSlapRecipe
):
"""
Take a list of "request" sections, and publish every connection parameter.
Input:
section-list: String, representing the list of sections to fetch
parameters to publish, in order, separated by a space.
"""
def
_install
(
self
):
publish_dict
=
dict
()
for
section
in
self
.
options
[
'section-list'
].
strip
().
split
():
section
=
section
.
strip
()
options
=
self
.
buildout
[
section
].
copy
()
for
k
,
v
in
options
.
iteritems
():
if
k
.
startswith
(
CONNECTION_PARAMETER_STRING
):
print
k
,
v
publish_dict
[
k
.
lstrip
(
CONNECTION_PARAMETER_STRING
)]
=
v
self
.
setConnectionDict
(
publish_dict
)
return
[]
slapos/recipe/request.py
View file @
7a5346c6
...
@@ -215,7 +215,6 @@ class RequestOptional(Recipe):
...
@@ -215,7 +215,6 @@ class RequestOptional(Recipe):
update
=
install
update
=
install
class
Serialised
(
Recipe
):
class
Serialised
(
Recipe
):
def
_filterForStorage
(
self
,
partition_parameter_kw
):
def
_filterForStorage
(
self
,
partition_parameter_kw
):
return
wrap
(
partition_parameter_kw
)
return
wrap
(
partition_parameter_kw
)
...
@@ -225,3 +224,39 @@ class Serialised(Recipe):
...
@@ -225,3 +224,39 @@ class Serialised(Recipe):
return
json
.
loads
(
instance
.
getConnectionParameter
(
JSON_SERIALISED_MAGIC_KEY
))
return
json
.
loads
(
instance
.
getConnectionParameter
(
JSON_SERIALISED_MAGIC_KEY
))
except
slapmodule
.
NotFoundError
:
except
slapmodule
.
NotFoundError
:
return
{}
return
{}
CONNECTION_PARAMETER_STRING
=
'connection-'
class
RequestEdge
(
Recipe
):
"""
For each country in country-list, do a request.
"""
def
__init__
(
self
,
buildout
,
name
,
options
):
self
.
logger
=
logging
.
getLogger
(
name
)
self
.
options
=
options
self
.
request_dict
=
{}
# Keep a copy of original options dict
original_options
=
options
.
copy
()
for
country
in
options
[
'country-list'
].
split
(
','
):
# Request will have its own copy of options dict
local_options
=
original_options
.
copy
()
local_options
[
'name'
]
=
'%s-%s'
%
(
country
,
name
)
local_options
[
'sla'
]
=
"region"
local_options
[
'sla-region'
]
=
country
self
.
request_dict
[
country
]
=
Recipe
(
buildout
,
name
,
local_options
)
# "Bubble" all connection parameters
for
option
,
value
in
local_options
.
iteritems
():
if
option
.
startswith
(
CONNECTION_PARAMETER_STRING
):
self
.
options
[
'%s-%s'
%
(
option
,
country
)]
=
value
def
install
(
self
):
for
country
,
request
in
self
.
request_dict
.
iteritems
():
request
.
install
()
return
[]
update
=
install
slapos/recipe/softwaretype.py
View file @
7a5346c6
...
@@ -116,7 +116,7 @@ class Recipe:
...
@@ -116,7 +116,7 @@ class Recipe:
for
parameter
,
value
in
self
.
parameter_dict
.
items
():
for
parameter
,
value
in
self
.
parameter_dict
.
items
():
# All parameters evaluating to False are... False, and shouldn't
# All parameters evaluating to False are... False, and shouldn't
# convey any information.
# convey any information.
# Here, all those parameters are s
et to empty string
.
# Here, all those parameters are s
imply ignored
.
if
value
:
if
value
:
if
isinstance
(
value
,
str
):
if
isinstance
(
value
,
str
):
buildout
.
set
(
'slap-parameter'
,
parameter
,
value
)
buildout
.
set
(
'slap-parameter'
,
parameter
,
value
)
...
...
slapos/recipe/wrapper.py
View file @
7a5346c6
...
@@ -30,25 +30,32 @@ import shlex
...
@@ -30,25 +30,32 @@ import shlex
from
slapos.recipe.librecipe
import
GenericBaseRecipe
from
slapos.recipe.librecipe
import
GenericBaseRecipe
class
Recipe
(
GenericBaseRecipe
):
class
Recipe
(
GenericBaseRecipe
):
def
install
(
self
):
def
install
(
self
):
command_line
=
shlex
.
split
(
self
.
options
[
'command-line'
])
command_line
=
shlex
.
split
(
self
.
options
[
'command-line'
])
wrapper_path
=
self
.
options
[
'wrapper-path'
]
wait_files
=
self
.
options
.
get
(
'wait-for-files'
)
wait_files
=
self
.
options
.
get
(
'wait-for-files'
)
environment
=
self
.
options
.
get
(
'environment'
)
if
not
wait_files
and
not
environment
:
# Create a simple wrapper as shell script
return
[
self
.
createWrapper
(
name
=
wrapper_path
,
command
=
command_line
[
0
],
parameters
=
command_line
[
1
:],
)]
# More complex needs: create a Python script as wrapper
if
wait_files
is
not
None
:
if
wait_files
is
not
None
:
wait_files
=
[
filename
.
strip
()
for
filename
in
wait_files
.
split
()
wait_files
=
[
filename
.
strip
()
for
filename
in
wait_files
.
split
()
if
filename
.
strip
()]
if
filename
.
strip
()]
environment
=
self
.
options
.
get
(
'environment'
)
if
environment
is
not
None
:
if
environment
is
not
None
:
environment
=
dict
((
k
.
strip
(),
v
.
strip
())
for
k
,
v
in
[
environment
=
dict
((
k
.
strip
(),
v
.
strip
())
for
k
,
v
in
[
line
.
split
(
'='
)
line
.
split
(
'='
)
for
line
in
environment
.
split
(
'
\
n
'
)
for
line
in
environment
.
split
(
'
\
n
'
)
])
])
return
[
self
.
createPythonScript
(
return
[
self
.
createPythonScript
(
self
.
options
[
'output'
]
,
wrapper_path
,
'slapos.recipe.librecipe.execute.generic_exec'
,
'slapos.recipe.librecipe.execute.generic_exec'
,
(
command_line
,
wait_files
,
environment
,),
(
command_line
,
wait_files
,
environment
,),
)]
)]
slapos/recipe/zimbra_kvm/__init__.py
0 → 100644
View file @
7a5346c6
##############################################################################
#
# Copyright (c) 2011 Vifib SARL and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from
slapos.recipe.librecipe
import
GenericBaseRecipe
import
sys
class
Recipe
(
GenericBaseRecipe
):
"""
kvm instance configuration.
"""
def
install
(
self
):
config
=
dict
(
vnc_ip
=
self
.
options
[
'vnc-ip'
],
vnc_port
=
self
.
options
[
'vnc-port'
],
boot_disk_path
=
self
.
options
[
'boot-disk-path'
],
disk_path
=
self
.
options
[
'data-disk-path'
],
disk_size
=
self
.
options
[
'data-disk-size'
],
disk_type
=
self
.
options
[
'data-disk-type'
],
mac_address
=
self
.
options
[
'mac-address'
],
smp_count
=
self
.
options
[
'smp-count'
],
ram_size
=
self
.
options
[
'ram-size'
],
socket_path
=
self
.
options
[
'socket-path'
],
pid_file_path
=
self
.
options
[
'pid-path'
],
python_path
=
sys
.
executable
,
shell_path
=
self
.
options
[
'shell-path'
],
qemu_path
=
self
.
options
[
'qemu-path'
],
qemu_img_path
=
self
.
options
[
'qemu-img-path'
],
vnc_passwd
=
self
.
options
[
'passwd'
]
)
# Runners
runner_path
=
self
.
createExecutable
(
self
.
options
[
'runner-path'
],
self
.
substituteTemplate
(
self
.
getTemplateFilename
(
'kvm_run.in'
),
config
))
controller_path
=
self
.
createExecutable
(
self
.
options
[
'controller-path'
],
self
.
substituteTemplate
(
self
.
getTemplateFilename
(
'kvm_controller_run.in'
),
config
))
return
[
runner_path
,
controller_path
]
slapos/recipe/zimbra_kvm/template/kvm_controller_run.in
0 → 100644
View file @
7a5346c6
#!%(python_path)s
# BEWARE: This file is operated by slapgrid
# BEWARE: It will be overwritten automatically
# Echo client program
import socket
import time
# Connect to KVM qmp socket
so = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
connected = False
while not connected:
try:
so.connect('%(socket_path)s')
except socket.error:
time.sleep(1)
else:
connected = True
data = so.recv(1024)
# Enable qmp
so.send('{ "execute": "qmp_capabilities" }')
data = so.recv(1024)
# Set VNC password
so.send('{ "execute": "change", ' \
'"arguments": { "device": "vnc", "target": "password", ' \
' "arg": "%(vnc_passwd)s" } }')
data = so.recv(1024)
# Finish
so.close()
slapos/recipe/zimbra_kvm/template/kvm_run.in
0 → 100644
View file @
7a5346c6
#!%(python_path)s
# BEWARE: This file is operated by slapgrid
# BEWARE: It will be overwritten automatically
# Echo client program
import os
import socket
import subprocess
def getSocketStatus(host, port):
s = None
for res in socket.getaddrinfo(host, port,
socket.AF_UNSPEC, socket.SOCK_STREAM):
af, socktype, proto, canonname, sa = res
try:
s = socket.socket(af, socktype, proto)
except socket.error, msg:
s = None
continue
try:
s.connect(sa)
except socket.error, msg:
s.close()
s = None
continue
break
return s
# create disk if doesn't exist
disk_path = '%(disk_path)s'
if not os.path.exists(disk_path):
subprocess.Popen(['%(qemu_img_path)s', 'create' ,'-f', 'qcow2',
disk_path, '%(disk_size)sG'])
# Generate NAT rules
nat_rules = ",".join("hostfwd=tcp:%(vnc_ip)s:%%s-:%%s" %% (port, port) for port in [25, 80, 110, 143, 443, 465, 587, 993, 995, 7071])
kvm_argument_list = ['%(qemu_path)s',
'-enable-kvm', '-net', 'nic,macaddr=%(mac_address)s',
'-net', 'user,hostfwd=tcp:%(vnc_ip)s:2222-:22,%%s' %% nat_rules,
'-smp', '%(smp_count)s',
'-m', '%(ram_size)s',
'-drive', 'file=%(disk_path)s,if=%(disk_type)s',
#'-drive', 'file=%(boot_disk_path)s,if=%(disk_type)s',
'-vnc', '%(vnc_ip)s:1,ipv4,password',
'-boot', 'menu=on',
'-qmp', 'unix:%(socket_path)s,server',
'-pidfile', '%(pid_file_path)s',
]
os.execv('%(qemu_path)s', kvm_argument_list)
software/apache-frontend/README.apache_frontend.txt
View file @
7a5346c6
...
@@ -83,6 +83,7 @@ port
...
@@ -83,6 +83,7 @@ port
Port used by Apache. Optional parameter, defaults to 4443.
Port used by Apache. Optional parameter, defaults to 4443.
plain_http_port
plain_http_port
~~~~~~~~~~~~~~~
Port used by apache to serve plain http (only used to redirect to https).
Port used by apache to serve plain http (only used to redirect to https).
Optional parameter, defaults to 8080.
Optional parameter, defaults to 8080.
...
@@ -192,7 +193,12 @@ Notes
...
@@ -192,7 +193,12 @@ Notes
=====
=====
It is not possible with slapos to listen to port <= 1024, because process are
It is not possible with slapos to listen to port <= 1024, because process are
not run as root. It is a good idea then to go on the node where the instance is
not run as root.
Solution 1
----------
It is a good idea then to go on the node where the instance is
and set some iptables rules like (if using default ports)::
and set some iptables rules like (if using default ports)::
iptables -t nat -A PREROUTING -p tcp -d {public_ipv4} --dport 443 -j DNAT --to-destination {listening_ipv4}:4443
iptables -t nat -A PREROUTING -p tcp -d {public_ipv4} --dport 443 -j DNAT --to-destination {listening_ipv4}:4443
...
@@ -200,3 +206,12 @@ and set some iptables rules like (if using default ports)::
...
@@ -200,3 +206,12 @@ and set some iptables rules like (if using default ports)::
Where {public ip} is the public IP of your server, or at least the LAN IP to where your NAT will forward to.
Where {public ip} is the public IP of your server, or at least the LAN IP to where your NAT will forward to.
{listening ip} is the private ipv4 (like 10.0.34.123) that the instance is using and sending as connection parameter.
{listening ip} is the private ipv4 (like 10.0.34.123) that the instance is using and sending as connection parameter.
Solution 2
----------
It is also possible to directly allow the service to listen on 80 and 443 ports using the following command:
setcap 'cap_net_bind_service=+ep' /opt/slapgrid/$APACHE_FRONTEND_SOFTWARE_RELEASE_MD5/parts/apache-2.2/bin/httpd
Then specify in the instance parameters "port" and "plain_http_port" to be 443 and 80, respectively.
software/helloworld/instance.cfg.in
0 → 100644
View file @
7a5346c6
#############################
#
# Deploy hello-world instance
#
#############################
[buildout]
parts =
directory
hello-world
publish-connection-parameter
# Define egg directories to be the one from Software Release
# (/opt/slapgrid/...)
# Always the same.
eggs-directory = ${buildout:eggs-directory}
develop-eggs-directory = ${buildout:develop-eggs-directory}
offline = true
[instance-parameter]
# Fetches parameters defined in SlapOS Master for this instance.
# Always the same.
recipe = slapos.cookbook:slapconfiguration
computer = $${slap_connection:computer_id}
partition = $${slap_connection:partition_id}
url = $${slap_connection:server_url}
key = $${slap_connection:key_file}
cert = $${slap_connection:cert_file}
# Define default parameter(s) that will be used later, in case user didn't
# specify it
name = anonymous
# Create all needed directories, depending on your needs
[directory]
recipe = slapos.cookbook:mkdirectory
etc = $${buildout:directory}/etc
# Executables put here will be started but not monitored (for startup scripts)
script = $${:etc}/run/
# Executables put here will be started and monitored (for daemons)
service = $${:etc}/service
# Executables put here will be launched after buildout has completed to see
# if instance is running
promise = $${:etc}/promise/
# Create a simple shell script that will only output your name if you
# specified it as instance parameter.
# Usually, of course, we use more useful commands, like web servers.
[hello-world]
# This recipe will try to "exec" the command-line after separating parameters.
recipe = slapos.cookbook:wrapper
# Notice that there is only one $ at ${dash:location}, it is because it comes from the Software Release buildout profile.
command-line = ${dash:location}/bin/dash -c 'echo "Hello $${instance-parameter:name}!"; sleep 100000;'
# Put this shell script in the "etc/service" directory. Every executable of this
# repository will be started and monitored by supervisord
wrapper-path = $${directory:service}/hello-world
# Publish all the parameters needed for the user to connect to the instance.
# It can be anything: URL(s), password(s), or arbitrary parameters.
# Here we'll just echo back the entered name as instance parameter
[publish-connection-parameter]
recipe = slapos.cookbook:publish
name = Hello $${instance-parameter:name}!
software/helloworld/software.cfg
0 → 100644
View file @
7a5346c6
[buildout]
extends =
# "slapos" stack describes basic things needed for 99.9% of SlapOS Software
# Releases
../../stack/slapos.cfg
# Extend here component profiles, like openssl, apache, mariadb, curl...
# Or/and extend a stack (lamp, tomcat) that does most of the work for you
# In this example we only need the dash binary to run a simple "hello world"
# shell script.
../../component/dash/buildout.cfg
parts =
# Call installation of slapos.cookbook egg defined in stack/slapos.cfg (needed
# in 99,9% of Slapos Software Releases)
slapos-cookbook
# Call creation of instance.cfg file that will be called for deployment of
# instance
template
# Download instance.cfg.in (buildout profile used to deployment of instance),
# replace all ${foo:bar} parameters by real values, and change $${foo:bar} to
# ${foo:bar}
[template]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/instance.cfg.in
output = ${buildout:directory}/instance.cfg
# MD5 checksum can be skipped for development, but must be filled for production
#md5sum =
mode = 0644
software/lamp-generic/README.txt
0 → 100644
View file @
7a5346c6
This Software Release represents a generic LAMP service.
The PHP application is given to the instance by parameter as URL of application archive.
XXX-Cedric: what about application configuration?
\ No newline at end of file
software/lamp-generic/development.cfg
0 → 100644
View file @
7a5346c6
# Exactly the same as software.cfg, but fetch the slapos.cookbook and
# slapos.toolbox from git repository instead of fetching stable version,
# allowing to play with bleeding edge environment.
# You'll need to run buildout twice for this profile.
[buildout]
extends =
../../component/git/buildout.cfg
software.cfg
parts +=
# Development parts
slapos.cookbook-repository
slapos.core-repository
slapos.toolbox-repository
check-recipe
develop =
${:parts-directory}/slapos.cookbook-repository
${:parts-directory}/slapos.core-repository
${:parts-directory}/slapos.toolbox-repository
[slapos.toolbox-repository]
recipe = slapos.recipe.build:gitclone
repository = http://git.erp5.org/repos/slapos.toolbox.git
branch = master
git-executable = ${git:location}/bin/git
[slapos.cookbook-repository]
recipe = slapos.recipe.build:gitclone
repository = http://git.erp5.org/repos/slapos.git
branch = lamp-edge
git-executable = ${git:location}/bin/git
[slapos.core-repository]
recipe = slapos.recipe.build:gitclone
repository = http://git.erp5.org/repos/slapos.core.git
branch = master
git-executable = ${git:location}/bin/git
[check-recipe]
recipe = plone.recipe.command
stop-on-error = true
update-command = ${:command}
command =
grep parts ${buildout:develop-eggs-directory}/slapos.cookbook.egg-link &&
grep parts ${buildout:develop-eggs-directory}/slapos.core.egg-link &&
grep parts ${buildout:develop-eggs-directory}/slapos.toolbox.egg-link
[versions]
slapos.cookbook =
slapos.toolbox =
slapos.core =
software/lamp-generic/instance-apache-php.cfg.in
0 → 100644
View file @
7a5346c6
[buildout]
parts =
logrotate
logrotate-entry-apache
cron
cron-entry-logrotate
promise
frontend-promise
publish-connection-informations
eggs-directory = ${buildout:eggs-directory}
develop-eggs-directory = ${buildout:develop-eggs-directory}
newest = false
#----------------
#--
#-- Creation of all needed directories.
[rootdirectory]
recipe = slapos.cookbook:mkdirectory
etc = $${buildout:directory}/etc
var = $${buildout:directory}/var
srv = $${buildout:directory}/srv
bin = $${buildout:directory}/bin
tmp = $${buildout:directory}/tmp
[basedirectory]
recipe = slapos.cookbook:mkdirectory
log = $${rootdirectory:var}/log
services = $${rootdirectory:etc}/service
run = $${rootdirectory:var}/run
backup = $${rootdirectory:srv}/backup
promises = $${rootdirectory:etc}/promise
[directory]
recipe = slapos.cookbook:mkdirectory
cron-entries = $${rootdirectory:etc}/cron.d
crontabs = $${rootdirectory:etc}/crontabs
cronstamps = $${rootdirectory:etc}/cronstamps
ca-dir = $${rootdirectory:srv}/ssl
httpd-log = $${basedirectory:log}/apache
php-ini-dir = $${rootdirectory:etc}/php
tmp-php = $${rootdirectory:tmp}/php
logrotate-entries = $${rootdirectory:etc}/logrotate.d
logrotate-backup = $${basedirectory:backup}/logrotate
report = $${rootdirectory:etc}/report
stunnel-conf = $${rootdirectory:etc}/stunnel
xml-report = $${rootdirectory:var}/xml_report
www = $${rootdirectory:srv}/www/
[cadirectory]
recipe = slapos.cookbook:mkdirectory
requests = $${directory:ca-dir}/requests
private = $${directory:ca-dir}/private
certs = $${directory:ca-dir}/certs
newcerts = $${directory:ca-dir}/newcerts
crl = $${directory:ca-dir}/crl
#----------------
#--
#-- Deploy cron.
[cron]
recipe = slapos.cookbook:cron
dcrond-binary = ${dcron:location}/sbin/crond
cron-entries = $${directory:cron-entries}
crontabs = $${directory:crontabs}
cronstamps = $${directory:cronstamps}
catcher = $${cron-simplelogger:wrapper}
binary = $${basedirectory:services}/crond
[cron-simplelogger]
recipe = slapos.cookbook:simplelogger
wrapper = $${rootdirectory:bin}/cron_simplelogger
log = $${basedirectory:log}/crond.log
#----------------
#--
#-- Deploy logrotate.
[cron-entry-logrotate]
<= cron
recipe = slapos.cookbook:cron.d
name = logrotate
frequency = 0 0 * * *
command = $${logrotate:wrapper}
[logrotate]
recipe = slapos.cookbook:logrotate
# Binaries
logrotate-binary = ${logrotate:location}/usr/sbin/logrotate
gzip-binary = ${gzip:location}/bin/gzip
gunzip-binary = ${gzip:location}/bin/gunzip
# Directories
wrapper = $${rootdirectory:bin}/logrotate
conf = $${rootdirectory:etc}/logrotate.conf
logrotate-entries = $${directory:logrotate-entries}
backup = $${directory:logrotate-backup}
state-file = $${rootdirectory:srv}/logrotate.status
#----------------
#--
#-- Deploy Apache + PHP application.
[apache-php]
recipe = slapos.cookbook:lamp.generic
url = $${slap-parameter:application-location}
strip-top-level-dir = true
# md5sum =
# XXX-Cedric: add some "template" configuration
htdocs = $${directory:www}
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
httpd-binary = ${apache:location}/bin/httpd
[logrotate-entry-apache]
<= logrotate
recipe = slapos.cookbook:logrotate.d
name = apache
log = $${apache-php:error-log} $${apache-php:access-log}
frequency = daily
rotate-num = 30
sharedscripts = true
notifempty = true
create = true
#----------------
#--
#-- Request frontend.
[request-frontend]
<= slap-connection
recipe = slapos.cookbook:requestoptional
name = Frontend
# XXX We have hardcoded SR URL here.
software-url = http://git.erp5.org/gitweb/slapos.git/blob_plain/HEAD:/software/apache-frontend/software.cfg
slave = true
config = url custom_domain
config-url = http://[$${apache-php:ip}]:$${apache-php:port}/
return = site_url
config-custom_domain = $${slap-parameter:domain}
#----------------
#--
#-- Publish instance parameters.
[publish-connection-informations]
recipe = slapos.cookbook:publish
backend-url = http://[$${apache-php:ip}]:$${apache-php:port}/
url = $${request-frontend:connection-site_url}
#----------------
#--
#-- Deploy promises scripts.
[promise]
recipe = slapos.cookbook:check_port_listening
path = $${basedirectory:promises}/apache
hostname = $${apache-php:ip}
port = $${apache-php:port}
[frontend-promise]
recipe = slapos.cookbook:check_url_available
path = $${basedirectory:promises}/frontend
url = $${request-frontend:connection-site_url}
dash_path = ${dash:location}/bin/dash
curl_path = ${curl:location}/bin/curl
[slap-parameter]
# Default value if no domain is specified
domain =
# Default value if no ssh parameter is specified
logbox-ip =
logbox-port =
logbox-user =
logbox-passwd =
software/lamp-generic/instance-edge.cfg.in
0 → 100644
View file @
7a5346c6
# This instance will request other instances of lamp-generic depending on a
# list of countries.
[buildout]
parts =
request-edge
publish-connection-parameter
eggs-directory = ${buildout:eggs-directory}
develop-eggs-directory = ${buildout:develop-eggs-directory}
offline = true
[request-edge]
<= slap-connection
recipe = slapos.cookbook:request.edge
# This magic parameter triggers several requests, one request per country.
name = lamp
return = url backend-url
country-list = $${slap-parameter:country-list}
software-url = $${slap-connection:software-release-url}
software-type = default
config = application-location
config-application-location = $${slap-parameter:application-location}
return = backend-url
[publish-connection-parameter]
recipe = slapos.cookbook:publishsection
section-list = request-edge
software/lamp-generic/instance.cfg.in
0 → 100644
View file @
7a5346c6
[buildout]
parts =
switch_softwaretype
eggs-directory = ${buildout:eggs-directory}
develop-eggs-directory = ${buildout:develop-eggs-directory}
offline = true
[switch_softwaretype]
recipe = slapos.cookbook:softwaretype
default = ${instance-apache-php:output}
edge = ${instance-edge:output}
software/lamp-generic/software.cfg
0 → 100644
View file @
7a5346c6
[buildout]
extends =
../../stack/lamp/buildout.cfg
parts +=
instance-edge
# XXX: switch to ngnix
[instance]
url = ${:_profile_base_location_}/instance.cfg.in
md5sum = 26ac6629a83869140189a85e581e822f
[instance-apache-php]
url = ${:_profile_base_location_}/instance-apache-php.cfg.in
md5sum = fdc849c9f49b9d2fb043bf229d24076b
[instance-edge]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/instance-edge.cfg.in
output = ${buildout:directory}/instance-edge.cfg
#md5sum = 6b7a6caf44e3a94bed7f89c04003a171
mode = 0644
software/zimbra-kvm/README.txt
0 → 100644
View file @
7a5346c6
zimbra-kvm
==========
Introduction
------------
Zimbra single-machine deployment inside of a virtual machine.
Internals
---------
The following ports are reachable from the outside world:
22 -> 2222
443 -> 4443
Others?
For each port, KVM does a NAT redirection from the VM to the local ipv4. Then, 6tunnel is called to redirect it to the outside world using ipv6.
Deployment
----------
To deploy a new Zimbra service, you just need to request a new instance of it,
then connect the the machine using ssh with root:zimbra credentials, reconfigure
Zimbra to use another domain name, and change root password.
Disk Image content
------------------
Ubuntu 12.04, Zimbra install from official packages, 8.0.3
admin password: Cedric de Saint Martin has it.
bind9: http://wiki.zimbra.com/index.php?title=Split_dns
resolv.conf: http://askubuntu.com/questions/30942/why-does-my-resolv-conf-file-get-regenerated-every-time
Todo
----
* SMTP master/slave design implemented
* Reverse proxy for web works
* Automatically download the proper boot disk image.
* Have two virtual disks: one for system/zimbra, one for data.
* Unify smtp frontend and web frontend
software/zimbra-kvm/common.cfg
0 → 100644
View file @
7a5346c6
[buildout]
extends =
../../component/6tunnel/buildout.cfg
../../component/curl/buildout.cfg
../../component/dash/buildout.cfg
../../component/dcron/buildout.cfg
../../component/gzip/buildout.cfg
../../component/qemu-kvm/buildout.cfg
../../component/logrotate/buildout.cfg
../../component/noVNC/buildout.cfg
../../component/openssl/buildout.cfg
../../stack/slapos.cfg
parts =
template
eggs
[eggs]
recipe = z3c.recipe.scripts
eggs =
${lxml-python:egg}
websockify
slapos.cookbook
slapos.toolbox
[template-kvm]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/instance-kvm.cfg.in
#md5sum = d4f7203365bacd70ad62f6b6de9f74d4
output = ${buildout:directory}/template-kvm.cfg
mode = 0644
[template]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/instance.cfg.in
#md5sum = 68788763d23f70f24b9e575871c903a8
output = ${buildout:directory}/template.cfg
mode = 0644
[versions]
# Numpy 1.7.0 doesn't install well
numpy = 1.6.2
software/zimbra-kvm/development.cfg
0 → 100644
View file @
7a5346c6
[buildout]
extends =
../../component/git/buildout.cfg
common.cfg
parts +=
slapos.cookbook-repository
slapos.toolbox-repository
check-recipe
develop =
${:parts-directory}/slapos.cookbook-repository
${:parts-directory}/slapos.toolbox-repository
[slapos.cookbook-repository]
recipe = slapos.recipe.build:gitclone
repository = http://git.erp5.org/repos/slapos.git
branch = zimbra-kvm
git-executable = ${git:location}/bin/git
[slapos.toolbox-repository]
recipe = slapos.recipe.build:gitclone
repository = http://git.erp5.org/repos/slapos.toolbox.git
branch = master
git-executable = ${git:location}/bin/git
[check-recipe]
recipe = plone.recipe.command
stop-on-error = true
update-command = ${:command}
command =
grep parts ${buildout:develop-eggs-directory}/slapos.cookbook.egg-link &&
grep parts ${buildout:develop-eggs-directory}/slapos.toolbox.egg-link
software/zimbra-kvm/instance-kvm.cfg.in
0 → 100644
View file @
7a5346c6
#############################
#
# Instanciate kvm
#
#############################
[buildout]
parts =
certificate-authority
request-web-frontend
kvm-promise
tunnel-ipv6-kvm-https
tunnel-ipv6-kvm-ssh
tunnel-ipv6-kvm-zimbra-admin
tunnel-ipv6-kvm-smtp
tunnel-ipv6-kvm-smtp-submission
websockify-sighandler
novnc-promise
publish-kvm-connection-information
eggs-directory = ${buildout:eggs-directory}
develop-eggs-directory = ${buildout:develop-eggs-directory}
offline = true
[directory]
recipe = slapos.cookbook:mkdirectory
etc = $${buildout:directory}/etc
bin = $${buildout:directory}/bin
srv = $${buildout:directory}/srv
var = $${buildout:directory}/var
scripts = $${:etc}/run
services = $${:etc}/service
promises = $${:etc}/promise
novnc-conf = $${:etc}/novnc
run = $${:var}/run
ca-dir = $${:srv}/ssl
[create-mac]
recipe = slapos.cookbook:generate.mac
storage-path = $${directory:srv}/mac
[gen-passwd]
recipe = slapos.cookbook:generate.password
storage-path = $${directory:srv}/passwd
bytes = 4
[kvm-instance]
# XXX-Cedric: change "KVM" recipe to simple "create wrappers". No need for this
# Specific code
recipe = slapos.cookbook:zimbra.kvm
vnc-ip = $${slap-network-information:local-ipv4}
vnc-port = 5901
boot-disk-path = $${directory:srv}/boot.qcow2
data-disk-path = $${directory:srv}/virtual.qcow2
data-disk-size = $${slap-parameter:disk-size}
data-disk-type = $${slap-parameter:disk-type}
socket-path = $${directory:var}/qmp_socket
pid-path = $${directory:run}/pid_file
smp-count = $${slap-parameter:cpu-count}
ram-size = $${slap-parameter:ram-size}
disk-type = virtio
mac-address = $${create-mac:mac-address}
runner-path = $${directory:services}/kvm
controller-path = $${directory:scripts}/kvm_controller
shell-path = ${dash:location}/bin/dash
qemu-path = ${kvm:location}/bin/qemu-system-x86_64
qemu-img-path = ${kvm:location}/bin/qemu-img
passwd = $${gen-passwd:passwd}
[kvm-promise]
recipe = slapos.cookbook:check_port_listening
path = $${directory:promises}/vnc_promise
hostname = $${kvm-instance:vnc-ip}
port = $${kvm-instance:vnc-port}
# 6tunnel
# Refers to http://wiki.zimbra.com/wiki/Ports#External_Access
[tunnel-ipv6-kvm-https]
recipe = slapos.cookbook:ipv6toipv4
ipv6 = $${slap-network-information:global-ipv6}
ipv6-port = 443
ipv4 = $${slap-network-information:local-ipv4}
ipv4-port = 443
shell-path = ${dash:location}/bin/dash
6tunnel-path = ${6tunnel:location}/bin/6tunnel
runner-path = $${directory:services}/6tunnel-https
[tunnel-ipv6-kvm-zimbra-admin]
recipe = slapos.cookbook:ipv6toipv4
ipv6 = $${slap-network-information:global-ipv6}
ipv6-port = 7071
ipv4 = $${slap-network-information:local-ipv4}
ipv4-port = 7071
shell-path = ${dash:location}/bin/dash
6tunnel-path = ${6tunnel:location}/bin/6tunnel
runner-path = $${directory:services}/6tunnel-zimbra_admin
[tunnel-ipv6-kvm-ssh]
recipe = slapos.cookbook:ipv6toipv4
ipv6 = $${slap-network-information:global-ipv6}
ipv6-port = 2222
ipv4 = $${slap-network-information:local-ipv4}
ipv4-port = 2222
shell-path = ${dash:location}/bin/dash
6tunnel-path = ${6tunnel:location}/bin/6tunnel
runner-path = $${directory:services}/6tunnel-ssh
[tunnel-ipv6-kvm-smtp]
recipe = slapos.cookbook:ipv6toipv4
ipv6 = $${slap-network-information:global-ipv6}
ipv6-port = 25
ipv4 = $${slap-network-information:local-ipv4}
ipv4-port = 25
shell-path = ${dash:location}/bin/dash
6tunnel-path = ${6tunnel:location}/bin/6tunnel
runner-path = $${directory:services}/6tunnel-smtp
[tunnel-ipv6-kvm-smtp-submission]
recipe = slapos.cookbook:ipv6toipv4
ipv6 = $${slap-network-information:global-ipv6}
ipv6-port = 587
ipv4 = $${slap-network-information:local-ipv4}
ipv4-port = 587
shell-path = ${dash:location}/bin/dash
6tunnel-path = ${6tunnel:location}/bin/6tunnel
runner-path = $${directory:services}/6tunnel-smtp-submission
[novnc-instance]
recipe = slapos.cookbook:novnc
path = $${ca-novnc:executable}
ip = $${slap-network-information:global-ipv6}
port = 6080
vnc-ip = $${kvm-instance:vnc-ip}
vnc-port = $${kvm-instance:vnc-port}
novnc-location = ${noVNC:location}
websockify-path = ${buildout:directory}/bin/websockify
ssl-key-path = $${ca-novnc:key-file}
ssl-cert-path = $${ca-novnc:cert-file}
[websockify-sighandler]
recipe = slapos.cookbook:signalwrapper
wrapper-path = $${directory:services}/websockify
wrapped-path = $${novnc-instance:path}
[certificate-authority]
recipe = slapos.cookbook:certificate_authority
openssl-binary = ${openssl:location}/bin/openssl
ca-dir = $${directory:ca-dir}
requests-directory = $${cadirectory:requests}
wrapper = $${directory:services}/certificate_authority
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-novnc]
<= certificate-authority
recipe = slapos.cookbook:certificate_authority.request
key-file = $${directory:novnc-conf}/novnc.key
cert-file = $${directory:novnc-conf}/novnc.crt
executable = $${directory:bin}/novnc
wrapper = $${directory:bin}/websockify
[novnc-promise]
recipe = slapos.cookbook:check_port_listening
path = $${directory:promises}/novnc_promise
hostname = $${novnc-instance:ip}
port = $${novnc-instance:port}
[kvm-monitor]
recipe = slapos.cookbook:generic.slapmonitor
db-path = $${directory:srv}/slapmonitor_database
[request-slave-frontend]
recipe = slapos.cookbook:requestoptional
software-url = $${slap-parameter:frontend-software-url}
server-url = $${slap-connection:server-url}
key-file = $${slap-connection:key-file}
cert-file = $${slap-connection:cert-file}
computer-id = $${slap-connection:computer-id}
partition-id = $${slap-connection:partition-id}
name = VNC Frontend
software-type = $${slap-parameter:frontend-software-type}
slave = true
config = host port
config-host = $${novnc-instance:ip}
config-port = $${novnc-instance:port}
return = url resource port domainname
sla = instance_guid
sla-instance_guid = $${slap-parameter:frontend-instance-guid}
[request-web-frontend]
<= slap-connection
recipe = slapos.cookbook:requestoptional
name = Web Frontend
# XXX We have hardcoded SR URL here.
software-url = http://git.erp5.org/gitweb/slapos.git/blob_plain/HEAD:/software/apache-frontend/software.cfg
slave = true
config = url custom_domain
config-url = https://[$${tunnel-ipv6-kvm-https:ipv6}]:$${tunnel-ipv6-kvm-https:ipv6-port}/
return = site_url
config-custom_domain = $${slap-parameter:domain}
[publish-kvm-connection-information]
recipe = slapos.cookbook:publish
web-backend-url = https://[$${tunnel-ipv6-kvm-https:ipv6}]:$${tunnel-ipv6-kvm-https:ipv6-port}/
web-url = $${request-web-frontend:connection-site_url}
vnc-backend-url = https://[$${novnc-instance:ip}]:$${novnc-instance:port}/vnc_auto.html?host=[$${novnc-instance:ip}]&port=$${novnc-instance:port}&encrypt=1
vnc-password = $${kvm-instance:passwd}
vnc-url = $${request-slave-frontend:connection-url}/vnc_auto.html?host=$${request-slave-frontend:connection-domainname}&port=$${request-slave-frontend:connection-port}&encrypt=1&path=$${request-slave-frontend:connection-resource}
ssh = ssh root@$${tunnel-ipv6-kvm-ssh:ipv6} -p $${tunnel-ipv6-kvm-ssh:ipv6-port}
[slap-parameter]
# Default values if not specified
frontend-instance-guid =
frontend-software-type = frontend
frontend-software-url = http://git.erp5.org/gitweb/slapos.git/blob_plain/refs/tags/slapos-0.92:/software/kvm/software.cfg
ram-size = 4096
disk-size = 50
disk-type = virtio
cpu-count = 4
domain =
software/zimbra-kvm/instance.cfg.in
0 → 100644
View file @
7a5346c6
[buildout]
parts =
switch-softwaretype
eggs-directory = ${buildout:eggs-directory}
develop-eggs-directory = ${buildout:develop-eggs-directory}
offline = true
[switch-softwaretype]
recipe = slapos.cookbook:softwaretype
default = ${template-kvm:output}
[slap-connection]
# part to migrate to new - separated words
computer-id = $${slap_connection:computer_id}
partition-id = $${slap_connection:partition_id}
server-url = $${slap_connection:server_url}
software-release-url = $${slap_connection:software_release_url}
key-file = $${slap_connection:key_file}
cert-file = $${slap_connection:cert_file}
software/zimbra-kvm/software.cfg
0 → 100644
View file @
7a5346c6
[buildout]
extends = common.cfg
[networkcache]
# signature certificates of the following uploaders.
# Romain Courteaud
# Cedric de Saint Martin
# Test Agent
signature-certificate-list =
-----BEGIN CERTIFICATE-----
MIIB4DCCAUkCADANBgkqhkiG9w0BAQsFADA5MQswCQYDVQQGEwJGUjEZMBcGA1UE
CBMQRGVmYXVsdCBQcm92aW5jZTEPMA0GA1UEChMGTmV4ZWRpMB4XDTExMDkxNTA5
MDAwMloXDTEyMDkxNTA5MDAwMlowOTELMAkGA1UEBhMCRlIxGTAXBgNVBAgTEERl
ZmF1bHQgUHJvdmluY2UxDzANBgNVBAoTBk5leGVkaTCBnzANBgkqhkiG9w0BAQEF
AAOBjQAwgYkCgYEApYZv6OstoqNzxG1KI6iE5U4Ts2Xx9lgLeUGAMyfJLyMmRLhw
boKOyJ9Xke4dncoBAyNPokUR6iWOcnPHtMvNOsBFZ2f7VA28em3+E1JRYdeNUEtX
Z0s3HjcouaNAnPfjFTXHYj4um1wOw2cURSPuU5dpzKBbV+/QCb5DLheynisCAwEA
ATANBgkqhkiG9w0BAQsFAAOBgQBCZLbTVdrw3RZlVVMFezSHrhBYKAukTwZrNmJX
mHqi2tN8tNo6FX+wmxUUAf3e8R2Ymbdbn2bfbPpcKQ2fG7PuKGvhwMG3BlF9paEC
q7jdfWO18Zp/BG7tagz0jmmC4y/8akzHsVlruo2+2du2freE8dK746uoMlXlP93g
QUUGLQ==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB9jCCAV+gAwIBAgIJAO4V/jiMoICoMA0GCSqGSIb3DQEBBQUAMBMxETAPBgNV
BAMMCENPTVAtMjMyMCAXDTEyMDIxNjExMTAyM1oYDzIxMTIwMTIzMTExMDIzWjAT
MREwDwYDVQQDDAhDT01QLTIzMjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
wi/3Z8W9pUiegUXIk/AiFDQ0UJ4JFAwjqr+HSRUirlUsHHT+8DzH/hfcTDX1I5BB
D1ADk+ydXjMm3OZrQcXjn29OUfM5C+g+oqeMnYQImN0DDQIOcUyr7AJc4xhvuXQ1
P2pJ5NOd3tbd0kexETa1LVhR6EgBC25LyRBRae76qosCAwEAAaNQME4wHQYDVR0O
BBYEFMDmW9aFy1sKTfCpcRkYnP6zUd1cMB8GA1UdIwQYMBaAFMDmW9aFy1sKTfCp
cRkYnP6zUd1cMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAskbFizHr
b6d3iIyN+wffxz/V9epbKIZVEGJd/6LrTdLiUfJPec7FaxVCWNyKBlCpINBM7cEV
Gn9t8mdVQflNqOlAMkOlUv1ZugCt9rXYQOV7rrEYJBWirn43BOMn9Flp2nibblby
If1a2ZoqHRxoNo2yTmm7TSYRORWVS+vvfjY=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIB9jCCAV+gAwIBAgIJAKRvzcy7OH0UMA0GCSqGSIb3DQEBBQUAMBMxETAPBgNV
BAMMCENPTVAtNzcyMCAXDTEyMDgxMDE1NDI1MVoYDzIxMTIwNzE3MTU0MjUxWjAT
MREwDwYDVQQDDAhDT01QLTc3MjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
o7aipd6MbnuGDeR1UJUjuMLQUariAyQ2l2ZDS6TfOwjHiPw/mhzkielgk73kqN7A
sUREx41eTcYCXzTq3WP3xCLE4LxLg1eIhd4nwNHj8H18xR9aP0AGjo4UFl5BOMa1
mwoyBt3VtfGtUmb8whpeJgHhqrPPxLoON+i6fIbXDaUCAwEAAaNQME4wHQYDVR0O
BBYEFEfjy3OopT2lOksKmKBNHTJE2hFlMB8GA1UdIwQYMBaAFEfjy3OopT2lOksK
mKBNHTJE2hFlMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAaNRx6YN2
M/p3R8/xS6zvH1EqJ3FFD7XeAQ52WuQnKSREzuw0dsw12ClxjcHiQEFioyTiTtjs
5pW18Ry5Ie7iFK4cQMerZwWPxBodEbAteYlRsI6kePV7Gf735Y1RpuN8qZ2sYL6e
x2IMeSwJ82BpdEI5niXxB+iT0HxhmR+XaMI=
-----END CERTIFICATE-----
[versions]
numpy = 1.6.2
Jinja2 = 2.6
Werkzeug = 0.8.3
apache-libcloud = 0.12.1
async = 0.6.1
buildout-versions = 1.7
gitdb = 0.5.4
hexagonit.recipe.cmmi = 1.6
lxml = 3.1.0
meld3 = 0.6.10
plone.recipe.command = 1.1
pycrypto = 2.6
slapos.cookbook = 0.73.1
slapos.recipe.template = 2.4.2
slapos.toolbox = 0.33.1
smmap = 0.8.2
websockify = 0.3.0
z3c.recipe.scripts = 1.0.1
# Required by:
# slapos.core==0.35.1
# slapos.toolbox==0.33.1
Flask = 0.9
# Required by:
# slapos.toolbox==0.33.1
GitPython = 0.3.2.RC1
# Required by:
# slapos.toolbox==0.33.1
atomize = 0.1.1
# Required by:
# slapos.toolbox==0.33.1
feedparser = 5.1.3
# Required by:
# hexagonit.recipe.cmmi==1.6
hexagonit.recipe.download = 1.6nxd002
# Required by:
# slapos.cookbook==0.73.1
inotifyx = 0.2.0
# Required by:
# slapos.cookbook==0.73.1
netaddr = 0.7.10
# Required by:
# slapos.core==0.35.1
netifaces = 0.8
# Required by:
# slapos.toolbox==0.33.1
paramiko = 1.10.0
# Required by:
# slapos.toolbox==0.33.1
psutil = 0.6.1
# Required by:
# slapos.core==0.35.1
pyflakes = 0.6.1
# Required by:
# slapos.cookbook==0.73.1
pytz = 2012j
# Required by:
# slapos.cookbook==0.73.1
# slapos.core==0.35.1
# slapos.toolbox==0.33.1
setuptools = 0.6c12dev-r88846
# Required by:
# slapos.cookbook==0.73.1
# slapos.toolbox==0.33.1
slapos.core = 0.35.1
# Required by:
# slapos.core==0.35.1
supervisor = 3.0b1
# Required by:
# slapos.core==0.35.1
unittest2 = 0.5.1
# Required by:
# slapos.cookbook==0.73.1
# slapos.toolbox==0.33.1
xml-marshaller = 0.9.7
# Required by:
# slapos.core==0.35.1
zope.interface = 4.0.5
\ No newline at end of file
stack/lamp/buildout.cfg
View file @
7a5346c6
...
@@ -297,6 +297,7 @@ inotifyx = 0.2.0
...
@@ -297,6 +297,7 @@ inotifyx = 0.2.0
lxml = 3.1.0
lxml = 3.1.0
meld3 = 0.6.10
meld3 = 0.6.10
netaddr = 0.7.10
netaddr = 0.7.10
plone.recipe.command = 1.1
pycrypto = 2.6
pycrypto = 2.6
pytz = 2012j
pytz = 2012j
rdiff-backup = 1.0.5
rdiff-backup = 1.0.5
...
...
stack/slapos.cfg
View file @
7a5346c6
...
@@ -60,6 +60,7 @@ recipe = zc.recipe.egg
...
@@ -60,6 +60,7 @@ recipe = zc.recipe.egg
eggs =
eggs =
${lxml-python:egg}
${lxml-python:egg}
slapos.cookbook
slapos.cookbook
hexagonit.recipe.download
inotifyx
inotifyx
netaddr
netaddr
slapos.core
slapos.core
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment