Commit 99c1f5fc authored by Kirill Smelkov's avatar Kirill Smelkov

Merge branch 'master' into x/gitlab

* master: (45 commits)
  add firewalld component
  fixup! NEO: fix build of [slapos-deps-eggs]
  version up : mesa 11.0.3.
  version up eggs.
  python: Add patch to support pytracemalloc and add the corresponding egg to ERP5.
  NEO: do not rely on $HOME, which is not always equal to ${buildout:directory}
  NEO: fix build of [slapos-deps-eggs]
  component python-setuptools updated to version 18.4
  use lockfile egg version 0.10.2 for kvm and webrunner development
  monitor2: fix rss link
  monitor2: add minimal css for the default promise interface
  monitor2: add rss button
  version up: numpy 1.10.0.post2.
  monitor2: add rss feed
  version up : zc.buildout 1.7.1.post13 and zc.recipe.egg 1.3.2.post5.
  version up eggs.
  version up : FreeType 2.6.1.
  version up : pkg-config 0.29
  monitor2: fix status interface js error according to dom
  kvm: cdrom-iso update to version 8.2.0
  ...
parents e4453972 d6971226
[buildout]
parts =
firewalld-patch
extends =
../pkgconfig/buildout.cfg
../autoconf/buildout.cfg
../automake/buildout.cfg
../libtool/buildout.cfg
../intltool/buildout.cfg
../gettext/buildout.cfg
../glib/buildout.cfg
../m4/buildout.cfg
../python-slip/buildout.cfg
../dbus/buildout.cfg
../python-2.7/buildout.cfg
../libffi/buildout.cfg
../flex/buildout.cfg
../bison/buildout.cfg
[firewalld]
recipe = slapos.recipe.cmmi
url = https://github.com/t-woerner/firewalld/archive/v0.3.14.2.tar.gz
md5sum = b8f81b536ede502721f69300d374447b
python-egg = ${buildout:parts-directory}/${:_buildout_section_name_}/lib/python2.7/site-packages
configure-command =
aclocal -I${pkgconfig:location}/share/aclocal -I${gettext:location}/share/aclocal -I${libtool:location}/share/aclocal
./autogen.sh
sed -i "s#SUBDIRS = config doc po shell-completion src#SUBDIRS = config po shell-completion src#" Makefile
environment =
PKG_CONFIG_PATH=${glib:location}/lib/pkgconfig
PATH=${autoconf:location}/bin:${automake:location}/bin:${pkgconfig:location}/bin:${libtool:location}/bin:${intltool:location}/bin:${gettext:location}/bin:${glib:location}/bin:%(PATH)s
CPPFLAGS=-I${gettext:location}/include
LDFLAGS=-L${gettext:location}/lib -Wl,-rpath=${gettext:location}/lib
PYTHON=${python2.7:location}/bin/python2.7
M4=${m4:location}/bin/m4
ACLOCAL_PATH=${pkgconfig:location}/share/aclocal:${gettext:location}/share/aclocal:${libtool:location}/share/aclocal:${glib:location}/share/aclocal:${intltool:location}/share/aclocal
FIREWALLD_DEVEL_ENV=${buildout:parts-directory}/${:_buildout_section_name_}/src
PYTHONPATH=${buildout:parts-directory}/${:_buildout_section_name_}/src
[dbus-python]
recipe = slapos.recipe.cmmi
version = 1.2.0
url = http://dbus.freedesktop.org/releases/dbus-python/dbus-python-${:version}.tar.gz
md5sum = b09cd2d1a057cc432ce944de3fc06bf7
python-egg = ${buildout:parts-directory}/${:_buildout_section_name_}/lib/python2.7/site-packages
environment =
PKG_CONFIG_PATH=${dbus:location}/lib/pkgconfig:${dbus-glib:location}/lib/pkgconfig:${glib:location}/lib/pkgconfig
PATH=${pkgconfig:location}/bin:%(PATH)s
DBUS_CFLAGS=-I${dbus:location}/include/dbus-1.0 -I${dbus:location}/lib/dbus-1.0/include
DBUS_LIBS=-L${dbus:location}/lib -ldbus-1
DBUS_GLIB_CFLAGS=-I${dbus-glib:location}/include/dbus-1.0
DBUS_GLIB_LIBS=-L${dbus-glib:location}/lib -ldbus-glib-1
CPPFLAGS=-I${glib:location}/include/glib-2.0 -I${glib:location}/lib/glib-2.0/include
LDFLAGS=-L${glib:location}/lib -Wl,-rpath=${glib:location}/lib
PYTHON=${python2.7:location}/bin/python2.7
PYTHON_INCLUDES=-I${python2.7:location}/include/python2.7
PYTHON_LIBS=-L${python2.7:location}/lib -lpython2.7
[gobject-introspection]
recipe = slapos.recipe.cmmi
url = https://github.com/GNOME/gobject-introspection/archive/GOBJECT_INTROSPECTION_1_45_2.tar.gz
configure-command =
libtoolize -c -f
aclocal -I${pkgconfig:location}/share/aclocal -I${gettext:location}/share/aclocal -I${libtool:location}/share/aclocal
./autogen.sh
configure-options =
--disable-static
environment =
PATH=${autoconf:location}/bin:${automake:location}/bin:${pkgconfig:location}/bin:${libtool:location}/bin:${intltool:location}/bin:${gettext:location}/bin:${glib:location}/bin:${flex:location}/bin:${bison:location}/bin:%(PATH)s
PKG_CONFIG_PATH=${glib:location}/lib/pkgconfig
CPPFLAGS=-I${glib:location}/include/glib-2.0 -I${glib:location}/lib/glib-2.0/include
LDFLAGS=-L${glib:location}/lib -Wl,-rpath=${glib:location}/lib -L${libffi:location}/lib -Wl,-rpath=${libffi:location}/lib -lffi
M4=${m4:location}/bin/m4
ACLOCAL_PATH=${pkgconfig:location}/share/aclocal:${gettext:location}/share/aclocal:${libtool:location}/share/aclocal:${glib:location}/share/aclocal:${intltool:location}/share/aclocal
PYTHON=${python2.7:location}/bin/python2.7
GLIB_CFLAGS=-I${glib:location}/include/glib-2.0 -I${glib:location}/lib/glib-2.0/include
GLIB_LIBS=-L${glib:location}/lib -lglib-2.0 -lintl -lgobject-2.0
FFI_CFLAGS=-I${libffi:location}/include
FFI_LIBS=-L${libffi:location}/lib -Wl,-rpath=${libffi:location}/lib -lffi
[pygobject3]
recipe = slapos.recipe.cmmi
url = http://ftp.gnome.org/pub/GNOME/sources/pygobject/3.10/pygobject-3.10.2.tar.xz
python-egg = ${buildout:parts-directory}/${:_buildout_section_name_}/lib/python2.7/site-packages
# md5sum =
configure-command =
sed -i 's#/usr/local#${gobject-introspection:location}#g' ${gobject-introspection:location}/lib/pkgconfig/gobject-introspection-1.0.pc
./configure
configure-options =
--prefix=${buildout:parts-directory}/${:_buildout_section_name_}
--disable-static
--disable-cairo
--with-python=${python2.7:location}/bin/python2.7
environment =
PATH=${pkgconfig:location}/bin:${libtool:location}/bin:${glib:location}/bin:%(PATH)s
PKG_CONFIG_PATH=${glib:location}/lib/pkgconfig:${gobject-introspection:location}/lib/pkgconfig
PYTHON=${python2.7:location}/bin/python2.7
FFI_CFLAGS=-I${libffi:location}/include
FFI_LIBS=-L${libffi:location}/lib -Wl,-rpath=${libffi:location}/lib -lffi
CPPFLAGS=-I${glib:location}/include/glib-2.0 -I${glib:location}/lib/glib-2.0/include -I${gettext:location}/include -I${libffi:location}/include
LDFLAGS=-L${glib:location}/lib -Wl,-rpath=${glib:location}/lib -L${gettext:location}/lib -Wl,-rpath=${gettext:location}/lib
# GLIB_CFLAGS=-I${glib:location}/include/glib-2.0 -I${glib:location}/lib/glib-2.0/include
# GLIB_LIBS=-L${glib:location}/lib -lgobject-2.0 -lgthread-2.0 -pthread -lrt -lglib-2.0
GIO_LIBS=-L${glib:location}/lib -lgio-2.0
GI_CFLAGS=-I${gobject-introspection:location}/include/gobject-introspection-1.0
GI_LIBS=-L${gobject-introspection:location}/lib -lgirepository-1.0
[trusted-config]
recipe = hexagonit.recipe.download
url = https://raw.githubusercontent.com/t-woerner/firewalld/v0.3.14/config/zones/trusted.xml
download-only = true
filename = trusted.xml
md5sum = 893752ba2e93a1e96334dfee19f884ad
[firewalld-patch]
recipe = plone.recipe.command
python = ${buildout:directory}/bin/${firewalld-eggs:interpreter}
command =
sed -i 's#/usr/bin/python -Es#${:python}#' ${firewalld:location}/bin/firewall-cmd
sed -i 's#/usr/bin/python -Es#${:python}#' ${firewalld:location}/sbin/firewalld
sed -i 's#DefaultZone=public#DefaultZone=trusted#' ${firewalld:location}/etc/firewalld/firewalld.conf
sed -i 's#/usr/lib/firewalld#${firewalld:location}/lib/firewalld#' ${firewalld:location}/lib/python2.7/site-packages/firewall/config/__init__.py
sed -i 's#/usr/share/#${firewalld:location}/share#' ${firewalld:location}/lib/python2.7/site-packages/firewall/config/__init__.py
sed -i "s#import sys#import sys, os\n\nos.environ['GI_TYPELIB_PATH'] = '${gobject-introspection:location}/lib/girepository-1.0/'#" ${:python}
sed -i 's#<syslog/>#<!-- no syslog -->#' ${dbus:location}/etc/dbus-1/system.conf
sed -i 's#<user>messagebus</user>#<user>slapsoft</user>#' ${dbus:location}/etc/dbus-1/system.conf
cp -f ${firewalld:location}/lib/firewalld/zones/trusted.xml ${firewalld:location}/etc/firewalld/zones/
cp -f ${firewalld:location}/etc/dbus-1/system.d/FirewallD.conf ${dbus:location}/etc/dbus-1/system.d/
mkdir -p ${buildout:directory}/sbin
update-command = ${:command}
[firewalld-eggs]
recipe = zc.recipe.egg:scripts
interpreter = python.eggs
eggs =
decorator
six
${python-slip-egg:eggs}
extra-paths =
${dbus-python:python-egg}
${firewalld:python-egg}
${pygobject3:python-egg}
......@@ -13,8 +13,8 @@ parts =
[freetype]
recipe = slapos.recipe.cmmi
url = http://download.savannah.gnu.org/releases/freetype/freetype-2.6.tar.bz2
md5sum = 5682890cb0267f6671dd3de6eabd3e69
url = http://download.savannah.gnu.org/releases/freetype/freetype-2.6.1.tar.bz2
md5sum = 35cb8f4d9e5906847901bb39324c2f80
pkg_config_depends = ${zlib:location}/lib/pkgconfig:${libpng:location}/lib/pkgconfig
location = ${buildout:parts-directory}/${:_buildout_section_name_}
configure-options =
......@@ -24,5 +24,3 @@ environment =
PKG_CONFIG_PATH=${:pkg_config_depends}
CPPFLAGS=-I${bzip2:location}/include -I${zlib:location}/include
LDFLAGS=-L${bzip2:location}/lib -Wl,-rpath=${bzip2:location}/lib -L${zlib:location}/lib -Wl,-rpath=${zlib:location}/lib
make-targets =
install && ln -s . ${:location}/include/freetype2/freetype
......@@ -16,8 +16,8 @@ parts =
[git]
recipe = slapos.recipe.cmmi
url = https://www.kernel.org/pub/software/scm/git/git-2.5.1.tar.xz
md5sum = 55b9c496ea2d87148a2bfe1b6f6edd02
url = https://www.kernel.org/pub/software/scm/git/git-2.5.3.tar.xz
md5sum = e69b41f2d0a93f3d3dc5eb19196e4e5c
configure-options =
--with-curl=${curl:location}
--with-openssl=${openssl:location}
......
......@@ -13,8 +13,8 @@ extends =
[groonga]
recipe = slapos.recipe.cmmi
url = http://packages.groonga.org/source/groonga/groonga-5.0.7.tar.gz
md5sum = 389d5353a18ff5f48ccf65a576c7b2d1
url = http://packages.groonga.org/source/groonga/groonga-5.0.8.tar.gz
md5sum = ccb36449fdd62c61367f3ed5e830aec3
# temporary patch to respect more tokens in natural language mode.
patches =
${:_profile_base_location_}/groonga.patch#9ed02fbe8400402d3eab47eee149978b
......
......@@ -4,8 +4,8 @@ parts =
[libtasn1]
recipe = slapos.recipe.cmmi
url = http://ftp.gnu.org/gnu/libtasn1/libtasn1-4.6.tar.gz
md5sum = 454a7f80362f38bd2335b6e9d95f57a6
url = http://ftp.gnu.org/gnu/libtasn1/libtasn1-4.7.tar.gz
md5sum = 12d10ca4ae0a3b95f7aa06a076da39ec
configure-options =
--disable-static
--disable-gtk-doc-html
......@@ -57,8 +57,8 @@ environment =
# mroonga - a storage engine for MySQL. It provides fast fulltext search feature to all MySQL users.
# http://mroonga.github.com/
recipe = slapos.recipe.cmmi
url = http://packages.groonga.org/source/mroonga/mroonga-5.06.tar.gz
md5sum = 15597acfb1375c931e7b5588511c17bb
url = http://packages.groonga.org/source/mroonga/mroonga-5.08.tar.gz
md5sum = 65011c1da8700c4950d11dea7355b32d
configure-command = mkdir fake_mariadb_source && ln -s ${mariadb:location}/include/mysql/private fake_mariadb_source/sql && ./configure
configure-options =
--prefix=${buildout:parts-directory}/${:_buildout_section_name_}
......
......@@ -8,31 +8,34 @@ extends =
../libtool/buildout.cfg
../pkgconfig/buildout.cfg
../xorg/buildout.cfg
../xz-utils/buildout.cfg
parts =
mesa
[mesa]
recipe = slapos.recipe.cmmi
url = ftp://ftp.freedesktop.org/pub/mesa/10.3.2/MesaLib-10.3.2.tar.bz2
md5sum = c0a2a975899c4e7485124b388c16cd2f
url = ftp://ftp.freedesktop.org/pub/mesa/11.0.3/mesa-11.0.3.tar.xz
md5sum = bf9118bf0fbf360715cfe60baf7a1db5
configure-options =
--disable-static
--disable-gles1
--disable-gles2
--disable-dri
--disable-dri3
--disable-egl
--disable-gbm
--disable-xvmc
--disable-vdpau
--disable-va
--enable-xlib-glx
--disable-gallium-gbm
--disable-shared-glapi
--disable-driglx-direct
--disable-gallium-llvm
--with-gallium-drivers=
--with-dri-drivers=
environment =
PATH=${autoconf:location}/bin:${bison:location}/bin:${flex:location}/bin:${pkgconfig:location}/bin:%(PATH)s
PATH=${autoconf:location}/bin:${bison:location}/bin:${flex:location}/bin:${pkgconfig:location}/bin:${xz-utils:location}/bin:%(PATH)s
PKG_CONFIG_PATH=${damageproto:location}/lib/pkgconfig:${fixesproto:location}/lib/pkgconfig:${glproto:location}/lib/pkgconfig:${kbproto:location}/lib/pkgconfig:${libX11:location}/lib/pkgconfig:${libXau:location}/lib/pkgconfig:${libXext:location}/lib/pkgconfig:${libexpat:location}/lib/pkgconfig:${libxcb:location}/lib/pkgconfig:${xdamage:location}/lib/pkgconfig:${xextproto:location}/lib/pkgconfig:${xfixes:location}/lib/pkgconfig:${xorg-libpthread-stubs:location}/lib/pkgconfig:${xproto:location}/lib/pkgconfig
PYTHON2=${buildout:executable}
ACLOCAL=${automake:location}/bin/aclocal -I${libtool:location}/share/aclocal -I${pkgconfig:location}/share/aclocal
......
......@@ -14,8 +14,8 @@ extends =
[pkgconfig]
recipe = slapos.recipe.cmmi
url = http://pkgconfig.freedesktop.org/releases/pkg-config-0.28.tar.gz
md5sum = aa3c86e67551adc3ac865160e34a2a0d
url = http://pkgconfig.freedesktop.org/releases/pkg-config-0.29.tar.gz
md5sum = 77f27dce7ef88d0634d0d6f90e03a77f
location = ${buildout:parts-directory}/${:_buildout_section_name_}
# build pkg-config twice so that second configure can use pkg-config
# to compute GLIB_CFLAGS and GLIB_LIBS.
......@@ -25,6 +25,7 @@ configure-options =
--prefix=${:location}
--with-installed-glib
--with-installed-popt
--disable-host-tool
environment =
PATH=.:%(PATH)s
PKG_CONFIG_PATH=${glib:location}/lib/pkgconfig
......
......@@ -40,6 +40,7 @@ executable = ${:prefix}/bin/python${:version}
patch-options = -p1
patches =
${:_profile_base_location_}/fix_compiler_module_issue_20613.patch#94443a77f903e9de880a029967fa6aa7
${:_profile_base_location_}/pytracemalloc_pep445.patch#46662cf0ccc7cb7cfb8289bbfd68b21a
url =
http://python.org/ftp/python/${:package_version}/Python-${:package_version}${:package_version_suffix}.tar.xz
configure-options =
......
This diff is collapsed.
......@@ -4,10 +4,10 @@ parts = python-setuptools
[setuptools-download]
recipe = hexagonit.recipe.download
download-only = true
package_suffix = setuptools-1.4.2
package_suffix = setuptools-18.4
filename = ${:package_suffix}.tar.gz
url = https://pypi.python.org/packages/source/s/setuptools/${:filename}
md5sum = 13951be6711438073fbe50843e7f141f
md5sum = 214c6c43bd7035e870c1beab402c48e7
mode = 0644
[python-setuptools]
......
[buildout]
parts =
python-slip-egg
[python-slip]
recipe = slapos.recipe.cmmi
url = https://fedorahosted.org/released/python-slip/python-slip-0.6.1.tar.bz2
md5sum = a6d8ee96245fc21785d4c1c062c85f2f
configure-command = true
make-targets =
make-binary =
make all
cp -ax . ${:slip}/
cp -ax . ${:slip.dbus}/
cp -ax . ${:slip.gtk}/
sed -i '/setup(name="slip.dbus"/,/"gtk", "pango"])/d' ${:slip}/setup.py
sed -i '/setup(name="slip"/,/selinux"])/d' ${:slip.dbus}/setup.py
sed -i '/if sys.version_info.major/,/"gtk", "pango"])/d' ${:slip.dbus}/setup.py
sed -i '/setup(name="slip"/,/xml.etree.ElementTree"])/d' ${:slip.gtk}/setup.py
slip = ${buildout:parts-directory}/slip
slip.dbus = ${buildout:parts-directory}/slip.dbus
slip.gtk = ${buildout:parts-directory}/slip.gtk
[slip.gtk-develop]
recipe = zc.recipe.egg:develop
setup = ${python-slip:slip.gtk}
egg-name = slip.gtk
[slip.dbus-develop]
recipe = zc.recipe.egg:develop
setup = ${python-slip:slip.dbus}
egg-name = slip.dbus
[slip-develop]
recipe = zc.recipe.egg:develop
setup = ${python-slip:slip}
egg-name = slip
[python-slip-egg]
recipe = zc.recipe.egg
eggs =
${slip-develop:egg-name}
${slip.dbus-develop:egg-name}
${slip.gtk-develop:egg-name}
......@@ -43,9 +43,9 @@ environment =
[debian-amd64-netinst.iso]
# Download the installer of Debian 8 (Jessie)
recipe = hexagonit.recipe.download
url = http://cdimage.debian.org/debian-cd/8.1.0/amd64/iso-cd/debian-8.1.0-amd64-netinst.iso
url = http://cdimage.debian.org/debian-cd/8.2.0/amd64/iso-cd/debian-8.2.0-amd64-netinst.iso
filename = ${:_buildout_section_name_}
md5sum = 1a311f9afb68d6365211b13b4342c40b
md5sum = 762eb3dfc22f85faf659001ebf270b4f
download-only = true
mode = 0644
location = ${buildout:parts-directory}/${:_buildout_section_name_}
......@@ -9,12 +9,14 @@ extends =
../sqlite3/buildout.cfg
../swig/buildout.cfg
../patch/buildout.cfg
../firewalld/buildout.cfg
parts =
slapos
cfg-environment
sh-environment
py
firewalld-patch
......@@ -76,7 +78,7 @@ rpath =
#############################################
[slapos]
recipe = z3c.recipe.scripts
recipe = zc.recipe.egg
eggs =
${lxml-python:egg}
${python-cffi:egg}
......
......@@ -274,8 +274,8 @@ environment =
[pixman]
recipe = slapos.recipe.cmmi
url = http://xorg.freedesktop.org/archive/individual/lib/pixman-0.33.2.tar.bz2
md5sum = 837f48ecedb96f2d558f0d5763e9447b
url = http://xorg.freedesktop.org/archive/individual/lib/pixman-0.32.8.tar.bz2
md5sum = 18d6b62abdb7bc0f8e6b0ddf48986b2c
configure-options =
--disable-static
......
......@@ -24,6 +24,7 @@
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
import os
from slapos.recipe.librecipe import GenericBaseRecipe
from zc.buildout import UserError
......@@ -50,6 +51,13 @@ class NeoBaseRecipe(GenericBaseRecipe):
#'-n', options['name'],
'-c', options['cluster'],
]
if options['ssl']:
etc = os.path.join(self.buildout['buildout']['directory'], 'etc', '')
option_list += (
'--ca', etc + 'ca.crt',
'--cert', etc + 'neo.crt',
'--key', etc + 'neo.key',
)
option_list.extend(self._getOptionList())
return [self.createPythonScript(
options['wrapper'],
......
......@@ -54,7 +54,7 @@ md5sum = 7c5c43eb98d5a11961d72fce97a8e67b
mode = 0644
[script]
recipe = z3c.recipe.scripts
recipe = zc.recipe.egg
eggs =
zc.buildout
slapos.core
......
......@@ -5,35 +5,35 @@ extends = common.cfg
PyRSS2Gen = 1.1
apache-libcloud = 0.18.0
cns.recipe.symlink = 0.2.3
collective.recipe.template = 1.11
ecdsa = 0.13
gitdb = 0.6.4
plone.recipe.command = 1.1
pycrypto = 2.6.1
rdiff-backup = 1.0.5
slapos.recipe.template = 2.8
slapos.toolbox = 0.51
slapos.toolbox = 0.52
smmap = 0.9.0
# Required by:
# slapos.toolbox==0.51
# slapos.toolbox==0.52
GitPython = 1.0.1
# Required by:
# slapos.toolbox==0.51
# slapos.toolbox==0.52
atomize = 0.2.0
# Required by:
# slapos.toolbox==0.51
# slapos.toolbox==0.52
feedparser = 5.2.1
# Required by:
# slapos.toolbox==0.51
# slapos.toolbox==0.52
lockfile = 0.10.2
# Required by:
# slapos.toolbox==0.51
paramiko = 1.15.2
# slapos.toolbox==0.52
paramiko = 1.15.3
# Required by:
# slapos.toolbox==0.51
# slapos.toolbox==0.52
rpdb = 0.1.5
......@@ -28,7 +28,7 @@ mode = 0644
branch = request.product
[eggs]
recipe = z3c.recipe.scripts
recipe = zc.recipe.egg
eggs =
collective.recipe.environment
cns.recipe.symlink
......
......@@ -25,7 +25,7 @@ initialization =
${manpy:initialization}
[dream_interpreter]
recipe = z3c.recipe.scripts
recipe = zc.recipe.egg
eggs = ${manpy:eggs}
interpreter = dream_interpreter
initialization =
......@@ -51,12 +51,10 @@ tablib = 0.10.0
MySQL-python = 1.2.5
# indirect dependancies
collective.recipe.template = 1.11
cp.recipe.cmd = 0.5
plone.recipe.command = 1.1
slapos.recipe.template = 2.7
slapos.recipe.template = 2.8
zope.exceptions = 4.0.7
zope.testing = 4.1.3
zc.recipe.testrunner = 2.0.0
zope.testrunner = 4.4.6
z3c.recipe.scripts = 1.0.1
......@@ -220,6 +220,13 @@
},
"storage-dict": {
"description": "Storage configuration. For NEO, 'logfile' is automatically set (see http://git.erp5.org/gitweb/neoppod.git/blob/HEAD:/neo/client/component.xml for other settings).",
"properties": {
"ssl": {
"description": "For external NEO. Pass false if you want to disable SSL or pass custom values for ca/cert/key.",
"default": true,
"type": "boolean"
}
},
"additionalProperties": {"type": "string"},
"type": "object"
}
......
......@@ -75,7 +75,6 @@ rdiff-backup = 1.0.5
slapos.recipe.template = 2.4.2
slapos.toolbox = 0.40.4
smmap = 0.8.2
z3c.recipe.scripts = 1.0.1
plone.recipe.command = 1.1
# Required by:
......@@ -92,4 +91,4 @@ feedparser = 5.1.3
# Required by:
# slapos.toolbox==0.40.2
paramiko = 1.15.2
paramiko = 1.15.3
......@@ -46,6 +46,5 @@ md5sum = 8cde04bfd0c0e9bd56744b988275cfd8
[versions]
PyRSS2Gen = 1.1
cns.recipe.symlink = 0.2.3
collective.recipe.template = 1.11
plone.recipe.command = 1.1
slapos.recipe.template = 2.7
slapos.recipe.template = 2.8
......@@ -43,7 +43,7 @@ parts =
#XXX-Cedric : add list of keyboard layouts (azerty/us querty/...) parameter to qemu
[eggs]
recipe = z3c.recipe.scripts
recipe = zc.recipe.egg
eggs =
${lxml-python:egg}
websockify
......
......@@ -54,4 +54,6 @@ command =
slapos.cookbook =
slapos.core =
slapos.toolbox =
erp5.util =
\ No newline at end of file
erp5.util =
# XXX Fix lockfile 0.11.0 requirement (pbr!=0.7,<1.0,>=0.6)
lockfile = 0.10.2
\ No newline at end of file
......@@ -44,7 +44,7 @@ numpy = 1.9.2
# Required by:
# slapos.toolbox==0.48
paramiko = 1.15.2
paramiko = 1.15.3
# Required by:
# slapos.toolbox==0.48
......
......@@ -89,7 +89,7 @@ gems +=
fluent-plugin-grep==0.3.4
[eggs]
recipe = z3c.recipe.scripts
recipe = zc.recipe.egg
eggs =
cns.recipe.symlink
slapos.cookbook
......@@ -102,7 +102,6 @@ PyRSS2Gen = 1.1
cns.recipe.symlink = 0.2.3
plone.recipe.command = 1.1
slapos.recipe.template = 2.7
z3c.recipe.scripts = 1.0.1
rubygemsrecipe = 0.2.1
pycurl = 7.19.5.1
......@@ -127,7 +126,7 @@ feedparser = 5.1.3
# Required by:
# slapos.toolbox==0.52
paramiko = 1.15.2
paramiko = 1.15.3
# Required by:
# slapos.toolbox==0.52
......
......@@ -10,6 +10,7 @@ wrapper = ${directory:etc_run}/neoadmin
logfile = ${directory:log}/neoadmin.log
ip = ${publish:ip}
port = ${publish:port-admin}
ssl = {{ dumps(bool(slapparameter_dict['ssl'])) }}
cluster = {{ dumps(slapparameter_dict['cluster']) }}
masters = ${publish:masters}
......
......@@ -35,6 +35,20 @@
},
"type": "object"
},
"ssl": {
"description": "Enable SSL. All nodes look for 3 files in ~/etc: ca.crt, neo.crt, neo.key. Waiting that SlapOS provides a way to manage certificates, the user must deploy them manually, or use the temporary _ca/_cert/_key parameters.",
"default": true,
"type": "boolean"
},
"_ca": {
"type": "string"
},
"_cert": {
"type": "string"
},
"_key": {
"type": "string"
},
"node-list": {
"description": "List of dictionaries containing parameters for each node.",
"items": {
......
......@@ -10,6 +10,7 @@ wrapper = ${directory:etc_run}/neomaster
logfile = ${directory:log}/neomaster.log
ip = ${publish:ip}
port = ${publish:port-master}
ssl = {{ dumps(bool(slapparameter_dict['ssl'])) }}
cluster = {{ dumps(slapparameter_dict['cluster']) }}
partitions = {{ slapparameter_dict['partitions'] }}
replicas = {{ slapparameter_dict['replicas'] }}
......
......@@ -41,7 +41,7 @@ context = section parameter_dict my-cnf-parameters
[publish]
recipe = slapos.cookbook:publish.serialised
# TODO: make port a partition parameter
ip = {{ (ipv4_set | list)[0] }}
ip = {{ "[%s]" % list(ipv6_set)[0] if ipv6_set else list(ipv4_set)[0] }}
{% set admin = slapparameter_dict.get('admin', 2050) -%}
{% set master = slapparameter_dict.get('master', 2051) -%}
{% if master -%}
......@@ -61,10 +61,26 @@ masters = {{ ' '.join(sorted(master_list)) }}
admins = {{ ' '.join(sorted(admin_list)) }}
{%- endif %}
{#- Hack to deploy SSL certs via instance parameters #}
{%- for name, pem in zip(('ca.crt', 'neo.crt', 'neo.key'),
slapparameter_dict['ssl']) %}
{%- if pem %}
[{{ section(name) }}]
recipe = slapos.recipe.template:jinja2
rendered = ${directory:etc}/{{name}}
template = inline:{{'{{'}}pem}}
context = key pem :pem
pem = {{dumps(pem)}}
{%- endif %}
{%- endfor %}
{#- endhack #}
[neo-storage]
recipe = slapos.cookbook:neoppod.storage
binary = {{ bin_directory }}/neostorage
ip = ${publish:ip}
ssl = {{ dumps(bool(slapparameter_dict['ssl'])) }}
cluster = {{ dumps(slapparameter_dict['cluster']) }}
masters = ${publish:masters}
database-adapter = MySQL
......
......@@ -42,6 +42,11 @@ config-cluster = {{ parameter_dict['cluster'] }}
{% set replicas = parameter_dict.get('replicas', 0) -%}
config-partitions = {{ dumps(parameter_dict.get('partitions', 12)) }}
config-replicas = {{ dumps(replicas) }}
config-ssl = {{ dumps((
parameter_dict.get('_ca'),
parameter_dict.get('_cert'),
parameter_dict.get('_key'),
) if parameter_dict.get('ssl', 1) else ()) }}
config-upstream-cluster = {{ dumps(parameter_dict.get('upstream-cluster', '')) }}
config-upstream-masters = {{ dumps(parameter_dict.get('upstream-masters', '')) }}
software-type = {{ software_type }}
......
......@@ -16,6 +16,7 @@ extends =
../../component/python-2.7/buildout.cfg
../../component/mariadb/buildout.cfg
../../component/mysql-python/buildout.cfg
../../component/pycrypto-python/buildout.cfg
parts =
slapos-deps-eggs
......@@ -27,13 +28,13 @@ parts =
mysql-python
neoppod
[slapos.cookbook-repository]
branch = erp5-cluster
[slapos-deps-eggs]
recipe = zc.recipe.egg
eggs =
${lxml-python:egg}
${python-PyYAML:egg}
${pycrypto-python:egg}
${python-cliff:egg}
slapos.toolbox
scripts =
slapos-kill
......@@ -74,19 +75,19 @@ context =
[root-common]
<= download-base-neo
md5sum = 26193dbb132d340c8ba919a616449a17
md5sum = f3259726bd5d824c569dc7db6b7d26a0
[instance-neo-admin]
<= download-base-neo
md5sum = 16d11f0fe74de06aebbadcff3527db1c
md5sum = f030a25d320f2edf0186b69bfa521228
[instance-neo-master]
<= download-base-neo
md5sum = 023f08763dbba2319f58e5c597f7761d
md5sum = 82f3f76f54ee9db355966a7ada61f56e
[instance-neo-storage-mysql]
<= download-base-neo
md5sum = 5a61039c7a980e24519e1bbb1252e662
md5sum = 84b1150ce30ec827485f9c17debd6b44
[template-neo-my-cnf]
<= download-base-neo
......@@ -101,5 +102,22 @@ ZODB3-patches = ${:_profile_base_location_}/../../component/egg-patch/ZODB3-3.10
ZODB3-patch-options = -p1
[versions]
# patched eggs
MySQL-python = 1.2.5
neoppod = 1.5
slapos.recipe.template = 2.8
# patched egg
ZODB3 = 3.10.5+SlapOSPatched001
# Required by slapos.toolbox==0.52
slapos.toolbox = 0.52
apache-libcloud = 0.18.0
atomize = 0.2.0
ecdsa = 0.13
feedparser = 5.2.1
GitPython = 1.0.1
gitdb = 0.6.4
lockfile = 0.10.2
paramiko = 1.15.3
pycrypto = 2.6.1
rpdb = 0.1.5
smmap = 0.9.0
##
......@@ -20,3 +20,12 @@ context =
[cluster]
<= download-base-neo
md5sum = ee8401a4e7d82bf488a57e3399f9ce48
[versions]
# To match ERP5
transaction = 1.1.1
ZConfig = 2.9.1
zc.lockfile = 1.0.2
zdaemon = 2.0.7
zope.event = 3.5.2
##
......@@ -62,6 +62,5 @@ mode = 0644
[versions]
PyRSS2Gen = 1.1
cns.recipe.symlink = 0.2.3
collective.recipe.template = 1.11
plone.recipe.command = 1.1
slapos.recipe.template = 2.7
slapos.recipe.template = 2.8
......@@ -164,7 +164,7 @@ miniupnpc = 1.9
# Required by:
# slapos.toolbox==0.47.3
paramiko = 1.15.2
paramiko = 1.15.3
# Required by:
# slapos.toolbox==0.47.3
......
......@@ -190,7 +190,7 @@ filename = monitor-check-webrunner-internal-instances.py
mode = 0644
[eggs]
recipe = z3c.recipe.scripts
recipe = zc.recipe.egg
eggs =
collective.recipe.environment
cns.recipe.symlink
......
......@@ -67,3 +67,5 @@ setup = ${slapos.core-repository:location}
slapos.cookbook =
slapos.core =
slapos.toolbox =
# XXX Fix lockfile 0.11.0 requirement (pbr!=0.7,<1.0,>=0.6)
lockfile = 0.10.2
......@@ -12,7 +12,6 @@ PyRSS2Gen = 1.1
apache-libcloud = 0.18.0
cns.recipe.symlink = 0.2.3
collective.recipe.environment = 0.2.0
collective.recipe.template = 1.12
ecdsa = 0.13
erp5.util = 0.4.43
gitdb = 0.6.4
......@@ -42,7 +41,7 @@ lockfile = 0.10.2
# Required by:
# slapos.toolbox==0.52
paramiko = 1.15.2
paramiko = 1.15.3
# Required by:
# slapos.toolbox==0.52
......
......@@ -87,4 +87,4 @@ feedparser = 5.1.3
# Required by:
# slapos.toolbox==0.40.2
paramiko = 1.15.2
paramiko = 1.15.3
[buildout]
find-links +=
http://www.owlfish.com/software/wsgiutils/download.html
# Separate from site eggs
allowed-eggs-from-site-packages =
include-site-packages = false
......
[buildout]
find-links +=
http://www.owlfish.com/software/wsgiutils/download.html
extends =
# Exact version of Zope
https://raw.github.com/zopefoundation/Zope/2.13.22/versions.cfg
......@@ -29,7 +26,6 @@ extends =
../../component/percona-toolkit/buildout.cfg
../../component/patch/buildout.cfg
../../component/pillow/buildout.cfg
../../component/pycrypto-python/buildout.cfg
../../component/pysvn-python/buildout.cfg
../../component/python-ldap-python/buildout.cfg
../../component/rdiff-backup/buildout.cfg
......@@ -122,7 +118,6 @@ parts +=
genbt5list
# some additional utils
slapos-toolbox
zodbanalyze
# Create instance template
......@@ -163,12 +158,12 @@ link-binary =
[template-kumofs]
<= download-base
filename = instance-kumofs.cfg.in
md5sum = 7d9760fe65f454700342eeffec14c884
md5sum = 763db0c4a94649296e74fe1f53c03940
[template-cloudooo]
<= download-base
filename = instance-cloudoo.cfg.in
md5sum = 8468648aa91712f0349baa1ad0c8ccdf
md5sum = 1b515056c5892a86d4ece252ad114a97
[template-zope-conf]
<= download-base
......@@ -225,7 +220,7 @@ recipe = slapos.recipe.template:jinja2
# XXX: "template.cfg" is hardcoded in instanciation recipe
rendered = ${buildout:directory}/template.cfg
template = ${:_profile_base_location_}/instance.cfg.in
md5sum = 708a721558f9bbe8856482e60891b4c7
md5sum = 540956c635acc9707045510c11f80016
mode = 640
context =
key mariadb_link_binary template-mariadb:link-binary
......@@ -319,17 +314,17 @@ rendered = ${monitor-template-dummy:target}
[template-erp5]
<= download-base
filename = instance-erp5.cfg.in
md5sum = 60cdf98d996f220d66daa11452c3f4bf
md5sum = 78c2db733e72c4197a90e8be1ff15098
[template-zeo]
<= download-base
filename = instance-zeo.cfg.in
md5sum = 9670cf63099e2c520017a23defff51a4
md5sum = 985c0010db6b553a89dbdb31353c56f5
[template-zope]
<= download-base
filename = instance-zope.cfg.in
md5sum = 44c4aa068cffe2c1d8320d59e6d1c499
md5sum = 0cd033da89a79c5b26dc0342ea57d5f7
link-binary =
${aspell:location}/bin/aspell
${dmtx-utils:location}/bin/dmtxwrite
......@@ -353,7 +348,7 @@ link-binary =
[template-balancer]
<= download-base
filename = instance-balancer.cfg.in
md5sum = 3628f0ba358e7ee96a8d0185c4775911
md5sum = 28c04f599cdbdfa97f2a67156f4f6b67
[template-apache-conf]
<= download-base
......@@ -463,6 +458,7 @@ eggs =
${pysvn-python:egg}
${pycrypto-python:egg}
lock_file
PyStemmer
PyXML
Pympler
SOAPpy
......@@ -507,6 +503,7 @@ eggs =
jsonschema
# Needed for checking ZODB Components source code
pylint
pytracemalloc
neoppod[client]
# Zope
......@@ -589,20 +586,19 @@ setup = ${erp5:location}
branch =
revision = f1545ad0e6db238d22fd8c84a149b004ab6b8f03
[slapos-toolbox]
[slapos-deps-eggs]
recipe = zc.recipe.egg
eggs =
${lxml-python:egg}
slapos.toolbox
eggs +=
slapos.toolbox[zodbpack]
scripts =
scripts +=
is-local-tcp-port-opened
onetimedownload
slapos-kill
zodbpack
[versions]
# See ../../software/neoppod/software-common.cfg for versions common with NEO:
# neoppod, MySQL-python, slapos.recipe.template & [slapos-deps-eggs]
# patched eggs
Acquisition = 2.13.8+SlapOSPatched001
Products.DCWorkflow = 2.2.4+SlapOSPatched001
......@@ -615,7 +611,7 @@ cloudooo = 1.2.5-dev
# use newer version than specified in ZTK
PasteDeploy = 1.5.2
Pygments = 2.0.2
coverage = 3.7.1
coverage = 4.0.1
zope.dottedname = 4.1.0
# test_UserManagerInterfaces in testERP5Security fails with 1.10.0.
......@@ -632,7 +628,7 @@ SOAPpy = 0.12.0nxd001
# CMF 2.3 is not yet supported.
Products.CMFCalendar = 2.2.3
Products.CMFCore = 2.2.8
Products.CMFCore = 2.2.9
Products.CMFDefault = 2.2.4
Products.CMFTopic = 2.2.1
Products.CMFUid = 2.2.1
......@@ -647,102 +643,97 @@ zope.app.publication = 3.14.0
zope.app.testing = 3.8.1
# Pinned versions
MySQL-python = 1.2.5
Pillow = 2.9.0
Pillow = 3.0.0
Products.CMFActionIcons = 2.1.3
Products.DCWorkflowGraph = 0.4.1
Products.ExternalEditor = 2.0.0
Products.GenericSetup = 1.7.7
Products.LongRequestLogger = 1.1.0
Products.GenericSetup = 1.8.0
Products.LongRequestLogger = 1.1.post1
Products.MimetypesRegistry = 2.0.8
Products.PluginRegistry = 1.3
Products.TIDStorage = 5.4.9
PyPDF2 = 1.25.1
PyStemmer = 1.3.0
PyXML = 0.8.5
Pympler = 0.4.2
StructuredText = 2.11.1
WSGIUtils = 0.7
apache-libcloud = 0.18.0
astroid = 1.3.6
astroid = 1.3.8
chardet = 2.3.0
collective.recipe.template = 1.11
csp-eventlet = 0.7.0
ecdsa = 0.13
elementtree = 1.2.6.post20050316
erp5diff = 0.8.1.7
eventlet = 0.17.4
five.formlib = 1.0.4
five.localsitemanager = 2.0.5
gitdb = 0.6.4
greenlet = 0.4.9
http-parser = 0.8.3
httplib2 = 0.9.1
httplib2 = 0.9.2
huBarcode = 1.0.0
interval = 1.0.0
ipdb = 0.8.1
ipython = 3.2.0
logilab-common = 1.0.2
neoppod = 1.4.0
numpy = 1.9.2
ipython = 4.0.0
logilab-common = 1.1.0
numpy = 1.10.1
objgraph = 2.0.1
plone.recipe.command = 1.1
ply = 3.7
ply = 3.8
polib = 1.0.7
pprofile = 1.7.3
pycountry = 1.15
pycrypto = 2.6.1
pyflakes = 0.9.2
ptyprocess = 0.5
pycountry = 1.17
pyflakes = 1.0.0
pylint = 1.4.4
python-magic = 0.4.6
python-memcached = 1.57
pytracemalloc = 1.2
qrcode = 5.1
restkit = 4.2.2
rtjp-eventlet = 0.3.2
slapos.recipe.template = 2.8
slapos.toolbox = 0.52
smmap = 0.9.0
simplegeneric = 0.8.1
socketpool = 0.5.3
spyne = 2.11.0
spyne = 2.12.10
suds = 0.4
threadframe = 0.2
timerserver = 2.0.2
urlnorm = 1.1.2
uuid = 1.30
validictory = 1.0.0
validictory = 1.0.1
xfw = 0.10
xupdate-processor = 0.4
# Required by:
# slapos.toolbox==0.52
GitPython = 1.0.1
# Products.CMFCore==2.2.9
Products.ZSQLMethods = 2.13.4
# Required by:
# Products.CMFCore==2.2.8
Products.ZSQLMethods = 2.13.4
# ipython==4.0.0
# traitlets==4.0.0
decorator = 4.0.4
# Required by:
# slapos.toolbox==0.52
atomize = 0.2.0
# SOAPpy===0.12.0nxd001
fpconst = 0.7.2
# Required by:
# slapos.toolbox==0.52
feedparser = 5.2.1
# traitlets==4.0.0
ipython-genutils = 0.1.0
# Required by:
# SOAPpy===0.12.0nxd001
fpconst = 0.7.2
# pickleshare==0.5
path.py = 8.1.2
# Required by:
# slapos.toolbox==0.52
lockfile = 0.10.2
# ipython==4.0.0
pexpect = 4.0.1
# Required by:
# slapos.toolbox==0.52
paramiko = 1.15.2
# ipython==4.0.0
pickleshare = 0.5
# Required by:
# slapos.toolbox==0.52
rpdb = 0.1.5
# ipython==4.0.0
traitlets = 4.0.0
# Required by:
# zope.app.testing==3.8.1
......@@ -756,3 +747,8 @@ zope.app.dependable = 3.5.1
# Products.CMFCalendar==2.2.3
# five.formlib==1.0.4
zope.app.form = 4.0.2
# Required by:
# Products.ZCatalog==2.13.27
# zope.container==3.11.2
zope.dottedname = 4.1.0
......@@ -206,8 +206,15 @@ certs = ${:ca-dir}/certs
newcerts = ${:ca-dir}/newcerts
crl = ${:ca-dir}/crl
[monitor-instance-parameter]
monitor-httpd-ipv6 = {{ (ipv6_set | list)[0] }}
monitor-httpd-port = {{ next_port }}
monitor-title = Balancer monitor
[buildout]
extends = {{ logrotate_cfg }}
extends =
{{ logrotate_cfg }}
{{ parameter_dict['template-monitor'] }}
parts +=
publish
logrotate-apache
......
{% set bin_directory = parameter_dict['buildout-bin-directory'] -%}
{% set use_ipv6 = slapparameter_dict.get('use-ipv6', False) -%}
[buildout]
parts =
publish-cloudooo-connection-information
extends =
{{ parameter_dict['template-monitor'] }}
parts +=
publish
cloudooo-instance
resiliency-exclude-file
promise
promise-openoffice
{% if use_ipv6 %}promise-tunnel{% endif %}
[publish-cloudooo-connection-information]
[publish]
recipe = slapos.cookbook:publish.serialised
{% if use_ipv6 -%}
url = cloudooo://[${ipv6toipv4:ipv6}]:${ipv6toipv4:ipv6-port}/
......@@ -99,3 +101,8 @@ service = ${:etc}/run
promise = ${:etc}/promise
cloudooo-data = ${:srv}/cloudooo
font = ${:srv}/font
[monitor-instance-parameter]
monitor-httpd-ipv6 = {{ (ipv6_set | list)[0] }}
monitor-httpd-port = {{ tcpv4_port + 2 }}
monitor-title = Cloudooo monitor
......@@ -62,8 +62,12 @@ connection-url = smtp://127.0.0.2:0/
{% if server_type == 'neo' -%}
{% set ((name, server_dict),) = server_dict.items() -%}
{% do neo.append(server_dict.get('cluster')) -%}
{% do server_dict.__setitem__('cluster', '${publish-early:neo-cluster}') -%}
{% do server_dict.update(cluster='${publish-early:neo-cluster}') -%}
{{ root_common.request_neo(server_dict, 'zodb-neo', 'neo-') }}
{% set client_dict = zodb_dict[name].setdefault('storage-dict', {}) -%}
{% for k in 'ssl', '_ca', '_cert', '_key' -%}
{% do k in server_dict and client_dict.setdefault(k, server_dict[k]) -%}
{% endfor -%}
{% else -%}
{{ assert(server_type == 'zeo', server_type) -}}
{# BBB: for compatibility, keep 'zodb' as partition_reference for ZEO -#}
......
{% set use_ipv6 = slapparameter_dict.get('use-ipv6', False) -%}
[buildout]
extends = {{ logrotate_cfg }}
extends =
{{ logrotate_cfg }}
{{ parameter_dict['template-monitor'] }}
parts +=
publish-kumofs-connection-information
publish
kumofs-instance
logrotate-entry-kumofs
resiliency-exclude-file
......@@ -11,7 +13,7 @@ parts +=
promise-kumofs-gateway
promise-kumofs-manager
[publish-kumofs-connection-information]
[publish]
recipe = slapos.cookbook:publish.serialised
{% if use_ipv6 -%}
url = memcached://[${kumofs-instance:ip}]:${kumofs-instance:gateway-port}/
......@@ -106,3 +108,8 @@ port = ${kumofs-instance:gateway-port}
<= promise-template
path = ${directory:promise}/kumofs-manager
port = ${kumofs-instance:manager-port}
[monitor-instance-parameter]
monitor-httpd-ipv6 = {{ (ipv6_set | list)[0] }}
monitor-httpd-port = {{ tcpv4_port + 4 }}
monitor-title = Kumofs monitor
......@@ -185,8 +185,16 @@ backup-zodb = {{ default_backup_path }}
zodb = {{ default_zodb_path }}
tidstorage = {{ tidstorage_repozo_path }}
{% set next_port = next_port + 1 -%}
[monitor-instance-parameter]
monitor-httpd-ipv6 = {{ (ipv6_set | list)[0] }}
monitor-httpd-port = {{ next_port }}
monitor-title = ZODB monitor
[buildout]
extends = {{ logrotate_cfg }}
extends =
{{ logrotate_cfg }}
{{ parameter_dict['template-monitor'] }}
parts +=
{{ part_list | join('\n ') }}
publish
......@@ -175,6 +175,27 @@ context = section parameter_dict preload-userhosts-runzope-parameter
template = {{ parameter_dict['runzope-userhosts-preloaded-template'] }}
mode = 755
{# Hack to deploy SSL certs via instance parameters -#}
{% for zodb in zodb_dict.itervalues() -%}
{% set storage_dict = zodb.setdefault('storage-dict', {}) -%}
{% if zodb['type'] == 'neo' and storage_dict.get('ssl', 1) -%}
{% for k, v in (('_ca', 'ca.crt'),
('_cert', 'neo.crt'),
('_key', 'neo.key')) -%}
{% if k in storage_dict -%}
[{{ section('neo-ssl-' + k[1:]) }}]
recipe = slapos.recipe.template:jinja2
rendered = ${directory:etc}/{{v}}
template = inline:{{'{{'}}pem}}
context = key pem :pem
pem = {{dumps(storage_dict.pop(k))}}
{% endif -%}
{% endfor -%}
{% endif -%}
{% endfor -%}
{# endhack -#}
[zope-base]
recipe = slapos.cookbook:generic.zope.zeo.client
inituser = ${directory:instance}/inituser
......@@ -192,9 +213,23 @@ bt5-repository =
[zope-conf-parameter-base]
ip = {{ ipv4 }}
site-id = {{ site_id }}
{% set storage_dict = {'neo': {}, 'zeo': slapparameter_dict.get('zodb-zeo', {})} -%}
{% set zeo_dict = slapparameter_dict.get('zodb-zeo', {}) -%}
{% for name, zodb in zodb_dict.iteritems() -%}
{% do zodb.setdefault('storage-dict', {}).update(storage_dict[zodb['type']].get(name, {})) -%}
{% set storage_dict = zodb.setdefault('storage-dict', {}) -%}
{% if zodb['type'] == 'zeo' -%}
{% do storage_dict.update(zeo_dict.get(name, ())) -%}
{% else -%}
{% if name == slapparameter_dict.get('neo-name') -%}
{% do storage_dict.update(master_nodes=slapparameter_dict['neo-masters'],
name=slapparameter_dict['neo-cluster']) -%}
{% endif -%}
{{ assert(storage_dict['master_nodes'], name) }}
{% if storage_dict.pop('ssl', 1) -%}
{% do storage_dict.update(ca='~/etc/ca.crt',
cert='~/etc/neo.crt',
key='~/etc/neo.key') -%}
{% endif -%}
{% endif -%}
{% endfor -%}
developer-list = {{ dumps(slapparameter_dict['developer-list']) }}
instance = ${directory:instance}
......@@ -250,14 +285,9 @@ node-id = {{ dumps(node_id_base ~ '-' ~ index) }}
{% for db_name, zodb in zodb_dict.iteritems() -%}
{% if zodb['type'] == 'neo' -%}
{% do import_set.add('neo.client') -%}
{% set log = buildout_directory ~ '/var/log/' ~ name ~ '-neo-' ~ db_name ~ '.log' -%}
{% set log = '~/var/log/' ~ name ~ '-neo-' ~ db_name ~ '.log' -%}
{% do log_list.append(log) -%}
{% do zodb['storage-dict'].__setitem__('logfile', log) -%}
{% if db_name == slapparameter_dict.get('neo-name') -%}
{% do zodb['storage-dict'].__setitem__('name', slapparameter_dict['neo-cluster']) -%}
{% do zodb['storage-dict'].__setitem__('master_nodes', slapparameter_dict['neo-masters']) -%}
{% endif -%}
{{ assert(zodb['storage-dict']['master_nodes'], db_name) }}
{% do zodb['storage-dict'].update(logfile=log) -%}
{% endif -%}
{% endfor -%}
import-list = {{ dumps(list(import_set)) }}
......@@ -323,7 +353,7 @@ post = {{ bin_directory }}/slapos-kill --pidfile {{ '${' ~ conf_parameter_name ~
{% set next_port = next_port + 1 -%}
{% endfor -%}
[publish-zope]
[publish]
recipe = slapos.cookbook:publish.serialised
zope-address-list = {{ dumps(publish_list) }}
{#
......@@ -345,12 +375,19 @@ smtp-url = {{ dumps(slapparameter_dict['smtp-url']) }}
bt5 = {{ dumps(slapparameter_dict['bt5']) }}
bt5-repository-url = {{ dumps(slapparameter_dict['bt5-repository-url']) }}
[monitor-instance-parameter]
monitor-httpd-ipv6 = {{ (ipv6_set | list)[0] }}
monitor-httpd-port = {{ next_port }}
monitor-title = Zope monitor
[buildout]
extends = {{ logrotate_cfg }}
extends =
{{ logrotate_cfg }}
{{ parameter_dict['template-monitor'] }}
parts +=
erp5-promise
{{ part_list | join('\n ') }}
publish-zope
publish
versions = versions
[versions]
......
......@@ -36,6 +36,7 @@ fonts = {{ fonts_location }}
buildout-bin-directory = {{ buildout_bin_directory }}
6tunnel = {{ sixtunnel_location }}
dash = {{ dash_location }}
template-monitor = {{ dumps(template_monitor) }}
[dynamic-template-cloudooo]
<= jinja2-template-base
......@@ -84,6 +85,7 @@ bin-directory = {{ bin_directory }}
dash = {{ dash_location }}
template-haproxy-cfg = {{ template_haproxy_cfg }}
template-apache-conf = {{ template_apache_conf }}
template-monitor = {{ dumps(template_monitor) }}
[dynamic-template-balancer]
<= jinja2-template-base
......@@ -94,6 +96,7 @@ extra-context =
[dynamic-template-zeo-parameters]
buildout-bin-directory = {{ buildout_bin_directory }}
template-monitor = {{ dumps(template_monitor) }}
[dynamic-template-zeo]
<= jinja2-template-base
......@@ -115,6 +118,7 @@ jsl = {{ jsl_location }}
link-binary = {{ dumps(zope_link_binary) }}
userhosts = {{ userhosts_location }}
runzope-userhosts-preloaded-template = {{ template_runzope_userhosts_preloaded }}
template-monitor = {{ dumps(template_monitor) }}
[dynamic-template-zope]
<= jinja2-template-base
......@@ -131,6 +135,7 @@ dcron-location = {{ dcron_location }}
gzip-location = {{ gzip_location }}
kumo-location = {{ kumo_location }}
logrotate-location = {{ logrotate_location }}
template-monitor = {{ dumps(template_monitor) }}
[dynamic-template-kumofs]
<= jinja2-template-base
......
......@@ -62,4 +62,4 @@ feedparser = 5.1.1
# Required by:
# slapos.toolbox==0.40.2
paramiko = 1.15.2
paramiko = 1.15.3
......@@ -205,4 +205,4 @@ feedparser = 5.1.3
# Required by:
# slapos.toolbox==0.40.2
paramiko = 1.15.2
paramiko = 1.15.3
......@@ -202,7 +202,7 @@ feedparser = 5.1.3
# Required by:
# slapos.toolbox==0.40.2
paramiko = 1.15.2
paramiko = 1.15.3
# Required by:
# slapos.recipe.maarch==0.4
......
Monitor
=======
This stack has for purpose to know if all promises went/are ok.
It provides a web interface, to see which promises failed. It also provide a rss
feed to easily know the actual state of your instance, and to know when it
started to went bad.
THIS STACK IS A KIND OF FORK OF THE `stack/monitor`. THIS ONE WAS CREATED AS A
REDESIGNED ONE TO REMOVE UNWANTED FEATURES AND TO GO FURTHER TO THE GOOD DESIGN
DIRECTION. PLEASE, DO NOT USE THE OLD MONITORING INTERFACE OR ONLY FOR BACKWARD
COMPATIBILITY REASON.
Summary:
- Activate monitoring for you software
- Add a monitor promise
- Information about URL access
- Monitor promise configuration example
- Promise requirements
- monitor.haljson example
- monitor.conf example
Activate monitoring for your software
-------------------------------------
You just have to extend the monitor stack from your software.cfg.
You can also create a new buildout which extends your software, and the
monitoring stack:
[buildout]
extends =
monitor_url
my_software_url
In your instance.cfg, your publish section should be named `[publish]` in order
to extends the one of the monitoring stack.
Then, in the same file you can configure the monitor by adding this section:
[monitor-instance-parameter]
monitor-httpd-ipv6 = ...
monitor-httpd-port = ...
monitor-title = ...
Add a monitor promise
---------------------
For instance, we want to create a promise for KVM log parsing. Add these
sections in its instance.cfg:
[directory]
monitor-promise = ${:etc}/monitor-promise
[kvm-log-parser-promise]
recipe = ....
filename = kvm-log-parser
rendered = ${directory:monitor-promise}/${:filename}
mode = 0755
[buildout]
parts += kvm-log-parser-promise
We can optionaly add promise title:
[kvm-log-parser-promise-parameter]
# fill with -> see "Service config example" below
title = Kvm log parse
[kvm-log-parser-promise-cfg]
recipe = slapos.recipe.template:jinja2
rendered = ${directory:monitor-promise}/${kvm-log-parser-promise:filename}.cfg
template = service.cfg
context = section parameter_dict kvm-log-parser-promise-parameter
[buildout]
parts += kvm-log-parser-promise-cfg
... and optionaly a specific frequency:
[kvm-log-parser-promise-parameter]
frequency = */5 * * * *
Optionaly, we also want a custom interface:
[directory]
kvm-log-parser-promise-interface-dir = ....../interface
[kvm-log-parser-promise-parameter]
private-path-list += ${directory:kvm-log-parser-promise-interface-dir}
[kvm-log-parser-promise-interface]
recipe = ....
rendered = ${directory:kvm-log-parser-interface-dir}/index.html
[buildout]
parts += kvm-log-parser-promise-interface
service.cfg:
[service]
{% for key, value in parameter_dict.items() -%}
{{ key }} = {{ value.strip().replace("\n", "\n ") }}
{% endfor -%}
Information about URL access
----------------------------
Open HTTP GET on static files, open HTTP POST on cgi
GET <root_monitor>/ // classical monitoring interface
GET <root_monitor>/monitor.haljson // monitor conf
GET <root_monitor>/public/<service>.status.json // service status json
Example for KVM log parsing promise
GET <kvm_monitor>/monitor.haljson
GET <kvm_monitor>/public/kvm-log-parser.status.json
GET <kvm_monitor>/public/kvm-log-parser/index.html
POST <kvm_monitor>/cgi-bin/monitor-run-promise.cgi?service=kvm-log-parse // rerun the promise
Information about internal file tree
------------------------------------
Tree for monitor runtime:
etc/monitor.conf // generated by slapos
etc/cron.d/monitor // generated by slapos
bin/monitor.py // generated by slapos
srv/monitor/web/index.html // static
srv/monitor/web/monitor.css // static
srv/monitor/web/monitor.js // static
srv/monitor/web/monitor.haljson // generated by monitor.py
srv/monitor/public/.... // generated by monitor.py
srv/monitor/private/.... // generated by monitor.py
srv/monitor/cgi-bin/.... // generated by monitor.py
Example for KVM log parsing promise
etc/monitor-promise/kvm-log-parse.cfg // generated by slapos (kvm-log-parser-promise)
etc/monitor-promise/kvm-log-parse // generated by slapos (kvm-log-parser-promise)
var/kvm-log-parser-promise/interface/index.html // generated by slapos (kvm-log-parser-promise)
var/log/kvm.log // generated by kvm
var/log/kvm-log-parse-last-report.csv // generated by kvm-log-parse
srv/monitor/public/kvm-log-parse.status.json // generated by kvm-log-parse (indirectly by the monitor promise executor)
srv/monitor/public/kvm-log-parse/kvm.log -> var/log/kvm.log // generated by monitor.py
srv/monitor/public/kvm-log-parse/kvm-log-parse-last-report.csv -> var/log/kvm-log-parse-last-report.csv // genareted by monitor.py
srv/monitor/private/kvm-log-parse/interface -> var/kvm-log-parser-promise/interface // generated by monitor.py
srv/monitor/cgi-bin/kvm-log-parse/action.cgi -> var/kvm-log-parser-promise/action.cgi // generated by monitor.py
Monitor promise config example
------------------------------
Example for KVM log parsing promise
# etc/monitor-promise/kvm-log-parse.cfg
[service]
title = Kvm log parse
frequency = <Cron Syntax>
cgi-path-list = # automatically symlink to srv/monitor/cgi-bin/$service/
$instance/var/kvm-log-parser-promise/action.cgi
public-path-list = # automatically symlink to srv/monitor/public/$service/
$instance/var/log/kvm.log
private-path-list = # automatically symlink to srv/monitor/private/$service/
$instance/var/log
$instance/var/kvm-log-parser-promise/interface
On cron, the command will be something like:
${service:frequency} ${monitor:promise-executor-path} '${monitor:service-pid-folder}/${service:name}.pid' '${service:status-path}' '${promise_path}'
and "monitor:promise-executor-path" is a script that would run a promise if not
already on going (see `run-promise.py`).
TODO cron accepts 999 characters maximum for a command, so we should reduce the
size of the cron command
TODO put `run-promise.py` in the software
Promise requirements
--------------------
A promise should check something (like web page is well cached, there's not too
much slow queries, ...):
- MUST output the status.json in stdout
- SHOULD output on stdout
- MUST return 0 if status is good else != 0
- the status.json MUST contain "message" (string) which explains why the status is OK or bad
monitor.haljson example
-----------------------
{
"_links": {
"related_monitor": [
{ "href": "<url>/static" },
{ "href": "http://my.other.monitor" }
]
},
"_embedded": {
"service": [
{
"_links": {
"status": { "href": "<url>/kvm-log-parse/status.json" },
"interface": { "href": "<url>/kvm-log-parse/index.html" }
},
"title": "KVM log parse",
"id": "kvm-log-parse"
},
{
"_links": {
"status": { "href": "<url>/<service>/status.json" },
"interface": { "href": "<url>/<service>/index.html" }
},
"title": "Service name",
"id": "<service>"
}
]
},
"title": "KVM Monitoring interface"
}
monitor.conf example
--------------------
[monitor]
title = KVM Monitoring interface
monitor-hal-json = $instance/srv/monitor/web/monitor.haljson
public-folder = $instance/srv/monitor/public
private-folder = $instance/srv/monitor/private
web-folder = $instance/srv/monitor/web
cgi-folder = $instance/srv/monitor/cgi-bin
service-pid-folder = $instance/var/monitor/service-pid
public-path-list =
$instance/var/log
private-path-list =
$instance/srv/backup/log_rotate
monitor-url-list =
https://[...]/
https://[...]/
[buildout]
# XXX THIS STACK IS A KIND OF FORK OF `stack/monitor`. THIS ONE WAS
# CREATED AS A REDESIGNED ONE TO REMOVE UNWANTED FEATURES AND
# TO GO FURTHER TO THE GOOD DESIGN DIRECTION. SEE THE README FOR
# MORE INFORMATION.
extends =
../../component/apache/buildout.cfg
../../component/curl/buildout.cfg
../../component/dash/buildout.cfg
../../component/dcron/buildout.cfg
../../component/openssl/buildout.cfg
parts +=
slapos-cookbook
dcron
monitor-eggs
extra-eggs
monitor-conf
monitor-bin
monitor-web-index-html
monitor-web-monitor-css
monitor-web-monitor-js
monitor-web-monitor-logout-cgi
monitor-web-monitor-logout-page
monitor-template
rss-bin
[monitor-download-base]
recipe = hexagonit.recipe.download
download-only = true
url = ${:_profile_base_location_}/${:filename}
mode = 0644
[monitor-eggs]
recipe = zc.recipe.egg
eggs =
collective.recipe.template
cns.recipe.symlink
[extra-eggs]
recipe = zc.recipe.egg
interpreter = pythonwitheggs
eggs =
PyRSS2Gen
Jinja2
[make-rss-script]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/make-rss.sh.in
md5sum = 98c8f6fd81e405b0ad10db07c3776321
output = ${buildout:directory}/template-make-rss.sh.in
mode = 0644
[monitor-conf]
<= monitor-download-base
filename = monitor.conf.in
md5sum = 2db5c08c7e8658981b4b1e3f27fd5967
[monitor-bin]
<= monitor-download-base
filename = monitor.py.in
md5sum = 2484cb185c391890a05db26c2163af8e
[monitor-web-default-promise-interface]
<= monitor-download-base
filename = default-promise-interface.html
md5sum = eaedae330cd155f8b693b418286d0d98
[monitor-web-index-html]
<= monitor-download-base
filename = index.html
md5sum = 262db07691c145301252a49b6b51d11d
[monitor-web-monitor-css]
<= monitor-download-base
filename = monitor.css
md5sum = a18ab932e5e2e656995f47c7d4a7853a
[monitor-web-monitor-js]
<= monitor-download-base
filename = monitor.js.in
md5sum = 3451788c49d3664cd9b72551fab34a9b
[monitor-web-monitor-logout-cgi]
recipe = slapos.recipe.template:jinja2
filename = monitor-logout.py.cgi
md5sum = 5b3c0aa559722a3bae5a692ea9a0a441
mode = 0755
template = ${:_profile_base_location_}/${:filename}
rendered = ${buildout:directory}/monitor-logout.cgi
context = key python_executable buildout:executable
[monitor-web-monitor-logout-page]
<= monitor-download-base
filename = monitor-logout.html
md5sum = b210c6842df541305d299081bc1bf81e
[monitor-web-monitor-promise-runner-cgi]
<= monitor-download-base
filename = monitor-run-promise.py.cgi
md5sum = 15625e5bf6c1b57b9199250951ffc16e
[monitor-template]
recipe = slapos.recipe.template:jinja2
filename = template-monitor.cfg
template = ${:_profile_base_location_}/instance-monitor.cfg.jinja2.in
rendered = ${buildout:directory}/template-monitor.cfg
md5sum = 6d5f1ceff198262319566ee25093c350
context =
key apache_location apache:location
key gzip_location gzip:location
raw monitor_bin ${monitor-bin:location}/${monitor-bin:filename}
raw monitor_conf_template ${monitor-conf:location}/${monitor-conf:filename}
raw monitor_password_promise_template ${monitor-password-promise:location}/${monitor-password-promise:filename}
raw monitor_password_cgi_template ${monitor-password-cgi:location}/${monitor-password-cgi:filename}
raw monitor_password_promise_interface_template ${monitor-password-promise-interface:location}/${monitor-password-promise-interface:filename}
raw monitor_web_default_promise_interface ${monitor-web-default-promise-interface:location}/${monitor-web-default-promise-interface:filename}
raw monitor_web_index_html ${monitor-web-index-html:location}/${monitor-web-index-html:filename}
raw monitor_web_monitor_css ${monitor-web-monitor-css:location}/${monitor-web-monitor-css:filename}
key monitor_web_monitor_logout_cgi monitor-web-monitor-logout-cgi:rendered
raw monitor_web_monitor_logout_page ${monitor-web-monitor-logout-page:location}/${monitor-web-monitor-logout-page:filename}
raw monitor_web_monitor_promise_runner_cgi ${monitor-web-monitor-promise-runner-cgi:location}/${monitor-web-monitor-promise-runner-cgi:filename}
raw monitor_web_monitor_js ${monitor-web-monitor-js:location}/${monitor-web-monitor-js:filename}
raw curl_executable_location ${curl:location}/bin/curl
raw dash_executable_location ${dash:location}/bin/dash
raw dcron_executable_location ${dcron:location}/sbin/crond
raw logrotate_executable_location ${logrotate:location}/usr/sbin/logrotate
raw monitor_httpd_template ${monitor-httpd-conf:location}/${monitor-httpd-conf:filename}
raw monitor_service_conf_template ${monitor-service-conf-template:location}/${monitor-service-conf-template:filename}
raw monitor_service_run ${monitor-service-template-run:location}/${monitor-service-template-run:filename}
raw openssl_executable_location ${openssl:location}/bin/openssl
raw python_executable ${buildout:executable}
raw promise_executor_py ${run-promise-py:location}/${run-promise-py:filename}
raw template_wrapper ${template-wrapper:output}
raw status2rss_executable_path ${status2rss-executable:location}/${status2rss-executable:filename}
[monitor-httpd-conf]
<= monitor-download-base
md5sum = 625d3d948c0af7b4848d7fad92bfb844
filename = monitor-httpd.conf.in
[monitor-service-conf-template]
<= monitor-download-base
filename = monitor-service.cfg.in
md5sum = 5913d2a0096b50537f394a49b762b3e5
[monitor-service-template-run]
<= monitor-download-base
md5sum = d5f29fa859a45696e1ff1bb174ab1111
filename = monitor-service-run.in
[run-promise-py]
<= monitor-download-base
filename = run-promise.py
md5sum = 6db26ce13becf8a190e34c14cb8b6f9f
[monitor-httpd-template]
<= monitor-download-base
md5sum = 93e1dda50cb71bfe29966b2946c02dd1
filename = cgi-httpd.conf.in
[index]
recipe = hexagonit.recipe.download
url = ${:_profile_base_location_}/webfile-directory/${:filename}
download-only = true
md5sum = e759977b21c70213daa4c2701f2c2078
destination = ${buildout:parts-directory}/monitor-index
filename = index.cgi.in
mode = 0644
[index-template]
recipe = hexagonit.recipe.download
url = ${:_profile_base_location_}/webfile-directory/${:filename}
download-only = true
destination = ${buildout:parts-directory}/monitor-template-index
md5sum = 7400c8cfa16a15a0d41f512b8bbb1581
filename = index.html.jinja2
mode = 0644
[status-cgi]
recipe = hexagonit.recipe.download
url = ${:_profile_base_location_}/webfile-directory/${:filename}
download-only = true
md5sum = e43d79bec8824265e22df7960744113a
destination = ${buildout:parts-directory}/monitor-template-status-cgi
filename = status.cgi.in
mode = 0644
[status-history-cgi]
recipe = hexagonit.recipe.download
url = ${:_profile_base_location_}/webfile-directory/${:filename}
download-only = true
#md5sum = 4fb26753ee669b8ac90ffe33dbd12e8f
destination = ${buildout:parts-directory}/monitor-template-status-history-cgi
filename = status-history.cgi.in
mode = 0644
[settings-cgi]
recipe = hexagonit.recipe.download
url = ${:_profile_base_location_}/webfile-directory/${:filename}
download-only = true
md5sum = b4cef123a3273e848e8fe496e22b20a8
destination = ${buildout:parts-directory}/monitor-template-settings-cgi
filename = settings.cgi.in
mode = 0644
[monitor-password-promise]
<= monitor-download-base
filename = monitor-password-promise.py.in
md5sum = 0a9a42551ed6bdb973fd1f0dd1d4ec86
[monitor-password-cgi]
<= monitor-download-base
md5sum = 04fc7e6d892d29a601cfd43d1700eeda
filename = monitor-password.py.cgi
[monitor-password-promise-interface]
<= monitor-download-base
filename = monitor-password-interface.html
md5sum = 04b664dfb47bfd3d01502768311aa239
[status2rss-executable]
<= monitor-download-base
filename = status2rss.py
md5sum = 65315ded80cd72f54f6e12d06ce813c4
[dcron-service]
recipe = slapos.recipe.template
url = ${template-dcron-service:output}
output = $${directory:services}/crond
mode = 0700
logfile = $${directory:log}/crond.log
[template-wrapper]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/wrapper.in
output = ${buildout:directory}/template-wrapper.cfg
mode = 0644
md5sum = 8cde04bfd0c0e9bd56744b988275cfd8
PidFile "{{ httpd_configuration.get('pid-file') }}"
StartServers 1
ServerLimit 1
ThreadLimit 4
ThreadsPerChild 4
ServerName example.com
ServerAdmin someone@email
<IfDefine !MonitorPort>
Listen [{{ httpd_configuration.get('listening-ip') }}]:{{ monitor_parameters.get('port') }}
Define MonitorPort
</IfDefine>
DocumentRoot "{{ directory.get('www') }}"
ErrorLog "{{ httpd_configuration.get('error-log') }}"
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 authn_core_module modules/mod_authn_core.so
LoadModule authz_host_module modules/mod_authz_host.so
LoadModule mime_module modules/mod_mime.so
LoadModule cgid_module modules/mod_cgid.so
LoadModule dir_module modules/mod_dir.so
LoadModule ssl_module modules/mod_ssl.so
LoadModule alias_module modules/mod_alias.so
LoadModule autoindex_module modules/mod_autoindex.so
LoadModule auth_basic_module modules/mod_auth_basic.so
LoadModule authz_user_module modules/mod_authz_user.so
LoadModule authn_file_module modules/mod_authn_file.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule rewrite_module modules/mod_rewrite.so
# SSL Configuration
<IfDefine !SSLConfigured>
Define SSLConfigured
SSLCertificateFile {{ httpd_configuration.get('certificate') }}
SSLCertificateKeyFile {{ httpd_configuration.get('key') }}
SSLRandomSeed startup builtin
SSLRandomSeed connect builtin
SSLRandomSeed startup /dev/urandom 256
SSLRandomSeed connect builtin
SSLProtocol -ALL +SSLv3 +TLSv1
SSLHonorCipherOrder On
SSLCipherSuite RC4-SHA:HIGH:!ADH
</IfDefine>
SSLEngine On
ScriptSock {{ httpd_configuration.get('cgid-pid-file') }}
<Directory {{ directory.get('www') }}>
SSLVerifyDepth 1
SSLRequireSSL
SSLOptions +StrictRequire
# XXX: security????
Options +ExecCGI
AddHandler cgi-script .cgi
DirectoryIndex {{ monitor_parameters.get('index-filename') }}
</Directory>
Alias /private/ {{ directory.get('private-directory') }}/
<Directory {{ directory.get('private-directory') }}>
Order Deny,Allow
Deny from env=AUTHREQUIRED
<Files ".??*">
Order Allow,Deny
Deny from all
</Files>
AuthType Basic
AuthName "Private access"
AuthUserFile "{{ monitor_parameters.get('htaccess-file') }}"
Require valid-user
Options Indexes FollowSymLinks
Satisfy all
</Directory>
<Location /rewrite>
AuthType Basic
AuthName "Private access"
AuthUserFile "{{ monitor_parameters.get('htaccess-file') }}"
Require valid-user
</Location>
ProxyVia On
RewriteEngine On
{% for key, value in monitor_rewrite_rule.iteritems() %}
RewriteRule ^/rewrite/{{ key }}($|/.*) {{ value }}/$1 [P,L]
{% endfor %}
<!DOCTYPE html>
<html>
<head>
<title>Promise status</title>
<style>
input, button {
min-height: 10mm;
min-width: 10mm;
}
</style>
<script>
function getServiceName() {
var match = /(?:&|\?)service_name=([^&]*)/.exec(location.search);
if (match) {
return match[1];
}
throw new Error("no service name found");
}
var service_name = getServiceName(),
monitor_json_url = "/monitor.haljson",
status_json_url = "/public/" + service_name + ".status.json",
rerun_cgi_url = "/cgi-bin/monitor-run-promise.cgi?service=" + service_name;
function newDeferred() {
var d = {
"promise": undefined,
"resolve": undefined,
"reject": undefined
};
d.promise = new Promise(function (resolve, reject) {
d.resolve = resolve;
d.reject = reject;
});
return d;
}
function xhr(param) {
/*global XMLHttpRequest */
var d = newDeferred(), xhr = new XMLHttpRequest(), k, i, l, a;
d.promise.cancel = function () { xhr.abort(); };
xhr.open((param.method || "GET").toUpperCase(), param.url, true);
xhr.responseType = param.responseType || "";
if (param.withCredentials !== undefined) {
xhr.withCredentials = param.withCredentials;
}
if (param.headers) {
a = Object.keys(param.headers);
l = a.length;
for (i = 0; i < l; i += 1) {
k = a[i];
xhr.setRequestHeader(k, param.headers[k]);
}
}
xhr.addEventListener("load", function (e) {
var r, t = e.target, callback;
if (param.noStatusCheck) {
d.resolve(t);
} else if (t.status < 400) {
d.resolve(t);
} else {
d.reject(new Error("HTTP: " + (t.status ? t.status + " " : "") + (t.statusText || "Unknown")));
}
}, false);
xhr.addEventListener("error", function (e) {
return d.reject(new Error("HTTP: Error"));
}, false);
xhr.addEventListener("abort", function (e) {
return d.reject(new Error("HTTP: Aborted"));
}, false);
xhr.send(param.data);
return d.promise;
}
function unexpectedError(reason) {
console.error(reason);
alert(reason);
}
function PromiseStatusInterface(config) {
var it = this,
statusP = document.createElement("p"),
descriptionH2 = document.createElement("h2"),
descriptionP = document.createElement("p"),
errorH2 = document.createElement("h2"),
errorPre = document.createElement("pre"),
header = document.createElement("header"),
h1 = document.createElement("h1"),
h2 = document.createElement("h2"),
a = document.createElement("a"),
button = document.createElement("button");
this.element = config.rootElement || document.createElement("div");
this.statusP = statusP;
this.descriptionP = descriptionP;
this.errorH2 = errorH2;
this.errorPre = errorPre;
this.element.appendChild(header);
header.appendChild(a);
a.setAttribute("tabindex", "-1");
a.setAttribute("href", "/");
a.appendChild(button);
button.textContent = "Home";
a = document.createElement("a");
button = document.createElement("button");
header.appendChild(a);
a.setAttribute("tabindex", "-1");
a.setAttribute("href", "");
a.appendChild(button);
button.textContent = "Refresh";
button = document.createElement("button");
header.appendChild(button);
button.textContent = "Run promise now";
button.onclick = function () {
this.runPromiseNow();
}.bind(this);
this.runPromiseNowButton = button;
this.element.appendChild(h1);
h1.textContent = "Promise status";
this.element.appendChild(statusP);
this.element.appendChild(descriptionH2);
descriptionH2.textContent = "Description";
this.element.appendChild(descriptionP);
this.element.appendChild(errorH2);
errorH2.textContent = "Error output";
errorH2.style.display = "none";
this.element.appendChild(errorPre);
errorPre.style.display = "none";
this.loadStatusUi();
this.loadDescriptionUi();
this.loadErrorUi();
}
PromiseStatusInterface.prototype.loadStatusJson = function () {
if (this.status_json_promise) { return; }
this.status_json_promise = Promise.resolve().then(function () {
return xhr({url: status_json_url, withCredentials: true, responseType: "json"});
}).then(function (xhr) {
return xhr.response;
});
this.status_json_promise.catch(function () { return; }).then(function () {
setTimeout(function () {
delete this.status_json_promise;
}.bind(this), 1000);
}.bind(this));
return this.status_json_promise;
};
PromiseStatusInterface.prototype.loadStatusUi = function () {
this.loadStatusJson();
this.statusP.textContent = "Loading status...";
return this.status_json_promise.then(function (status_json) {
if (status_json.status === "OK") {
this.statusP.textContent = "Status: OK.";
} else {
this.statusP.textContent = "Status: BAD (" + status_json.status + ").";
}
if (status_json.message) {
this.statusP.appendChild(document.createTextNode(" " + status_json.message));
}
}.bind(this), function (reason) {
var message = reason && (reason.target && (reason.target.statusText || "Unknown") || reason.message);
this.statusP.textContent = "Status Json Error: " + (message || "Unknown error");
}.bind(this)).catch(unexpectedError);
};
PromiseStatusInterface.prototype.loadDescriptionUi = function () {
this.loadStatusJson();
this.descriptionP.textContent = "Loading description...";
return this.status_json_promise.then(function (status_json) {
if (status_json.description) {
this.descriptionP.textContent = status_json.description;
} else {
this.descriptionP.textContent = "No description";
}
}.bind(this), function (reason) {
var message = reason && (reason.target && (reason.target.statusText || "Unknown") || reason.message);
this.descriptionP.textContent = "Status Json Error: " + (message || "Unknown error");
}.bind(this)).catch(unexpectedError);
};
PromiseStatusInterface.prototype.loadErrorUi = function () {
this.loadStatusJson();
this.errorPre.textContent = "Loading error output...";
return this.status_json_promise.then(function (status_json) {
if (status_json.error) {
this.errorH2.style.display = "";
this.errorPre.style.display = "";
this.errorPre.textContent = status_json.error;
} else {
this.errorH2.style.display = "none";
this.errorPre.style.display = "none";
this.errorPre.textContent = "";
}
}.bind(this), function (reason) {
var message = reason && (reason.target && (reason.target.statusText || "Unknown") || reason.message);
this.errorPre.textContent = "Status Json Error: " + (message || "Unknown error");
}.bind(this)).catch(unexpectedError);
};
PromiseStatusInterface.prototype.runPromiseNow = function () {
this.runPromiseNowButton.disabled = true;
var original_text = this.runPromiseNowButton.textContent;
this.runPromiseNowButton.textContent = "Sending message...";
return Promise.resolve().then(function () {
return xhr({url: rerun_cgi_url, method: "POST", withCredentials: true});
}).catch(unexpectedError).then(function () {
this.runPromiseNowButton.textContent = original_text;
}.bind(this));
};
/*global setTimeout */
setTimeout(function () {
/*global document */
document.body.innerHTML = "";
return new PromiseStatusInterface({rootElement: document.body});
});
</script>
</head>
<body>
<h1>Promise status</h1>
<noscript>Javascript should be enabled</noscript>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="monitor.css" />
<script src="monitor.js"></script>
</head>
<body>
<noscript>Please enable javascript on your browser to make this application to work.</noscript>
</body>
</html>
This diff is collapsed.
#!${dash-output:dash}
STATUS_DB={{ monitor_parameters['db-path'] }}
RSS_FILE={{ monitor_parameters['rss-path'] }}
PYTHON=${buildout:directory}/bin/${extra-eggs:interpreter}
STATUS2RSS=${rss-bin:location}/${rss-bin:filename}
$PYTHON $STATUS2RSS "Monitoring RSS feed" "{{ monitor_parameters['url'] }}/{{ monitor_parameters['index-filename'] }}" $STATUS_DB > $RSS_FILE
PidFile "{{ parameter_dict.get('pid-file') }}"
StartServers 1
ServerLimit 1
ThreadLimit 4
ThreadsPerChild 4
ServerName example.com
ServerAdmin someone@email
<IfDefine !MonitorPort>
Listen [{{ parameter_dict.get('listening-ip') }}]:{{ parameter_dict.get('port') }}
Define MonitorPort
</IfDefine>
DocumentRoot "{{ directory.get('www') }}"
ErrorLog "{{ parameter_dict.get('error-log') }}"
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 authn_core_module modules/mod_authn_core.so
LoadModule authz_host_module modules/mod_authz_host.so
LoadModule mime_module modules/mod_mime.so
LoadModule cgid_module modules/mod_cgid.so
LoadModule dir_module modules/mod_dir.so
LoadModule ssl_module modules/mod_ssl.so
LoadModule alias_module modules/mod_alias.so
LoadModule autoindex_module modules/mod_autoindex.so
LoadModule auth_basic_module modules/mod_auth_basic.so
LoadModule authz_user_module modules/mod_authz_user.so
LoadModule authn_file_module modules/mod_authn_file.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule rewrite_module modules/mod_rewrite.so
# SSL Configuration
<IfDefine !SSLConfigured>
Define SSLConfigured
SSLCertificateFile {{ parameter_dict.get('cert-file') }}
SSLCertificateKeyFile {{ parameter_dict.get('key-file') }}
SSLRandomSeed startup builtin
SSLRandomSeed connect builtin
SSLRandomSeed startup /dev/urandom 256
SSLRandomSeed connect builtin
SSLProtocol -ALL +SSLv3 +TLSv1
SSLHonorCipherOrder On
SSLCipherSuite RC4-SHA:HIGH:!ADH
</IfDefine>
AddType application/hal+json .haljson
SSLEngine On
ScriptSock {{ parameter_dict.get('cgid-pid-file') }}
<Directory {{ directory.get('www') }}>
SSLVerifyDepth 1
SSLRequireSSL
SSLOptions +StrictRequire
# XXX: security????
DirectoryIndex index.html
Options FollowSymLinks
Order Deny,Allow
AuthType Basic
AuthName "Private access"
AuthUserFile "{{ parameter_dict.get('htpasswd-file') }}"
Require valid-user
</Directory>
Alias /private {{ directory.get('private') }}/
<Directory {{ directory.get('private') }}>
Order Deny,Allow
Deny from env=AUTHREQUIRED
<Files ".??*">
Order Allow,Deny
Deny from all
</Files>
AuthType Basic
AuthName "Private access"
AuthUserFile "{{ parameter_dict.get('htpasswd-file') }}"
Require valid-user
Options Indexes FollowSymLinks
Satisfy all
</Directory>
Alias /public {{ directory.get('public') }}/
<Directory {{ directory.get('public') }}>
Options Indexes FollowSymLinks
Order Allow,Deny
Allow from all
</Directory>
Alias /cgi-bin {{ directory.get('cgi-bin') }}
<Directory {{ directory.get('cgi-bin') }}>
# XXX security ???
Order Deny,Allow
Deny from all
<Files "*.cgi">
Order Deny,Allow
Deny from env=AUTHREQUIRED
AuthType Basic
AuthName "Private access"
AuthUserFile "{{ parameter_dict.get('htpasswd-file') }}"
Require valid-user
</Files>
Options +ExecCGI
AddHandler cgi-script .cgi
Options Indexes FollowSymLinks
Satisfy all
</Directory>
<!DOCTYPE html>
<html>
<head><title>Monitor logout</title></head>
<body>
<noscript>Cannot logout without javascript</noscript>
<script>
var logoutURL = "/cgi-bin/monitor-logout.cgi",
xhr = new XMLHttpRequest();
xhr.onload = function () {
if (xhr.status === 401) {
document.body.innerHTML = "<p>You are now logged out. You can go back to the monitor interface <a href=\"/\">here</a>.</p>";
} else {
console.error("Cannot logout (" + xhr.status + ")");
document.body.innerHTML = "<p>Cannot logout, retrying in 5 seconds.</p>";
setTimeout(location.reload.bind(location), 5000);
}
};
xhr.onerror = function () {
document.body.innerHTML = "<p>Cannot logout, please try again later.</p>";
};
xhr.open("POST", logoutURL, true, " logout", " password");
xhr.send();
document.body.innerHTML = "<p>Logging out...</p>";
</script>
</body>
</html>
#!{{ python_executable }}
print("Status: 401 Unauthorized\r\nWWW-Authenticate: Basic realm=\"Private access\"\r\n\r")
This diff is collapsed.
#!{{ python_executable }}
password_changed_once_path = "{{ password_changed_once_path }}"
import os
def main():
if os.path.exists(password_changed_once_path):
print('{"status":"OK"}')
return 0
print('{"status":"BAD","message":"Password never changed"}')
return 1
if __name__ == "__main__":
exit(main())
#!{{ python_executable }}
htpasswd_executable = "{{ htpasswd_executable }}"
htpasswd_path = "{{ htpasswd_path }}"
password_changed_once_path = "{{ password_changed_once_path }}"
import cgi
import cgitb
import os
import sys
cgitb.enable(display=0)
def sh(args):
os.system(" ".join(["'" + arg.replace("'", "'\\''") + "'" for arg in args]))
def touch(path):
open(path, "w").close()
def main():
form = cgi.FieldStorage()
password = form["password"].value
if sh([htpasswd_executable, "-b", htpasswd_path, "admin", password]):
sys.stdout.write("Status: 500 Internal Server Error\r\n\r\n")
return 1
touch(password_changed_once_path)
sys.stdout.write("Status: 204 No Content\r\n\r\n")
return 0
if __name__ == "__main__":
exit(main())
#!{{ python_executable }}
# Put this file in the software release
promise_wrapper_folder = "{{ promise_wrapper_folder }}"
import cgi
import cgitb
import os
cgitb.enable(display=0)
def main():
form = cgi.FieldStorage()
promise_name = form["service"].value
if "/" not in promise_name:
promise_path = os.path.join(promise_wrapper_folder, promise_name)
os.spawnl(os.P_NOWAIT, promise_path, promise_path)
print("Status: 204 No Content\r\n\r")
if __name__ == "__main__":
exit(main())
#!/usr/bin/env python
configuration_location = "%(configuration_location)s"
process_pid_file = "%(process_pid_file)s"
import sys
import os
import ConfigParser
import json
import subprocess
def loadConfig(config_file):
config = ConfigParser.ConfigParser()
config.read(config_file)
return config
def main():
config = loadConfig(configuration_location)
script_path = config.get("service", "script-path")
executable_folder = os.path.dirname(script_path)
executable = os.path.basename(script_path)
parameter_json = os.path.join(os.path.abspath(os.path.dirname(__file__)),
'parameters_%%s.json' %% executable)
with open(parameter_json, 'w') as fjson:
fjson.write(json.dumps(dict(config.items("parameter"))))
process = subprocess.Popen(
[script_path, parameter_json],
stdin=None,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
with open(process_pid_file, "w") as pidfile:
pidfile.write(str(process.pid))
if __name__ == "__main__":
sys.exit(main())
\ No newline at end of file
[service]
{% for key, value in parameter_dict.items() -%}
{{ key }} = {{ value.strip().replace("\n", "\n ") }}
{% endfor -%}
[slap-parameters]
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}
[monitor-parameters]
json-filename = monitor.json
json-path = $${monitor-directory:monitor-result}/$${:json-filename}
rss-filename = rssfeed.html
rss-path = $${monitor-directory:public-cgi}/$${:rss-filename}
executable = $${monitor-directory:bin}/monitor.py
port = 9685
htaccess-file = $${monitor-directory:etc}/.htaccess-monitor
url = https://[$${slap-parameters:ipv6-random}]:$${:port}
index-filename = index.cgi
index-path = $${monitor-directory:www}/$${:index-filename}
db-path = $${monitor-directory:etc}/monitor.db
monitor-password-path = $${monitor-directory:etc}/.monitor.shadow
[monitor-directory]
recipe = slapos.cookbook:mkdirectory
# Standard directory needed by monitoring stack
home = $${buildout:directory}
etc = $${:home}/etc
bin = $${:home}/bin
srv = $${:home}/srv
var = $${:home}/var
log = $${:var}/log
run = $${:var}/run
service = $${:etc}/service/
etc-run = $${:etc}/run/
tmp = $${:home}/tmp
promise = $${:etc}/promise
cron-entries = $${:etc}/cron.d
crontabs = $${:etc}/crontabs
cronstamps = $${:etc}/cronstamps
ca-dir = $${:srv}/ssl
www = $${:var}/www
cgi-bin = $${:var}/cgi-bin
monitoring-cgi = $${:cgi-bin}/monitoring
knowledge0-cgi = $${:cgi-bin}/zero-knowledge
public-cgi = $${:cgi-bin}/monitor-public
monitor-custom-scripts = $${:etc}/monitor
monitor-result = $${:var}/monitor
private-directory = $${:srv}/monitor-private
[public-symlink]
recipe = cns.recipe.symlink
symlink = $${monitor-directory:public-cgi} = $${monitor-directory:www}/monitor-public
autocreate = true
[cron]
recipe = slapos.cookbook:cron
dcrond-binary = ${dcron:location}/sbin/crond
cron-entries = $${monitor-directory:cron-entries}
crontabs = $${monitor-directory:crontabs}
cronstamps = $${monitor-directory:cronstamps}
catcher = $${cron-simplelogger:wrapper}
binary = $${monitor-directory:service}/crond
# Add log to cron
[cron-simplelogger]
recipe = slapos.cookbook:simplelogger
wrapper = $${monitor-directory:bin}/cron_simplelogger
log = $${monitor-directory:log}/cron.log
[cron-entry-monitor]
<= cron
recipe = slapos.cookbook:cron.d
name = launch-monitor
frequency = */5 * * * *
command = $${deploy-monitor-script:rendered} -a
[cron-entry-rss]
<= cron
recipe = slapos.cookbook:cron.d
name = build-rss
frequency = */5 * * * *
command = $${make-rss:rendered}
[setup-static-files]
recipe = plone.recipe.command
command = ln -s ${download-monitor-jquery:destination} $${monitor-directory:www}/static
update-command = $${:command}
[deploy-index]
recipe = slapos.recipe.template:jinja2
template = ${index:location}/${index:filename}
rendered = $${monitor-parameters:index-path}
update-apache-access = ${apache:location}/bin/htpasswd -cb $${monitor-parameters:htaccess-file} admin
mode = 0744
context =
key cgi_directory monitor-directory:cgi-bin
raw index_template $${deploy-index-template:location}/$${deploy-index-template:filename}
key monitor_password_path monitor-parameters:monitor-password-path
key monitor_password_script_path deploy-monitor-password-cgi:rendered
key apache_update_command :update-apache-access
raw extra_eggs_interpreter ${buildout:directory}/bin/${extra-eggs:interpreter}
raw default_page /static/welcome.html
section rewrite_element monitor-rewrite-rule
[deploy-index-template]
recipe = hexagonit.recipe.download
url = ${index-template:location}/$${:filename}
destination = $${monitor-directory:www}
filename = ${index-template:filename}
download-only = true
mode = 0644
[deploy-status-cgi]
recipe = slapos.recipe.template:jinja2
template = ${status-cgi:location}/${status-cgi:filename}
rendered = $${monitor-directory:monitoring-cgi}/$${:filename}
filename = status.cgi
mode = 0744
context =
key json_file monitor-parameters:json-path
key monitor_bin monitor-parameters:executable
key pwd monitor-directory:monitoring-cgi
key this_file :filename
raw python_executable ${buildout:executable}
[deploy-status-history-cgi]
recipe = slapos.recipe.template:jinja2
template = ${status-history-cgi:location}/${status-history-cgi:filename}
rendered = $${monitor-directory:monitoring-cgi}/$${:filename}
filename = status-history.cgi
mode = 0744
context =
key monitor_db_path monitor-parameters:db-path
key status_history_length zero-parameters:status-history-length
raw python_executable ${buildout:executable}
[deploy-settings-cgi]
recipe = slapos.recipe.template:jinja2
template = ${settings-cgi:location}/${settings-cgi:filename}
rendered = $${monitor-directory:knowledge0-cgi}/$${:filename}
filename = settings.cgi
mode = 0744
context =
raw config_cfg $${buildout:directory}/knowledge0.cfg
raw timestamp $${buildout:directory}/.timestamp
raw python_executable ${buildout:executable}
key pwd monitor-directory:knowledge0-cgi
key this_file :filename
[deploy-monitor-password-cgi]
recipe = slapos.recipe.template:jinja2
template = ${monitor-password-cgi:location}/${monitor-password-cgi:filename}
rendered = $${monitor-directory:knowledge0-cgi}/$${:filename}
filename = monitor-password.cgi
mode = 0744
context =
raw python_executable ${buildout:executable}
key pwd monitor-directory:knowledge0-cgi
key this_file :filename
[deploy-monitor-script]
recipe = slapos.recipe.template:jinja2
template = ${monitor-bin:location}/${monitor-bin:filename}
rendered = $${monitor-parameters:executable}
mode = 0744
context =
section directory monitor-directory
section monitor_parameter monitor-parameters
key monitoring_file_json monitor-parameters:json-path
raw python_executable ${buildout:executable}
[make-rss]
recipe = slapos.recipe.template:jinja2
template = ${make-rss-script:output}
rendered = $${monitor-directory:bin}/make-rss.sh
mode = 0744
context =
section directory monitor-directory
section monitor_parameters monitor-parameters
[monitor-directory-access]
recipe = plone.recipe.command
command = ln -s $${:source} $${monitor-directory:private-directory}
source =
[monitor-instance-log-access]
recipe = plone.recipe.command
command = if [ -d $${:source} ]; then ln -s $${:source} $${monitor-directory:private-directory}/instance-logs; fi
update-command = if [ -d $${:source} ]; then ln -s $${:source} $${monitor-directory:private-directory}/instance-logs; fi
source = $${monitor-directory:home}/.slapgrid/log/
location = $${:source}
[cadirectory]
recipe = slapos.cookbook:mkdirectory
requests = $${monitor-directory:ca-dir}/requests/
private = $${monitor-directory:ca-dir}/private/
certs = $${monitor-directory:ca-dir}/certs/
newcerts = $${monitor-directory:ca-dir}/newcerts/
crl = $${monitor-directory:ca-dir}/crl/
[certificate-authority]
recipe = slapos.cookbook:certificate_authority
openssl-binary = ${openssl:location}/bin/openssl
ca-dir = $${monitor-directory:ca-dir}
requests-directory = $${cadirectory:requests}
wrapper = $${monitor-directory:service}/certificate_authority
ca-private = $${cadirectory:private}
ca-certs = $${cadirectory:certs}
ca-newcerts = $${cadirectory:newcerts}
ca-crl = $${cadirectory:crl}
[ca-httpd]
<= certificate-authority
recipe = slapos.cookbook:certificate_authority.request
key-file = $${cadirectory:certs}/httpd.key
cert-file = $${cadirectory:certs}/httpd.crt
executable = $${monitor-directory:bin}/cgi-httpd
wrapper = $${monitor-directory:service}/cgi-httpd
# Put domain name
name = example.com
###########
# Deploy a webserver running cgi scripts for monitoring
###########
[public]
recipe = slapos.cookbook:zero-knowledge.write
filename = knowledge0.cfg
status-history-length = 5
[zero-parameters]
recipe = slapos.cookbook:zero-knowledge.read
filename = $${public:filename}
[monitor-rewrite-rule]
# XXX could it be something lighter?
[monitor-httpd-configuration]
pid-file = $${monitor-directory:run}/cgi-httpd.pid
cgid-pid-file = $${monitor-directory:run}/cgi-httpd-cgid.pid
error-log = $${monitor-directory:log}/cgi-httpd-error-log
listening-ip = $${slap-parameters:ipv6-random}
certificate = $${ca-httpd:cert-file}
key = $${ca-httpd:key-file}
[monitor-httpd-configuration-file]
recipe = slapos.recipe.template:jinja2
template = ${monitor-httpd-template:destination}/${monitor-httpd-template:filename}
rendered = $${monitor-directory:etc}/cgi-httpd.conf
mode = 0744
context =
section directory monitor-directory
section monitor_parameters monitor-parameters
section httpd_configuration monitor-httpd-configuration
section monitor_rewrite_rule monitor-rewrite-rule
[cgi-httpd-wrapper]
recipe = slapos.cookbook:wrapper
apache-executable = ${apache:location}/bin/httpd
command-line = $${:apache-executable} -f $${monitor-httpd-configuration-file:rendered} -DFOREGROUND
wrapper-path = $${ca-httpd:executable}
wait-for-files =
$${cadirectory:certs}/httpd.key
$${cadirectory:certs}/httpd.crt
[cgi-httpd-graceful-wrapper]
recipe = slapos.recipe.template:jinja2
template = ${template-wrapper:output}
rendered = $${monitor-directory:etc-run}/cgi-httpd-graceful
mode = 0700
context =
key content :command
command = kill -USR1 $(cat $${monitor-httpd-configuration:pid-file})
[monitor-promise]
recipe = slapos.cookbook:check_url_available
path = $${monitor-directory:promise}/monitor
url = $${monitor-parameters:url}/$${monitor-parameters:index-filename}
check-secure = 1
dash_path = ${dash:location}/bin/dash
curl_path = ${curl:location}/bin/curl
[publish-connection-informations]
recipe = slapos.cookbook:publish
monitor_url = $${monitor-parameters:url}
[monitor]
{% for key, value in parameter_dict.items() -%}
{{ key }} = {{ value.strip().replace("\n", "\n ") }}
{% endfor -%}
body { width: 80vw; margin: auto; padding-top: 1%; }
/* h1 { align-text: center; margin: auto; } */
/*td { padding: 0 2%; }/**/
td { padding: 0 1em; }/**/
table { border: 1px solid black; }
table > table { margin-top: 1em; }
input {
box-sizing: border-box;
min-height: 10mm;
min-width: 10mm;
}
button {
box-sizing: border-box;
min-height: 10mm;
min-width: 10mm;
background-color: lightgray;
background: linear-gradient(180deg, #F6F6F6 0%, #DDDDDD 100%);
border-radius: 2px;
border-style: solid;
border-width: 1px;
border-color: #A4A4A4;
}
a.as-button {
display: inline-block;
box-sizing: border-box;
min-height: 10mm;
min-width: 10mm;
padding: 0.5em 0.5em;
text-align: center;
text-decoration: initial;
}
a.as-button {
color: black;
background-color: lightgray;
background: linear-gradient(180deg, #F6F6F6 0%, #DDDDDD 100%);
border-radius: 2px;
border-style: solid;
border-width: 1px;
border-color: #A4A4A4;
}
a.as-button:active, button:active {
background-color: white;
background: linear-gradient(0deg, #F6F6F6 0%, #DDDDDD 100%);
}
a.as-button:hover, button:hover {
border-color: #777777;
}
/*jslint indent: 2 */
(function () {
"use strict";
var monitor_title = '{{ dumps(monitor_title)[5:-1] }}',
RSS_ICON_DATA_URI = [
"data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIj8+CjwhRE9DVFlQR",
"SBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cu",
"dzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+CjxzdmcgeG1sbnM",
"9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2ZXJzaW9uPSIxLjEiIHdpZHRoPS",
"IxMjhweCIgaGVpZ2h0PSIxMjhweCIgdmlld0JveD0iMCAwIDI1NiAyNTYiPgo8cmVjd",
"CB3aWR0aD0iMjU2IiBoZWlnaHQ9IjI1NiIgeD0iMCIgIHk9IjAiICBmaWxsPSIjRjQ5",
"QzUyIi8+CjxjaXJjbGUgY3g9IjY4IiBjeT0iMTg5IiByPSIyNCIgZmlsbD0iI0ZGRiI",
"vPgo8cGF0aCBkPSJNMTYwIDIxM2gtMzRhODIgODIgMCAwIDAgLTgyIC04MnYtMzRhMT",
"E2IDExNiAwIDAgMSAxMTYgMTE2eiIgZmlsbD0iI0ZGRiIvPgo8cGF0aCBkPSJNMTg0I",
"DIxM0ExNDAgMTQwIDAgMCAwIDQ0IDczIFYgMzhhMTc1IDE3NSAwIDAgMSAxNzUgMTc1",
"eiIgZmlsbD0iI0ZGRiIvPgo8L3N2Zz4K"
].join("");
function loadJson(url) {
/*global XMLHttpRequest */
return new Promise(function (resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.onload = function (event) {
var response = event.target;
if (response.status < 400) {
try {
resolve(JSON.parse(response.responseText));
} catch (e) {
reject(e);
}
} else {
reject(new Error("XHR: " + response.status + ": " + response.statusText));
}
};
xhr.onerror = function () {
reject(new Error("XHR: Error"));
};
xhr.open("GET", url, true);
xhr.send();
});
}
///////////////////
// tools for HAL //
function getProperty(object, path) {
if (Array.isArray(path)) {
while (path.length) {
object = object[path.shift()];
}
} else {
return object[path];
}
return object;
}
function softGetProperty(object, path) {
try {
return getProperty(object, path);
} catch (ignored) {
return undefined;
}
}
function forceList(value) {
if (Array.isArray(value)) {
return value;
}
return [value];
}
function softGetPropertyAsList(object, path) {
try {
return forceList(getProperty(object, path));
} catch (ignored) {
return [];
}
}
///////////////////
function htmlToElementList(html) {
/*global document */
var div = document.createElement("div");
div.innerHTML = html;
return div.querySelectorAll("*");
}
function resolveUrl(firstUrl) {
/*jslint plusplus: true */
/*global URL, location */
var l = arguments.length, i = 1, url = new URL(firstUrl, location.href);
while (i < l) { url = new URL(arguments[i++], url); }
return url.href;
}
function escapeHtml(html) {
return html.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
}
function loadAndRenderMonitorSection(root, monitor_dict, monitor_url) {
var table, service_list = softGetPropertyAsList(monitor_dict, ["_embedded", "service"]);
if (!service_list) {
root.textContent = "";
return;
}
table = document.createElement("table");
root.appendChild(table);
return Promise.all(service_list.map(function (service_dict) {
var interface_url = softGetProperty(service_dict, ["_links", "interface", "href"]),
status_url = softGetProperty(service_dict, ["_links", "status", "href"]),
href_html_part = (interface_url ? " href=\"" + escapeHtml(interface_url) + "\"" : ""),
title_html_part = (service_dict.title ? escapeHtml(service_dict.title) : (service_dict.id ||"Untitled")),
row = htmlToElementList("<table><tbody><tr><td><a" + href_html_part + ">" + title_html_part + "</a></td><td>Loading status...</td><td><a" + href_html_part + "><div style=\"height: 10mm; width: 10mm; background-color: gray;\"></div></a></td></tr></tbody></table>");
table.appendChild(row[2]);
if (!status_url) {
row[5].textContent = "No status";
return;
}
return loadJson(resolveUrl(monitor_url, status_url)).then(function (status_dict) {
if (status_dict.description) {
row[2].title = status_dict.description;
}
row[5].textContent = status_dict.message || "";
row[8].style.backgroundColor = status_dict.status === "OK" ? "green" : "red";
}).catch(function (reason) {
row[5].textContent = (reason && (reason.name + ": " + reason.message));
row[8].style.backgroundColor = "red";
});
}));
}
function loadAndRenderMonitorJson(root) {
root.textContent = "Loading monitor section...";
return loadJson("monitor.haljson").then(function (monitor_dict) {
//monitor_json_list.push(monitor_dict);
root.innerHTML = "";
var loading = loadAndRenderMonitorSection(root, monitor_dict), related_monitor_list = softGetPropertyAsList(monitor_dict, ["_links", "related_monitor"]);
if (!related_monitor_list.length) { return loading; }
return Promise.all([loading, Promise.all(related_monitor_list.map(function (link) {
var div = htmlToElementList("<div>Loading monitor section...</div>")[0];
root.appendChild(div);
if (link.href[link.href.length - 1] !== "/") {
link.href += "/";
}
link.href = resolveUrl(link.href, "monitor.haljson");
return loadJson(link.href).catch(function (reason) {
div.textContent = (reason && (reason.name + ": " + reason.message));
}).then(function (monitor_dict) {
//monitor_json_list.push(monitor_dict);
div.remove();
return loadAndRenderMonitorSection(root, monitor_dict, link.href);
});
}))]);
});
}
function bootstrap(root) {
var element_list = htmlToElementList([
"<header>",
" <a href=\"\" class=\"as-button\">Refresh</a>",
" <a href=\"/logout\" class=\"as-button\">Logout</a>",
" <a href=\"/feed\"><img src=\"" + RSS_ICON_DATA_URI + "\" style=\"width: 10mm; height: 10mm; vertical-align: middle;\" alt=\"[RSS Feed]\" /></a>",
"</header>",
"<h1>" + monitor_title + "</h1>",
"<h2>System health status</h2>",
"<p>This interface allow to see the status of several features, it may show problems and sometimes provides a way to fix them.</p>",
"<p>Red square means the feature has a problem, green square means it is ok.</p>",
"<p>You can click on a feature below to get more precise information.</p>"
].join("\n")), div = document.createElement("div"), tmp;
[].reduce.call(element_list, function (array, element) {
if (element.parentNode.parentNode) { return array; }
array.push(element);
return array;
}, []).forEach(function (element) {
root.appendChild(element);
});
document.title = monitor_title;
root.appendChild(div);
/*global alert */
tmp = loadAndRenderMonitorJson(div);
tmp.catch(alert);
/*global console */
tmp.catch(console.error.bind(console));
}
/*global setTimeout */
setTimeout(function () {
/*global document */
bootstrap(document.body);
});
}());
#!{{ python_executable }}
# Put this file in the software release
promise_runner_path = "{{ promise_runner_path }}"
public_folder = "{{ public_folder }}"
private_folder = "{{ private_folder }}"
monitor_configuration_path = "{{ monitor_configuration_path }}"
promise_folder = "{{ promise_folder }}"
monitor_promise_folder = "{{ monitor_promise_folder }}"
promise_wrapper_folder = "{{ promise_wrapper_folder }}"
import sys
import os
import stat
import subprocess
import threading
import json
import ConfigParser
import traceback
def main():
# initialisation
config = loadConfig([monitor_configuration_path])
# get promises in monitor_promise_folder
promise_dict = {}
fillPromiseDictFromFolder(promise_dict, monitor_promise_folder)
# get promises in promise_folder
fillPromiseDictFromFolder(promise_dict, promise_folder)
# get promises configurations
for filename in os.listdir(monitor_promise_folder):
path = os.path.join(monitor_promise_folder, filename)
if os.path.isfile(path) and filename[-4:] == ".cfg":
promise_name = filename[:-4]
if promise_name in promise_dict:
loadConfig([path], promise_dict[promise_name]["configuration"])
promise_items = promise_dict.items()
# create symlinks from service configurations
for service_name, promise in promise_items:
service_config = promise["configuration"]
createSymlinksFromConfig((config, "monitor", "public-folder"), (service_config, "service", "public-path-list"), service_name)
createSymlinksFromConfig((config, "monitor", "private-folder"), (service_config, "service", "private-path-list"), service_name)
# create symlinks from monitor.conf
createSymlinksFromConfig((config, "monitor", "public-folder"), (config, "monitor", "public-path-list"))
createSymlinksFromConfig((config, "monitor", "private-folder"), (config, "monitor", "private-path-list"))
# generate monitor.json
monitor_dict = {}
tmp = softConfigGet(config, "monitor", "title")
if tmp:
monitor_dict["title"] = tmp
tmp = softConfigGet(config, "monitor", "monitor-url-list")
if tmp:
monitor_dict["_links"] = {"related_monitor": [{"href": url} for url in tmp.split()]}
if promise_items:
service_list = []
monitor_dict["_embedded"] = {"service": service_list}
for service_name, promise in promise_items:
service_config = promise["configuration"]
service_dict = {}
service_list.append(service_dict)
service_dict["id"] = service_name
service_dict["_links"] = {"status": {"href": "/public/%s.status.json" % service_name}} # hardcoded
tmp = softConfigGet(service_config, "service", "title")
if tmp:
service_dict["title"] = tmp
interface_path = os.path.join(private_folder, service_name, "interface/index.html") # hardcoded
if os.path.isfile(interface_path):
service_dict["_links"]["interface"] = {"href": "/private/%s/interface/" % service_name} # hardcoded
else:
service_dict["_links"]["interface"] = {"href": "/default-promise-interface.html?service_name=%s" % service_name} # XXX hardcoded
with open(config.get("monitor", "monitor-hal-json"), "w") as fp:
json.dump(monitor_dict, fp)
# put promises to a cron file
# XXX only if at least one configuration file is modified, then write in the cron
service_pid_folder = config.get("monitor", "service-pid-folder")
crond_folder = config.get("monitor", "crond-folder")
cron_line_list = []
for service_name, promise in promise_items:
service_status_path = "%s/%s.status.json" % (public_folder, service_name) # hardcoded
mkdirAll(os.path.dirname(service_status_path))
command = ("%s %s %s " % (
promise_runner_path,
os.path.join(service_pid_folder, "%s.pid" % service_name),
service_status_path,
)) + promise["path"]
cron_line_list.append("%s %s" % (
softConfigGet(service_config, "service", "frequency") or "* * * * *",
command.replace("%", "\\%"),
))
wrapper_path = os.path.join(promise_wrapper_folder, service_name)
with open(wrapper_path, "w") as fp:
fp.write("#!/bin/sh\n%s" % command) # XXX hardcoded, use dash, sh or bash binary!
os.chmod(wrapper_path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | stat.S_IRGRP | stat.S_IROTH )
with open(crond_folder + "/monitor-promises", "w") as fp:
fp.write("\n".join(cron_line_list))
return 0
def loadConfig(pathes, config=None):
if config is None:
config = ConfigParser.ConfigParser()
try:
config.read(pathes)
except ConfigParser.MissingSectionHeaderError:
traceback.print_exc()
return config
def fillPromiseDictFromFolder(promise_dict, folder):
for filename in os.listdir(folder):
path = os.path.join(folder, filename)
if os.path.isfile(path) and os.access(path, os.X_OK):
promise_dict[filename] = {"path": path, "configuration": ConfigParser.ConfigParser()}
def softConfigGet(config, *args, **kwargs):
try:
return config.get(*args, **kwargs)
except (ConfigParser.NoOptionError, ConfigParser.NoSectionError):
return None
def createSymlinksFromConfig(destination_folder_config_tuple, source_list_config_tuple, service_name=""):
destination_folder = softConfigGet(*destination_folder_config_tuple)
if destination_folder:
source_path_str = softConfigGet(*source_list_config_tuple)
if source_path_str:
for path in source_path_str.split():
dirname = os.path.join(destination_folder, service_name)
try:
mkdirAll(dirname) # could also raise OSError
os.symlink(path, os.path.join(dirname, os.path.basename(path)))
except OSError, e:
if e.errno != os.errno.EEXIST:
raise
def mkdirAll(path):
try:
os.makedirs(path)
except OSError, e:
if e.errno == os.errno.EEXIST and os.path.isdir(path):
pass
else: raise
if __name__ == "__main__":
sys.exit(main())
#!{{ python_executable }}
# -*- coding: utf-8 -*-
import sys
import os
import subprocess
import json
from cStringIO import StringIO
def main():
if len(sys.argv) < 4:
print("Usage: %s <pid_path> <output_path> <command...>" % sys.argv[0])
return 2
pid_path=sys.argv[1]
output_path=sys.argv[2]
if os.path.exists(pid_path):
with open(pid_path, "r") as pidfile:
try:
pid = int(pidfile.read(6))
except ValueError:
pid = None
if pid and os.path.exists("/proc/" + str(pid)):
print("A process is already running with pid " + str(pid))
return 1
with open(pid_path, "w") as pidfile:
process = executeCommand(sys.argv[3:])
pidfile.write(str(process.pid))
status_json = generateStatusJsonFromProcess(process)
with open(output_path, "w") as outputfile:
json.dump(status_json, outputfile)
os.remove(pid_path)
def generateStatusJsonFromProcess(process):
stdout, stderr = process.communicate()
try:
status_json = json.loads(stdout)
except ValueError:
status_json = {}
if process.returncode != 0:
status_json["status"] = "error"
elif not status_json.get("status"):
status_json["status"] = "OK"
if stderr:
status_json["error"] = stderr
return status_json
def executeCommand(args):
return subprocess.Popen(
args,
#cwd=instance_path,
#env=None if sys.platform == 'cygwin' else {},
stdin=None,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
if __name__ == "__main__":
sys.exit(main())
import sys
import os
import json
import datetime
import base64
import hashlib
def main():
_, title, link, public_folder, previous_status_path, output_path = sys.argv
final_status = "OK";
# getting status
for filename in os.listdir(public_folder):
if filename.endswith(".status.json"):
filepath = os.path.join(public_folder, filename)
status = None
try:
status = json.load(open(filepath, "r"))
except ValueError:
continue
try:
if status["status"] != "OK":
final_status = "BAD"
break
except KeyError:
final_status = "BAD"
break
# checking previous status
try:
status = open(previous_status_path, "r").readline(4)
if status == final_status:
return 0
except IOError:
pass
# update status
open(previous_status_path, "w").write(final_status)
# generating RSS
utcnow = datetime.datetime.utcnow()
open(output_path, "w").write(
newRssString(
title,
title,
link,
utcnow,
utcnow,
"60",
[
newRssItemString(
"Status is %s" % final_status,
"Status is %s" % final_status,
link,
newGuid("%s, %s" % (utcnow, final_status)),
utcnow,
)
],
)
)
def escapeHtml(string):
return string.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;").replace("\"", "&quot;")
def newGuid(string):
sha256 = hashlib.sha256()
sha256.update(string)
return sha256.hexdigest()
def newRssItemString(title, description, link, guid, pub_date, guid_is_perma_link=True):
return """<item>
<title>%(title)s</title>
<description>%(description)s</description>
<link>%(link)s</link>
<guid isPermaLink="%(guid_is_perma_link)s">%(guid)s</guid>
<pubDate>%(pub_date)s</pubDate>
</item>""" % {
"title": escapeHtml(title),
"description": escapeHtml(description),
"link": escapeHtml(link),
"guid": escapeHtml(guid),
"pub_date": escapeHtml(pub_date.strftime("%a, %d %b %Y %H:%M:%S +0000")),
"guid_is_perma_link": escapeHtml(repr(guid_is_perma_link).lower()),
}
def newRssString(title, description, link, last_build_date, pub_date, ttl, rss_item_string_list):
return """<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title>%(title)s</title>
<description>%(description)s</description>
<link>%(link)s</link>
<lastBuildDate>%(last_build_date)s</lastBuildDate>
<pubDate>%(pub_date)s</pubDate>
<ttl>%(ttl)s</ttl>
%(items)s
</channel>
</rss>
""" % {
"title": escapeHtml(title),
"description": escapeHtml(description),
"link": escapeHtml(link),
"last_build_date": escapeHtml(last_build_date.strftime("%a, %d %b %Y %H:%M:%S +0000")),
"pub_date": escapeHtml(pub_date.strftime("%a, %d %b %Y %H:%M:%S +0000")),
"ttl": escapeHtml(str(ttl)),
"items": "\n\n".join([" " + item.replace("\n", "\n ") for item in rss_item_string_list]),
}
if __name__ == "__main__":
exit(main())
#!{{ extra_eggs_interpreter }}
import cgi
import cgitb
import Cookie
import base64
import hashlib
import hmac
import jinja2
import os
import subprocess
import urllib
cgitb.enable(display=0, logdir="/tmp/cgi.log")
form = cgi.FieldStorage()
cookie = Cookie.SimpleCookie()
cgi_path = "{{ cgi_directory }}"
monitor_password_path = "{{ monitor_password_path }}"
monitor_password_script_path = "{{ monitor_password_script_path }}"
monitor_apache_password_command = "{{ apache_update_command }}"
monitor_rewrite = "{{ ' '.join(rewrite_element.keys()) }}"
########
# Password functions
#######
def crypt(word, salt="$$"):
salt = salt.split("$")
algo = salt[0] or 'sha1'
if algo in hashlib.algorithms:
H = getattr(hashlib, algo)
elif algo == "plain":
return "%s$%s" % (algo, word)
else:
raise ValueError
rounds = min(max(0, int(salt[1])), 30) if salt[1] else 9
salt = salt[2] or base64.b64encode(os.urandom(12), "./")
h = hmac.new(salt, word, H).digest()
for x in xrange(1, 1 << rounds):
h = H(h).digest()
return "%s$%s$%s$%s" % (algo, rounds, salt,
base64.b64encode(h, "./").rstrip("="))
def is_password_set():
if not os.path.exists(monitor_password_path):
return False
hashed_password = open(monitor_password_path, 'r').read()
try:
void, algo, salt, hsh = hashed_password.split('$')
except ValueError:
return False
return True
def set_password(raw_password):
hashed_password = crypt(raw_password)
subprocess.check_call(monitor_apache_password_command + " %s" % raw_password,
shell=True)
open(monitor_password_path, 'w').write(hashed_password)
def check_password(raw_password):
"""
Returns a boolean of whether the raw_password was correct. Handles
encryption formats behind the scenes.
"""
if not os.path.exists(monitor_password_path) or not raw_password:
return False
hashed_password = open(monitor_password_path, 'r').read()
return hashed_password == crypt(raw_password, hashed_password)
### End of password functions
def forward_form():
command = os.path.join(cgi_path, form['posting-script'].value)
params_dict = {}
for f in form:
params_dict[f] = form[f].value
del params_dict['posting-script']
os.environ['QUERY_STRING'] = urllib.urlencode(params_dict)
try:
if os.access(command, os.X_OK):
print '\n', subprocess.check_output([command])
except subprocess.CalledProcessError:
print "There is a problem with sub-process"
pass
def return_document(command=None):
if not command:
script = form['script'].value
command = os.path.join(cgi_path, script)
#XXX this functions should be called only for display,
#so a priori it doesn't need form data
os.environ['QUERY_STRING'] = ''
try:
if os.access(command, os.X_OK):
print '\n', subprocess.check_output([command])
elif os.access(command, os.R_OK):
print open(command).read()
else:
raise OSError
except (subprocess.CalledProcessError, OSError) as e:
print "<p>Error :</p><pre>%s</pre>" % e
def make_menu():
# Transform deep-2 tree in json
folder_list = {}
for folder in os.listdir(cgi_path):
if os.path.isdir(os.path.join(cgi_path, folder)):
folder_list[folder] = []
for folder in folder_list:
for file in os.listdir(os.path.join(cgi_path, folder)):
if os.path.isfile(os.path.join(cgi_path, folder, file)):
folder_list[folder].append(file)
return folder_list
def get_cookie_password():
cookie_string = os.environ.get('HTTP_COOKIE')
if cookie_string:
cookie.load(cookie_string)
try:
return cookie['password'].value
except KeyError:
pass
return None
def set_cookie_password(password):
cookie['password'] = password
print cookie, "; Path=/; HttpOnly"
# Beginning of response
print "Content-Type: text/html"
password = None
# Check if user is logged
if "password_2" in form and "password" in form:
password_2 = form['password_2'].value
password_1 = form['password'].value
password = get_cookie_password()
if not is_password_set() or check_password(password):
if password_2 == password_1:
password = password_1
set_password(password)
set_cookie_password(password)
elif "password" in form:
password = form['password'].value
if is_password_set() and check_password(password):
set_cookie_password(password)
else:
password = get_cookie_password()
print '\n'
if not is_password_set():
return_document(monitor_password_script_path)
elif not check_password(password):
print "<html><head>"
print """
<link rel="stylesheet" href="static/pure-min.css">
<link rel="stylesheet" href="static/style.css">"""
print "</head><body>"
if password is None:
print "<h1>This is the monitoring interface</h1>"
else:
print "<h1>Error</h1><p>Wrong password</p>"
print """
<p>Please enter the monitor_password in the next field to access the data</p>
<form action="/index.cgi" method="post" class="pure-form-aligned">
Password : <input type="password" name="password">
<button type="submit" class="pure-button pure-button-primary">Access</button>
</form>
</body></html>"""
# redirection to the required script/page
else:
print
if "posting-script" in form:
forward_form()
elif "script" in form:
return_document()
else:
html_base = jinja2.Template(open('{{ index_template }}').read())
print
print html_base.render(tree=make_menu(), default_page="{{ default_page }}", monitor_rewrite=monitor_rewrite)
<html>
<head>
<title>Monitoring Interface</title>
<link rel="stylesheet" href="static/pure-min.css">
<link rel="stylesheet" href="static/style.css">
<script src="static/jquery-1.10.2.min.js"></script>
<script src="static/script.js"></script>
</head>
<body>
<div id="div-menu">
<h1>Monitoring</h1>
<div id="script-categories" class="pure-menu pure-menu-open">
<ul>
{% for category in tree %}
<li class="pure-menu-heading category">{{ category }}</li>
{% for script in tree[category] %}
<li><a href="{{ category }}/{{ script }}" class="script">{{ script }}</a></li>
{% endfor %}
{% endfor %}
<li class="pure-menu-heading category">Files</li>
<li><a href="./private/" class="link"> User: admin</br> Password is yours</a></li>
<li class="pure-menu-heading category">Local Service</li>
{% set rewrite_list = monitor_rewrite.split() %}
{% for path in rewrite_list %}
<li><a href="./rewrite/{{path}}/" class="link">{{path}}</a></li>
{% endfor %}
</ul>
</div>
</div>
<div id="content">
<iframe src="{{ default_page }}">
</iframe>
</div>
</body>
</html>
#!{{ python_executable }}
import cgitb
cgitb.enable()
print "<html><head>"
print """
<script type="text/javascript" src="static/jquery-1.10.2.min.js"></script>
<link rel="stylesheet" href="static/pure-min.css">
<link rel="stylesheet" href="static/style.css">"""
print "</head><body>"
print "<h1>This is the monitoring interface</h1>"
print "<h2>Please set your password for later access</h2>"
print """
<form action="/index.cgi" method="post" class="pure-form-aligned">
<div class="pure-control-group">
<label for="password">Password*:</label>
<input placeholder="Set your password" type="password" name="password" id="password"></br>
</div><div class="pure-control-group">
<label for="password">Verify Password*:</label>
<input placeholder="Verify password" type="password" name="password_2" id="password_2"></br>
</div><p id="validate-status" style="color:red"></p>
<div class="pure-controls">
<button id="register-button" type="submit" class="pure-button pure-button-primary" disabled>Access</button></div>
</form>
<script type="text/javascript" src="static/monitor-register.js"></script>
</body></html>
"""
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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