Commit 20bf35fc authored by Alain Takoudjou's avatar Alain Takoudjou

Update Release Candidate

parents b04d30a2 425ae92c
Changes Changes
======= =======
1.0.75 (2018-09-04)
-------------------
* erp5_test: stop using erp5_test recipe
* random: fix password generation with newlines
* erp5testnode: enable password authentication for scalability test system
* pbs: Ignore numerical IDs (UID/GID) when push
* request: add requestoptional.serialised
1.0.65 (2018-06-22) 1.0.65 (2018-06-22)
------------------- -------------------
......
[buildout] [buildout]
extends = extends =
../gcc/buildout.cfg
../numpy/openblas.cfg ../numpy/openblas.cfg
../cython/buildout.cfg ../cython/buildout.cfg
../scipy/buildout.cfg ../scipy/buildout.cfg
...@@ -41,6 +42,6 @@ setup-eggs = ...@@ -41,6 +42,6 @@ setup-eggs =
${numpy:egg} ${numpy:egg}
${scipy:egg} ${scipy:egg}
rpath = rpath =
${gcc-fortran:location}/lib ${gcc:location}/lib
${gcc-fortran:location}/lib64 ${gcc:location}/lib64
${openblas:location}/lib ${openblas:location}/lib
...@@ -9,5 +9,5 @@ depends_gitfetch = ...@@ -9,5 +9,5 @@ depends_gitfetch =
[go_github.com_mholt_caddy] [go_github.com_mholt_caddy]
<= go-git-package <= go-git-package
go.importpath = github.com/mholt/caddy go.importpath = github.com/mholt/caddy
repository = https://github.com/mholt/caddy repository = https://lab.nexedi.com/nexedi/caddy.git
revision = v0.11.0-11-ge263566673 revision = nxd-v0.11.0-3-g12438f6cff8c15f307631151eb064cec579b7605
[buildout] [buildout]
extends = extends =
../alsa/buildout.cfg ../alsa/buildout.cfg
../dash/buildout.cfg
../dbus/buildout.cfg ../dbus/buildout.cfg
../fontconfig/buildout.cfg ../fontconfig/buildout.cfg
../gtk-2/buildout.cfg ../gtk-2/buildout.cfg
...@@ -15,152 +14,172 @@ extends = ...@@ -15,152 +14,172 @@ extends =
../xz-utils/buildout.cfg ../xz-utils/buildout.cfg
parts = parts =
firefox firefox-wrapper
geckodriver
# XXX : Firefox binary tries to find libgnomeui-2.so.0 and it will # XXX : Firefox binary tries to find libgnomeui-2.so.0 and it will
# fail to run if exists. # fail to run if exists.
[firefox]
<= firefox-51
[firefox-51] [firefox-wrapper]
# Install a firefox wrapper names ${:wrapper-name} in buildout's bin-directory,
# wrapping firefox installed in ${:part}
# This [firefox-wrapper] installs the default firefox with name `firefox` and
# can also be used as a macro to install under a different name.
wrapper-name = firefox
part = ${firefox:location}
recipe = slapos.recipe.build recipe = slapos.recipe.build
slapos_promise = location = ${buildout:bin-directory}/${:wrapper-name}
file:firefox part = ${firefox:location}
file:firefox-bin script =
firefox = self.options['part']
part = self.buildout[os.path.basename(firefox)]
with open(%(location)r, 'w') as f:
f.write("""#!/bin/sh -e
cd {}
export LD_LIBRARY_PATH=$PWD:{}
export PATH={}:$PATH
exec ./firefox "$@"
""".format(
firefox,
':'.join(part['library'].split()),
':'.join(part['path'].split()),
))
os.fchmod(f.fileno(), 0o755)
depends = [firefox-wrapper-52]
${liberation-fonts:location} <= firefox-wrapper
${ipaex-fonts:location} wrapper-name = firefox-52
part = ${firefox-52:location}
[firefox-wrapper-51]
<= firefox-wrapper
wrapper-name = firefox-51
part = ${firefox-51:location}
[firefox]
# The default installed firefox version when installing firefox-wrapper.
# Note that users must install ${firefox-wrapper:} to have a usable firefox
# installed in ${buildout:bin-directory}.
# Installing ${firefox:} is not enough, because wrapper setting $LD_LIBRARY_PATH
# would not be created.
<= firefox-52
[firefox-52]
<= firefox-download
version = 52.9.0esr
i686-md5sum = 9aa18888b7812670208490609d75c9bc
x86_64-md5sum = 9336d70f45070c743d08e5473b783a7a
[firefox-51]
<= firefox-download
version = 51.0.1 version = 51.0.1
i686-md5sum = 9a5b67e9d759a1e4df004294a24b2b43
x86_64-md5sum = bd93f2652d1d90d59ae462439a93c85f
x86 = http://download-installer.cdn.mozilla.net/pub/firefox/releases/${:version}/linux-i686/en-US/firefox-${:version}.tar.bz2 9a5b67e9d759a1e4df004294a24b2b43
x86-64 = http://download-installer.cdn.mozilla.net/pub/firefox/releases/${:version}/linux-x86_64/en-US/firefox-${:version}.tar.bz2 bd93f2652d1d90d59ae462439a93c85f
geckodriver_x86 = https://github.com/mozilla/geckodriver/releases/download/v0.14.0/geckodriver-v0.14.0-linux32.tar.gz b5836f5a944fe9f3ed1a67c7b342c6a7
geckodriver_x86-64 = https://github.com/mozilla/geckodriver/releases/download/v0.14.0/geckodriver-v0.14.0-linux64.tar.gz 4a185d3179862a35104603b9274452e7
script = [firefox-download]
if not self.options.get('url'): self.options['url'], self.options['md5sum'] = self.options[guessPlatform()].split(' ')
extract_dir = self.extract(self.download(self.options['url'], self.options.get('md5sum')))
workdir = guessworkdir(extract_dir)
self.copyTree(workdir, "%(location)s")
geckodriver_url, geckodriver_md5sum = self.options['geckodriver_' + guessPlatform()].split(' ')
extract_dir = self.extract(self.download(geckodriver_url, geckodriver_md5sum))
shutil.copy(extract_dir + '/geckodriver', "%(location)s")
wrapper_location = os.path.join("%(location)s", "firefox-slapos")
wrapper = open(wrapper_location, 'w')
wrapper.write("""#!${dash:location}/bin/dash
cd %(location)s
export LD_LIBRARY_PATH="%(location)s"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${alsa:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${atk:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${at-spi2-atk:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${at-spi2-core:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${bzip2:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${cairo:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${dbus:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${dbus-glib:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${fontconfig:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${freetype:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${gdk-pixbuf:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${gettext:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${glib:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${gtk-3:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${harfbuzz:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${libepoxy:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${libffi:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${libICE:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${libpng:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${libSM:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${libtool:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${libuuid:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${libX11:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${libXau:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${libxcb:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${libXcomposite:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${libXcursor:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${libXext:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${libXi:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${libxml2:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${libXrender:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${libXt:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${mesa:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${pango:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${pcre:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${pixman:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${xdamage:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${xfixes:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${xz-utils:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${zlib:location}/lib"
export PATH=${fontconfig:location}/bin:$PATH
exec %(location)s/firefox "$@" 2> /dev/null
""")
wrapper.close()
os.chmod(wrapper_location, 0755)
[firefox-45]
recipe = slapos.recipe.build recipe = slapos.recipe.build
slapos_promise = slapos_promise =
file:firefox file:firefox
file:firefox-bin
depends = x86 = https://download-installer.cdn.mozilla.net/pub/firefox/releases/${:version}/linux-i686/en-US/firefox-${:version}.tar.bz2 ${:i686-md5sum}
x86-64 = https://download-installer.cdn.mozilla.net/pub/firefox/releases/${:version}/linux-x86_64/en-US/firefox-${:version}.tar.bz2 ${:x86_64-md5sum}
fonts =
${liberation-fonts:location} ${liberation-fonts:location}
${ipaex-fonts:location} ${ipaex-fonts:location}
library =
${alsa:location}/lib
${atk:location}/lib
${at-spi2-atk:location}/lib
${at-spi2-core:location}/lib
${bzip2:location}/lib
${cairo:location}/lib
${dbus:location}/lib
${dbus-glib:location}/lib
${fontconfig:location}/lib
${freetype:location}/lib
${gdk-pixbuf:location}/lib
${gettext:location}/lib
${glib:location}/lib
${gtk-3:location}/lib
${harfbuzz:location}/lib
${libepoxy:location}/lib
${libffi:location}/lib
${libICE:location}/lib
${libpng:location}/lib
${libSM:location}/lib
${libtool:location}/lib
${libuuid:location}/lib
${libX11:location}/lib
${libXau:location}/lib
${libxcb:location}/lib
${libXcomposite:location}/lib
${libXcursor:location}/lib
${libXext:location}/lib
${libXi:location}/lib
${libxml2:location}/lib
${libXrender:location}/lib
${libXt:location}/lib
${mesa:location}/lib
${pango:location}/lib
${pcre:location}/lib
${pixman:location}/lib
${xdamage:location}/lib
${xfixes:location}/lib
${xz-utils:location}/lib
${zlib:location}/lib
path =
${fontconfig:location}/bin
script =
url, md5sum = self.options[guessPlatform()].split()
extract_dir = self.extract(self.download(url, md5sum))
self.copyTree(guessworkdir(extract_dir), %(location)r)
[geckodriver]
# Current geckodriver installed as buildout:bin-directory/geckodriver
<= geckodriver-0.17.0
[geckodriver-0.17.0]
<= geckodriver-base
version = 0.17.0
i686-md5sum = 79b1a158f96d29942a111c0905f1c807
x86_64-md5sum = be18faeea6e7db9db6990d8667e2298f
version = 45.0.1
# MD5SUMs are available at : [geckodriver-0.14.0]
# https://ftp.mozilla.org/pub/mozilla.org/firefox/releases/${:version}/MD5SUMS <= geckodriver-base
x86 = http://download-installer.cdn.mozilla.net/pub/firefox/releases/${:version}/linux-i686/en-US/firefox-${:version}.tar.bz2 3756c8d06d6f915a3dff1dae643ee74b version = 0.14.0
x86-64 = http://download-installer.cdn.mozilla.net/pub/firefox/releases/${:version}/linux-x86_64/en-US/firefox-${:version}.tar.bz2 0409177ef649ec90ffe7a421a19bc156 i686-md5sum = b5836f5a944fe9f3ed1a67c7b342c6a7
x86_64-md5sum = 4a185d3179862a35104603b9274452e7
[geckodriver-base]
# Installs geckodriver ${version}
recipe = slapos.recipe.build
location = ${buildout:bin-directory}/${:_buildout_section_name_}
x86 = https://github.com/mozilla/geckodriver/releases/download/v${:version}/geckodriver-v${:version}-linux32.tar.gz ${:i686-md5sum}
x86-64 = https://github.com/mozilla/geckodriver/releases/download/v${:version}/geckodriver-v${:version}-linux64.tar.gz ${:x86_64-md5sum}
script = script =
if not self.options.get('url'): self.options['url'], self.options['md5sum'] = self.options[guessPlatform()].split(' ') url, md5sum = self.options[guessPlatform()].split()
extract_dir = self.extract(self.download(self.options['url'], self.options.get('md5sum'))) extract_dir = self.extract(self.download(url, md5sum))
workdir = guessworkdir(extract_dir) shutil.copy(extract_dir + '/geckodriver', %(location)r)
self.copyTree(workdir, "%(location)s")
wrapper_location = os.path.join("%(location)s", "firefox-slapos")
wrapper = open(wrapper_location, 'w') ### BBB
wrapper.write("""#!${dash:location}/bin/dash # testnodes are still using erp5-util.0.4.50 and are not looking for firefox in path
cd %(location)s # To be removed once testnode are updated to
export LD_LIBRARY_PATH="%(location)s" # https://lab.node.vifib.com/nexedi/slapos/raw/1.0.73/software/erp5testnode/software.cfg
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${alsa:location}/lib" # or later
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${atk:location}/lib" [firefox-wrapper]
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${bzip2:location}/lib" location = ${firefox:location}/firefox-slapos
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${cairo:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${dbus:location}/lib" [geckodriver]
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${dbus-glib:location}/lib" location = ${firefox:location}/geckodriver
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${fontconfig:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${freetype:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${gdk-pixbuf:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${gettext:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${glib:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${gtk-2:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${harfbuzz:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${libICE:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${libSM:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${libX11:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${libXau:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${libXcomposite:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${libXcursor:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${libXext:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${libXrender:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${libXt:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${libffi:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${libpng:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${libtool:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${libuuid:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${libxcb:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${libxml2:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${p11-kit:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${pango:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${pixman:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${xdamage:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${xfixes:location}/lib"
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${zlib:location}/lib"
export PATH=${fontconfig:location}/bin:$PATH
exec %(location)s/firefox $*""")
wrapper.close()
os.chmod(wrapper_location, 0755)
...@@ -25,7 +25,7 @@ find-links = http://pkgs.fedoraproject.org/repo/pkgs/rdiff-backup/rdiff-backup-1 ...@@ -25,7 +25,7 @@ find-links = http://pkgs.fedoraproject.org/repo/pkgs/rdiff-backup/rdiff-backup-1
[rdiff-backup-build-1.3.4] [rdiff-backup-build-1.3.4]
<= rdiff-backup-build <= rdiff-backup-build
# use our own version # use our own version
find-links = http://www.nexedi.org/static/packages/source/rdiff-backup-1.3.4nxd2.tar.gz find-links = http://www.nexedi.org/static/packages/source/rdiff-backup-1.3.4nxd5.tar.gz
patches = patches =
${:_profile_base_location_}/rdiff-backup-1.3.4-librsync-1.0.0.patch#31fafc8bc4a00f002f52008a9f3b671f ${:_profile_base_location_}/rdiff-backup-1.3.4-librsync-1.0.0.patch#31fafc8bc4a00f002f52008a9f3b671f
......
[buildout] [buildout]
extends = extends =
../gcc/buildout.cfg
../numpy/openblas.cfg ../numpy/openblas.cfg
../cython/buildout.cfg ../cython/buildout.cfg
../scipy/buildout.cfg ../scipy/buildout.cfg
...@@ -49,6 +50,6 @@ setup-eggs = ...@@ -49,6 +50,6 @@ setup-eggs =
${pillow-python:egg} ${pillow-python:egg}
networkx networkx
rpath = rpath =
${gcc-fortran:location}/lib ${gcc:location}/lib
${gcc-fortran:location}/lib64 ${gcc:location}/lib64
${openblas:location}/lib ${openblas:location}/lib
[buildout] [buildout]
extends = extends =
../gcc/buildout.cfg
../cython/buildout.cfg ../cython/buildout.cfg
../numpy/openblas.cfg ../numpy/openblas.cfg
../scipy/buildout.cfg ../scipy/buildout.cfg
...@@ -40,6 +41,6 @@ setup-eggs = ...@@ -40,6 +41,6 @@ setup-eggs =
${numpy:egg} ${numpy:egg}
${scipy:egg} ${scipy:egg}
rpath = rpath =
${gcc-fortran:location}/lib ${gcc:location}/lib
${gcc-fortran:location}/lib64 ${gcc:location}/lib64
${openblas:location}/lib ${openblas:location}/lib
#!/usr/bin/env python
r"""Command-line tool to format software release JSON for slapos.
Inspired by json.tool from python
Usage::
format-json infile outfile
"""
import os
import sys
import json
import collections
def main():
if len(sys.argv) != 3:
raise SystemExit(sys.argv[0] + " infile outfile")
with open(sys.argv[1], 'rb') as infile:
try:
obj = json.load(infile, object_pairs_hook=collections.OrderedDict)
except ValueError, e:
raise SystemExit(e)
with open(sys.argv[2], 'wb') as outfile:
json.dump(obj, outfile, sort_keys=False, indent=2, separators=(',', ': '))
outfile.write('\n')
if __name__ == '__main__':
main()
...@@ -18,7 +18,10 @@ ...@@ -18,7 +18,10 @@
}, },
"serialisation": { "serialisation": {
"description": "How the parameters and results are serialised", "description": "How the parameters and results are serialised",
"enum": ["xml", "json-in-xml"], "enum": [
"xml",
"json-in-xml"
],
"type": "string" "type": "string"
}, },
"software-type": { "software-type": {
...@@ -44,7 +47,10 @@ ...@@ -44,7 +47,10 @@
}, },
"serialisation": { "serialisation": {
"description": "How the parameters and results are serialised, if different from global setting, required if global setting is not provided", "description": "How the parameters and results are serialised, if different from global setting, required if global setting is not provided",
"enum": ["xml", "json-in-xml"], "enum": [
"xml",
"json-in-xml"
],
"type": "string" "type": "string"
}, },
"request": { "request": {
...@@ -55,11 +61,11 @@ ...@@ -55,11 +61,11 @@
"description": "URL, relative to Software Release base path, of a json schema for values published by instance of current software type", "description": "URL, relative to Software Release base path, of a json schema for values published by instance of current software type",
"type": "string" "type": "string"
}, },
"software-type" : { "software-type": {
"description": "Value to be used as software type instead of the software type id (in order to use multiple diferent forms for the same software type).", "description": "Value to be used as software type instead of the software type id (in order to use multiple diferent forms for the same software type).",
"type": "string" "type": "string"
}, },
"shared" : { "shared": {
"description": "Define if the request will request a Slave or Software Instance.", "description": "Define if the request will request a Slave or Software Instance.",
"default": "false", "default": "false",
"type": "boolean" "type": "boolean"
...@@ -78,4 +84,3 @@ ...@@ -78,4 +84,3 @@
}, },
"type": "object" "type": "object"
} }
...@@ -28,7 +28,7 @@ from setuptools import setup, find_packages ...@@ -28,7 +28,7 @@ from setuptools import setup, find_packages
import glob import glob
import os import os
version = '1.0.66' version = '1.0.75'
name = 'slapos.cookbook' name = 'slapos.cookbook'
long_description = open("README.rst").read() + "\n" + \ long_description = open("README.rst").read() + "\n" + \
open("CHANGES.rst").read() + "\n" open("CHANGES.rst").read() + "\n"
...@@ -160,9 +160,11 @@ setup(name=name, ...@@ -160,9 +160,11 @@ setup(name=name,
'readline = slapos.recipe.readline:Recipe', 'readline = slapos.recipe.readline:Recipe',
'redis.server = slapos.recipe.redis:Recipe', 'redis.server = slapos.recipe.redis:Recipe',
'request = slapos.recipe.request:Recipe', 'request = slapos.recipe.request:Recipe',
'request.serialised = slapos.recipe.request:Serialised', 'request.serialised = slapos.recipe.request:RequestJSONEncoded',
'request.edge = slapos.recipe.request:RequestEdge', 'request.edge = slapos.recipe.request:RequestEdge',
'requestoptional = slapos.recipe.request:RequestOptional', 'requestoptional = slapos.recipe.request:RequestOptional',
'requestoptional.serialised = '
'slapos.recipe.request:RequestOptionalJSONEncoded',
're6stnet.registry = slapos.recipe.re6stnet:Recipe', 're6stnet.registry = slapos.recipe.re6stnet:Recipe',
'reverseproxy.nginx = slapos.recipe.reverse_proxy_nginx:Recipe', 'reverseproxy.nginx = slapos.recipe.reverse_proxy_nginx:Recipe',
'seleniumrunner = slapos.recipe.seleniumrunner:Recipe', 'seleniumrunner = slapos.recipe.seleniumrunner:Recipe',
...@@ -208,5 +210,6 @@ setup(name=name, ...@@ -208,5 +210,6 @@ setup(name=name,
tests_require=[ tests_require=[
'jsonschema', 'jsonschema',
'mock', 'mock',
'testfixtures',
], ],
) )
...@@ -12,4 +12,4 @@ ...@@ -12,4 +12,4 @@
"type": "string" "type": "string"
} }
} }
} }
\ No newline at end of file
...@@ -74,6 +74,7 @@ class Recipe(GenericSlapRecipe, Notify, Callback): ...@@ -74,6 +74,7 @@ class Recipe(GenericSlapRecipe, Notify, Callback):
$RDIFF_BACKUP \\ $RDIFF_BACKUP \\
--remote-schema %(remote_schema)s \\ --remote-schema %(remote_schema)s \\
--restore-as-of now \\ --restore-as-of now \\
--ignore-numerical-ids \\
--force \\ --force \\
%(local_dir)s \\ %(local_dir)s \\
%(remote_dir)s %(remote_dir)s
......
...@@ -264,7 +264,7 @@ class RequestOptional(Recipe): ...@@ -264,7 +264,7 @@ class RequestOptional(Recipe):
update = install update = install
class Serialised(Recipe): class JSONCodec(object):
def _filterForStorage(self, partition_parameter_kw): def _filterForStorage(self, partition_parameter_kw):
return wrap(partition_parameter_kw) return wrap(partition_parameter_kw)
...@@ -274,7 +274,17 @@ class Serialised(Recipe): ...@@ -274,7 +274,17 @@ class Serialised(Recipe):
except slapmodule.NotFoundError: except slapmodule.NotFoundError:
return {} return {}
class RequestJSONEncoded(JSONCodec, Recipe):
"""
Like Recipe, but serialised with JSONCodec.
"""
pass
class RequestOptionalJSONEncoded(JSONCodec, RequestOptional):
"""
Like RequestOptional, but serialised with JSONCodec.
"""
pass
CONNECTION_PARAMETER_STRING = 'connection-' CONNECTION_PARAMETER_STRING = 'connection-'
......
{ {
"id": "http://json-schema.org/draft-04/schema#", "id": "http://json-schema.org/draft-04/schema#",
"$schema": "http://json-schema.org/draft-04/schema#", "$schema": "http://json-schema.org/draft-04/schema#",
"description": "Core schema meta-schema", "description": "Core schema meta-schema",
"definitions": { "definitions": {
"schemaArray": { "schemaArray": {
"type": "array", "type": "array",
"minItems": 1, "minItems": 1,
"items": { "$ref": "#" } "items": {
"$ref": "#"
}
},
"positiveInteger": {
"type": "integer",
"minimum": 0
},
"positiveIntegerDefault0": {
"allOf": [
{
"$ref": "#/definitions/positiveInteger"
}, },
"positiveInteger": { {
"type": "integer", "default": 0
"minimum": 0 }
]
},
"simpleTypes": {
"enum": [
"array",
"boolean",
"integer",
"null",
"number",
"object",
"string"
]
},
"stringArray": {
"type": "array",
"items": {
"type": "string"
},
"minItems": 1,
"uniqueItems": true
}
},
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uri"
},
"$schema": {
"type": "string",
"format": "uri"
},
"title": {
"type": "string"
},
"description": {
"type": "string"
},
"default": {},
"multipleOf": {
"type": "number",
"minimum": 0,
"exclusiveMinimum": true
},
"maximum": {
"type": "number"
},
"exclusiveMaximum": {
"type": "boolean",
"default": false
},
"minimum": {
"type": "number"
},
"exclusiveMinimum": {
"type": "boolean",
"default": false
},
"maxLength": {
"$ref": "#/definitions/positiveInteger"
},
"minLength": {
"$ref": "#/definitions/positiveIntegerDefault0"
},
"pattern": {
"type": "string",
"format": "regex"
},
"additionalItems": {
"anyOf": [
{
"type": "boolean"
}, },
"positiveIntegerDefault0": { {
"allOf": [ { "$ref": "#/definitions/positiveInteger" }, { "default": 0 } ] "$ref": "#"
}
],
"default": {}
},
"items": {
"anyOf": [
{
"$ref": "#"
}, },
"simpleTypes": { {
"enum": [ "array", "boolean", "integer", "null", "number", "object", "string" ] "$ref": "#/definitions/schemaArray"
}
],
"default": {}
},
"maxItems": {
"$ref": "#/definitions/positiveInteger"
},
"minItems": {
"$ref": "#/definitions/positiveIntegerDefault0"
},
"uniqueItems": {
"type": "boolean",
"default": false
},
"maxProperties": {
"$ref": "#/definitions/positiveInteger"
},
"minProperties": {
"$ref": "#/definitions/positiveIntegerDefault0"
},
"required": {
"$ref": "#/definitions/stringArray"
},
"additionalProperties": {
"anyOf": [
{
"type": "boolean"
}, },
"stringArray": { {
"type": "array", "$ref": "#"
"items": { "type": "string" },
"minItems": 1,
"uniqueItems": true
} }
],
"default": {}
},
"definitions": {
"type": "object",
"additionalProperties": {
"$ref": "#"
},
"default": {}
}, },
"type": "object",
"properties": { "properties": {
"id": { "type": "object",
"type": "string", "additionalProperties": {
"format": "uri" "$ref": "#"
}, },
"$schema": { "default": {}
"type": "string", },
"format": "uri" "patternProperties": {
}, "type": "object",
"title": { "additionalProperties": {
"type": "string" "$ref": "#"
}, },
"description": { "default": {}
"type": "string"
},
"default": {},
"multipleOf": {
"type": "number",
"minimum": 0,
"exclusiveMinimum": true
},
"maximum": {
"type": "number"
},
"exclusiveMaximum": {
"type": "boolean",
"default": false
},
"minimum": {
"type": "number"
},
"exclusiveMinimum": {
"type": "boolean",
"default": false
},
"maxLength": { "$ref": "#/definitions/positiveInteger" },
"minLength": { "$ref": "#/definitions/positiveIntegerDefault0" },
"pattern": {
"type": "string",
"format": "regex"
},
"additionalItems": {
"anyOf": [
{ "type": "boolean" },
{ "$ref": "#" }
],
"default": {}
},
"items": {
"anyOf": [
{ "$ref": "#" },
{ "$ref": "#/definitions/schemaArray" }
],
"default": {}
},
"maxItems": { "$ref": "#/definitions/positiveInteger" },
"minItems": { "$ref": "#/definitions/positiveIntegerDefault0" },
"uniqueItems": {
"type": "boolean",
"default": false
},
"maxProperties": { "$ref": "#/definitions/positiveInteger" },
"minProperties": { "$ref": "#/definitions/positiveIntegerDefault0" },
"required": { "$ref": "#/definitions/stringArray" },
"additionalProperties": {
"anyOf": [
{ "type": "boolean" },
{ "$ref": "#" }
],
"default": {}
},
"definitions": {
"type": "object",
"additionalProperties": { "$ref": "#" },
"default": {}
},
"properties": {
"type": "object",
"additionalProperties": { "$ref": "#" },
"default": {}
},
"patternProperties": {
"type": "object",
"additionalProperties": { "$ref": "#" },
"default": {}
},
"dependencies": {
"type": "object",
"additionalProperties": {
"anyOf": [
{ "$ref": "#" },
{ "$ref": "#/definitions/stringArray" }
]
}
},
"enum": {
"type": "array",
"minItems": 1,
"uniqueItems": true
},
"type": {
"anyOf": [
{ "$ref": "#/definitions/simpleTypes" },
{
"type": "array",
"items": { "$ref": "#/definitions/simpleTypes" },
"minItems": 1,
"uniqueItems": true
}
]
},
"allOf": { "$ref": "#/definitions/schemaArray" },
"anyOf": { "$ref": "#/definitions/schemaArray" },
"oneOf": { "$ref": "#/definitions/schemaArray" },
"not": { "$ref": "#" }
}, },
"dependencies": { "dependencies": {
"exclusiveMaximum": [ "maximum" ], "type": "object",
"exclusiveMinimum": [ "minimum" ] "additionalProperties": {
"anyOf": [
{
"$ref": "#"
},
{
"$ref": "#/definitions/stringArray"
}
]
}
},
"enum": {
"type": "array",
"minItems": 1,
"uniqueItems": true
},
"type": {
"anyOf": [
{
"$ref": "#/definitions/simpleTypes"
},
{
"type": "array",
"items": {
"$ref": "#/definitions/simpleTypes"
},
"minItems": 1,
"uniqueItems": true
}
]
},
"allOf": {
"$ref": "#/definitions/schemaArray"
},
"anyOf": {
"$ref": "#/definitions/schemaArray"
},
"oneOf": {
"$ref": "#/definitions/schemaArray"
}, },
"default": {} "not": {
"$ref": "#"
}
},
"dependencies": {
"exclusiveMaximum": [
"maximum"
],
"exclusiveMinimum": [
"minimum"
]
},
"default": {}
} }
import mock
import unittest
from collections import defaultdict
from slapos.recipe import request
from testfixtures import LogCapture
class RecipeTestMixin(object):
def setUp(self):
self.buildout = {
"buildout": {
},
"slap-connection": {
}
}
slap_patch = mock.patch(
"slapos.recipe.request.slapmodule.slap", autospec=True)
slap = slap_patch.start()
self.addCleanup(slap_patch.stop)
slap_instance = mock.MagicMock()
self.request_instance = mock.MagicMock()
register_instance = mock.MagicMock()
requested_instance = mock.MagicMock()
self.request_instance.return_value = requested_instance
register_instance.request = self.request_instance
slap_instance.registerComputerPartition.return_value = register_instance
slap.return_value = slap_instance
self.instance_getConnectionParameter = \
requested_instance.getConnectionParameter
def test_no_return_in_options_logs(self):
options = defaultdict(str)
self.instance_getConnectionParameter.return_value = self.return_value_empty
with LogCapture() as log:
self.recipe(self.buildout, "request", options)
log.check(
('request', 'DEBUG',
'No parameter to return to main instance.Be careful about that...'),
)
self.request_instance.assert_called_with(
'', 'RootSoftwareInstance', '', filter_kw={},
partition_parameter_kw=self.called_partition_parameter_kw,
shared=False, state='started')
def test_return_in_options_logs(self):
options = defaultdict(str)
options['return'] = 'anything'
self.instance_getConnectionParameter.return_value = self.return_value_empty
with LogCapture() as log:
self.recipe(self.buildout, "request", options)
log.check()
self.request_instance.assert_called_with(
'', 'RootSoftwareInstance', '', filter_kw={},
partition_parameter_kw=self.called_partition_parameter_kw,
shared=False, state='started')
def test_return_not_ready(self):
options = defaultdict(str)
options['return'] = 'anything'
self.instance_getConnectionParameter.side_effect = \
request.slapmodule.NotFoundError()
recipe = self.recipe(self.buildout, "request", options)
if self.raises:
self.assertRaises(KeyError, recipe.install)
self.assertEqual(options['connection-anything'], '')
self.request_instance.assert_called_with(
'', 'RootSoftwareInstance', '', filter_kw={},
partition_parameter_kw=self.called_partition_parameter_kw,
shared=False, state='started')
def test_return_ready(self):
options = defaultdict(str)
options['return'] = 'anything'
self.instance_getConnectionParameter.return_value = self.return_value
recipe = self.recipe(self.buildout, "request", options)
result = recipe.install()
self.assertEqual([], result)
self.assertEqual(options['connection-anything'], 'done')
self.request_instance.assert_called_with(
'', 'RootSoftwareInstance', '', filter_kw={},
partition_parameter_kw=self.called_partition_parameter_kw,
shared=False, state='started')
class RecipeTest(RecipeTestMixin, unittest.TestCase):
recipe = request.Recipe
raises = True
return_value_empty = {}
return_value = 'done'
called_partition_parameter_kw = {}
class RequestOptionalTest(RecipeTestMixin, unittest.TestCase):
recipe = request.RequestOptional
raises = False
return_value = 'done'
return_value_empty = {}
called_partition_parameter_kw = {}
class RequestJSONEncodedTest(RecipeTestMixin, unittest.TestCase):
recipe = request.RequestJSONEncoded
return_value_empty = "{}"
return_value = '{"anything": "done"}'
raises = True
called_partition_parameter_kw = {'_': '{}'}
class RequestOptionalJSONEncodedTest(RecipeTestMixin, unittest.TestCase):
recipe = request.RequestOptionalJSONEncoded
return_value_empty = "{}"
return_value = '{"anything": "done"}'
raises = False
called_partition_parameter_kw = {'_': '{}'}
...@@ -14,7 +14,10 @@ ...@@ -14,7 +14,10 @@
"serialisation": { "serialisation": {
"description": "How the parameters and results are serialised", "description": "How the parameters and results are serialised",
"require": true, "require": true,
"enum": ["xml", "json-in-xml"], "enum": [
"xml",
"json-in-xml"
],
"type": "string" "type": "string"
}, },
"software-type": { "software-type": {
...@@ -35,7 +38,10 @@ ...@@ -35,7 +38,10 @@
}, },
"serialisation": { "serialisation": {
"description": "How the parameters and results are serialised, if different from global setting", "description": "How the parameters and results are serialised, if different from global setting",
"enum": ["xml", "json-in-xml"], "enum": [
"xml",
"json-in-xml"
],
"type": "string" "type": "string"
}, },
"request": { "request": {
...@@ -48,11 +54,11 @@ ...@@ -48,11 +54,11 @@
"description": "URL, relative to Software Release base path, of a json schema for values published by instance of current software type", "description": "URL, relative to Software Release base path, of a json schema for values published by instance of current software type",
"type": "string" "type": "string"
}, },
"software-type" : { "software-type": {
"description": "Value to be used as software type instead of the software type id (in order to use multiple diferent forms for the same software type).", "description": "Value to be used as software type instead of the software type id (in order to use multiple diferent forms for the same software type).",
"type": "string" "type": "string"
}, },
"shared" : { "shared": {
"description": "Define if the request will request a Slave or Software Instance.", "description": "Define if the request will request a Slave or Software Instance.",
"type": "boolean" "type": "boolean"
}, },
...@@ -69,4 +75,3 @@ ...@@ -69,4 +75,3 @@
}, },
"type": "object" "type": "object"
} }
...@@ -29,6 +29,7 @@ import unittest ...@@ -29,6 +29,7 @@ import unittest
import os import os
import glob import glob
import json import json
import collections
import slapos.test import slapos.test
import jsonschema import jsonschema
...@@ -41,20 +42,39 @@ def getSchemaValidator(filename): ...@@ -41,20 +42,39 @@ def getSchemaValidator(filename):
json_file.close() json_file.close()
return json_dict return json_dict
def createTest(path, json_dict): def createValidatorTest(path, json_dict):
# Test that json is valid
def run(self, *args, **kwargs): def run(self, *args, **kwargs):
with open(path, "r") as json_file: with open(path, "r") as json_file:
self.assertEquals(jsonschema.validate(json.loads(json_file.read()), json_dict), None) self.assertEqual(jsonschema.validate(json.load(json_file), json_dict), None)
json_file.close()
return run return run
def createFormatTest(path, json_dict):
# Test that json match our formatting rules
def run(self, *args, **kwargs):
with open(path, "r") as json_file:
content = json_file.read()
# this is the format produced by `format-json` tool at the
# root of this repository.
# XXX it would be better to reuse the code.
self.assertEqual(
(json.dumps(
json.loads(content, object_pairs_hook=collections.OrderedDict),
sort_keys=False,
indent=2,
separators=(',', ': ')) + "\n").splitlines(),
content.splitlines())
return run
def generateSoftwareCfgTest(): def generateSoftwareCfgTest():
json_dict = getSchemaValidator("schema.json") json_dict = getSchemaValidator("schema.json")
base_path = "/".join(slapos.test.__file__.split("/")[:-3]) base_path = "/".join(slapos.test.__file__.split("/")[:-3])
for path in glob.glob("%s/software/*/software.cfg.json" % base_path): for path in glob.glob("%s/software/*/software.cfg.json" % base_path):
test_name = "test_%s_software_cfg_json" % path.split("/")[-2] test_name = "test_%s_software_cfg_json" % path.split("/")[-2]
setattr(TestJSONSchemaValidation, test_name , createTest(path, json_dict)) setattr(TestJSONSchemaValidation, test_name, createValidatorTest(path, json_dict))
setattr(TestJSONSchemaValidation, test_name + '_format', createFormatTest(path, json_dict))
def generateJSONSchemaTest(): def generateJSONSchemaTest():
...@@ -64,7 +84,8 @@ def generateJSONSchemaTest(): ...@@ -64,7 +84,8 @@ def generateJSONSchemaTest():
software_type = path.split("/")[-2] software_type = path.split("/")[-2]
filename = path.split("/")[-1].replace("-", "_").replace(".", "_") filename = path.split("/")[-1].replace("-", "_").replace(".", "_")
test_name = "test_schema_%s_%s" % (software_type, filename) test_name = "test_schema_%s_%s" % (software_type, filename)
setattr(TestJSONSchemaValidation, test_name , createTest(path, json_dict)) setattr(TestJSONSchemaValidation, test_name, createValidatorTest(path, json_dict))
setattr(TestJSONSchemaValidation, test_name + '_format', createFormatTest(path, json_dict))
class TestJSONSchemaValidation(unittest.TestCase): class TestJSONSchemaValidation(unittest.TestCase):
pass pass
......
{ {
"type": "object", "type": "object",
"$schema": "http://json-schema.org/draft-04/schema", "$schema": "http://json-schema.org/draft-04/schema",
"title": "Input Parameters",
"title": "Input Parameters", "properties": {
"properties": { "public-ipv4": {
"public-ipv4": { "title": "Public IPv4",
"title": "Public IPv4", "description": "Public ipv4 of the frontend (the one Apache will be indirectly listening to).",
"description": "Public ipv4 of the frontend (the one Apache will be indirectly listening to).", "type": "string"
"type": "string" },
}, "ip-read-limit": {
"ip-read-limit": { "title": "IPReadLimit",
"title": "IPReadLimit", "description": "Value used to set IPReadLimit Parameter for antiloris.",
"description": "Value used to set IPReadLimit Parameter for antiloris.", "type": "integer",
"type": "integer", "default": 10
"default": 10 },
}, "mpm-server-limit": {
"mpm-server-limit": { "title": "ServerLimit",
"title": "ServerLimit", "description": "Value used to set ServerLimit on apache configuration.",
"description": "Value used to set ServerLimit on apache configuration.", "type": "integer",
"type": "integer", "default": 16
"default": 16 },
}, "mpm-max-clients": {
"mpm-max-clients": { "title": "MaxClients",
"title": "MaxClients", "description": "Value used to set MaxClients on apache configuration.",
"description": "Value used to set MaxClients on apache configuration.", "type": "integer",
"type": "integer", "default": 400
"default": 400 },
}, "mpm-start-servers": {
"mpm-start-servers": { "title": "StartServers",
"title": "StartServers", "description": "Value used to set StartServers on apache configuration.",
"description": "Value used to set StartServers on apache configuration.", "type": "integer",
"type": "integer", "default": 3
"default": 3 },
}, "mpm-thread-per-child": {
"mpm-thread-per-child": { "title": "ThreadsPerChild",
"title": "ThreadsPerChild", "description": "Value used to set ThreadsPerChild on apache configuration.",
"description": "Value used to set ThreadsPerChild on apache configuration.", "type": "integer",
"type": "integer", "default": 25
"default": 25 },
}, "mpm-graceful-shutdown-timeout": {
"mpm-graceful-shutdown-timeout": { "title": "ThreadsPerChild",
"title": "ThreadsPerChild", "description": "Value used to set ThreadsPerChild on apache configuration.",
"description": "Value used to set ThreadsPerChild on apache configuration.", "type": "integer",
"type": "integer", "default": 5
"default": 5 },
}, "enable-http2-by-default": {
"enable-http2-by-default": { "title": "Enable HTTP2 by Default",
"title": "Enable HTTP2 by Default", "description": "Use HTTP2 as default Protocol",
"description": "Use HTTP2 as default Protocol", "type": "string",
"type": "string", "default": "true",
"default": "true", "enum": [
"enum": ["true", "false"] "true",
}, "false"
"re6st-verification-url": { ]
"title": "Test Verification URL", },
"description": "Url to verify if the internet and/or re6stnet is working.", "re6st-verification-url": {
"type": "string" "title": "Test Verification URL",
}, "description": "Url to verify if the internet and/or re6stnet is working.",
"-frontend-authorized-slave-string": { "type": "string"
"title": "Authorized Slave String", },
"description": "List of SOFTINST-XXX of Slaves, separated by space which is allowed to use custom configuration.", "-frontend-authorized-slave-string": {
"type": "string" "title": "Authorized Slave String",
}, "description": "List of SOFTINST-XXX of Slaves, separated by space which is allowed to use custom configuration.",
"apache-key": { "type": "string"
"title": "Apache Key", },
"description": "Apache Key", "apache-key": {
"textarea": true, "title": "Apache Key",
"type": "string" "description": "Apache Key",
}, "textarea": true,
"apache-certificate": { "type": "string"
"title": "Apache Certificate", },
"description": "Apache Certificate", "apache-certificate": {
"textarea": true, "title": "Apache Certificate",
"type": "string" "description": "Apache Certificate",
}, "textarea": true,
"apache-ca-certificate": { "type": "string"
"title": "Apache CA Certificate", },
"description": "Apache CA Certificate", "apache-ca-certificate": {
"textarea": true, "title": "Apache CA Certificate",
"type": "string" "description": "Apache CA Certificate",
}, "textarea": true,
"domain": { "type": "string"
"title": "Domain", },
"description": "Base Domain for create subdomains (ie.: example.com).", "domain": {
"type": "string", "title": "Domain",
"pattern": "^([a-zA-Z0-9]([a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,6}$" "description": "Base Domain for create subdomains (ie.: example.com).",
}, "type": "string",
"nginx-domain": { "pattern": "^([a-zA-Z0-9]([a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,6}$"
"title": "Nginx Domain", },
"description": "Base Domain for create subdomains (ie.: example2.com) for websocket, notebook and eventsource.", "nginx-domain": {
"type": "string", "title": "Nginx Domain",
"pattern": "^([a-zA-Z0-9]([a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,6}$" "description": "Base Domain for create subdomains (ie.: example2.com) for websocket, notebook and eventsource.",
}, "type": "string",
"-frontend-quantity": { "pattern": "^([a-zA-Z0-9]([a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,6}$"
"title": "Frontend Replication Quantity", },
"description": "Quantity of Frontends Replicate.", "-frontend-quantity": {
"type": "integer" "title": "Frontend Replication Quantity",
} "description": "Quantity of Frontends Replicate.",
} "type": "integer"
}
}
} }
...@@ -6,31 +6,31 @@ ...@@ -6,31 +6,31 @@
"description": "Amount of Slaves allocated to the Instance which are deployed", "description": "Amount of Slaves allocated to the Instance which are deployed",
"type": "integer" "type": "integer"
}, },
"slave-amount": { "slave-amount": {
"description": "Total amount of Slaves allocated to the Instance (include blocked ones)", "description": "Total amount of Slaves allocated to the Instance (include blocked ones)",
"type": "integer" "type": "integer"
}, },
"reject-slave-amount": { "reject-slave-amount": {
"description": "Rejected Amount of Slaves allocated to the Instance which are not deployed", "description": "Rejected Amount of Slaves allocated to the Instance which are not deployed",
"type": "integer" "type": "integer"
}, },
"rejected-slave-list": { "rejected-slave-list": {
"description": "List of slave instances references which are rejected", "description": "List of slave instances references which are rejected",
"type": "array" "type": "array"
}, },
"domain": { "domain": {
"description": "Base domain used by the instance", "description": "Base domain used by the instance",
"type": "string" "type": "string"
}, },
"monitor-base-url": { "monitor-base-url": {
"description": "Base url for monitor", "description": "Base url for monitor",
"type": "string" "type": "string"
}, },
"monitor-url": { "monitor-url": {
"description": "Url of Monitor (opml)", "description": "Url of Monitor (opml)",
"type": "string" "type": "string"
}, },
"monitor-password": { "monitor-password": {
"description": "Password to access the monitor", "description": "Password to access the monitor",
"type": "string" "type": "string"
}, },
......
{ {
"type": "object", "type": "object",
"$schema": "http://json-schema.org/draft-04/schema", "$schema": "http://json-schema.org/draft-04/schema",
"title": "Input Parameters", "title": "Input Parameters",
"properties": { "properties": {
"url": { "url": {
...@@ -22,7 +21,6 @@ ...@@ -22,7 +21,6 @@
"type": "string", "type": "string",
"pattern": "^([a-zA-Z0-9]([a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,6}$" "pattern": "^([a-zA-Z0-9]([a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,6}$"
}, },
"server-alias": { "server-alias": {
"title": "Server Alias", "title": "Server Alias",
"description": "Server Alias List separated by space", "description": "Server Alias List separated by space",
...@@ -34,23 +32,26 @@ ...@@ -34,23 +32,26 @@
"description": "Type of slave. If redirect, the slave will redirect to the given url. If zope, the rewrite rules will be compatible with Virtual Host Monster", "description": "Type of slave. If redirect, the slave will redirect to the given url. If zope, the rewrite rules will be compatible with Virtual Host Monster",
"type": "string", "type": "string",
"default": "", "default": "",
"enum": ["", "zope", "redirect", "notebook", "eventsource"] "enum": [
"",
"zope",
"redirect",
"notebook",
"eventsource"
]
}, },
"path": { "path": {
"title": "Backend Path", "title": "Backend Path",
"description": "Path to proxy to in the backend", "description": "Path to proxy to in the backend",
"type": "string", "type": "string",
"default": "" "default": ""
}, },
"default-path": { "default-path": {
"title": "Default Path", "title": "Default Path",
"description": "Provide default path to redirect user to when user access / (the site root)", "description": "Provide default path to redirect user to when user access / (the site root)",
"type": "string", "type": "string",
"default": "" "default": ""
}, },
"ssl_crt": { "ssl_crt": {
"title": "SSL Certificate", "title": "SSL Certificate",
"description": "Content of the SSL Certificate file", "description": "Content of the SSL Certificate file",
...@@ -65,7 +66,6 @@ ...@@ -65,7 +66,6 @@
"textarea": true, "textarea": true,
"default": "" "default": ""
}, },
"ssl_ca_crt": { "ssl_ca_crt": {
"title": "SSL Certificate Authority's Certificate", "title": "SSL Certificate Authority's Certificate",
"description": "Content of the CA certificate file", "description": "Content of the CA certificate file",
...@@ -78,90 +78,101 @@ ...@@ -78,90 +78,101 @@
"description": "If set to true, http requests will be redirected to https", "description": "If set to true, http requests will be redirected to https",
"type": "string", "type": "string",
"default": "false", "default": "false",
"enum": ["false", "true"] "enum": [
"false",
"true"
]
}, },
"ssl-proxy-verify": { "ssl-proxy-verify": {
"title": "Verify Backend Certificates", "title": "Verify Backend Certificates",
"description": "If set to true, Backend SSL Certificates will be checked and frontend will refuse to proxy if certificate is invalid", "description": "If set to true, Backend SSL Certificates will be checked and frontend will refuse to proxy if certificate is invalid",
"type": "string", "type": "string",
"default": "false", "default": "false",
"enum": ["false", "true"] "enum": [
"false",
"true"
]
}, },
"ssl_proxy_ca_crt": { "ssl_proxy_ca_crt": {
"title": "SSL Backend Authority's Certificate", "title": "SSL Backend Authority's Certificate",
"description": "Content of the SSL Certificate Authority file of the backend (to be used with ssl-proxy-verify)", "description": "Content of the SSL Certificate Authority file of the backend (to be used with ssl-proxy-verify)",
"type": "string", "type": "string",
"default": "" "default": ""
}, },
"monitor-ipv6-test": { "monitor-ipv6-test": {
"title": "IPv6 Address to Monitor Packet Lost", "title": "IPv6 Address to Monitor Packet Lost",
"description": "IPv6 Address for the frontend keep monitoring with ping6 (without brackets)", "description": "IPv6 Address for the frontend keep monitoring with ping6 (without brackets)",
"type": "string", "type": "string",
"default": "" "default": ""
}, },
"monitor-ipv4-test": { "monitor-ipv4-test": {
"title": "IPv4 Address to Monitor Packet Lost", "title": "IPv4 Address to Monitor Packet Lost",
"description": "IPv4 Address for the frontend keep monitoring with ping", "description": "IPv4 Address for the frontend keep monitoring with ping",
"type": "string", "type": "string",
"default": "" "default": ""
}, },
"re6st-optimal-test": { "re6st-optimal-test": {
"title": "IPv6 and IPv4 Address to test Re6st", "title": "IPv6 and IPv4 Address to test Re6st",
"description": "IPv6 and IPv6 Address for the frontend test if re6st is on the optimal status (use ipv6,ipv4)", "description": "IPv6 and IPv6 Address for the frontend test if re6st is on the optimal status (use ipv6,ipv4)",
"type": "string", "type": "string",
"default": "" "default": ""
}, },
"enable_cache": { "enable_cache": {
"title": "Enable Cache", "title": "Enable Cache",
"description": "If set to true, http caching server (Apache Traffic Server) will be used between frontend apache and backend", "description": "If set to true, http caching server (Apache Traffic Server) will be used between frontend apache and backend",
"type": "string", "type": "string",
"default": "false", "default": "false",
"enum": ["false", "true"] "enum": [
"false",
"true"
]
}, },
"disable-no-cache-request": { "disable-no-cache-request": {
"title": "Disable 'no-cache' requests", "title": "Disable 'no-cache' requests",
"description": "If set to true, Cache-Control and Pragma requests headers will not be sent to cache and backend servers. This prevents clients from bypassing cache when enable_cache is true", "description": "If set to true, Cache-Control and Pragma requests headers will not be sent to cache and backend servers. This prevents clients from bypassing cache when enable_cache is true",
"type": "string", "type": "string",
"default": "false", "default": "false",
"enum": ["false", "true"] "enum": [
"false",
"true"
]
}, },
"disable-via-header": { "disable-via-header": {
"title": "Disable 'Via' headers from cache", "title": "Disable 'Via' headers from cache",
"description": "If set to true, Via response headers will not be sent to client", "description": "If set to true, Via response headers will not be sent to client",
"type": "string", "type": "string",
"default": "false", "default": "false",
"enum": ["false", "true"] "enum": [
"false",
"true"
]
}, },
"enable-http2": { "enable-http2": {
"title": "Enable HTTP2 Protocol", "title": "Enable HTTP2 Protocol",
"description": "Use HTTP2 Protocol for the site", "description": "Use HTTP2 Protocol for the site",
"type": "string", "type": "string",
"default": "true", "default": "true",
"enum": ["true", "false"] "enum": [
"true",
"false"
]
}, },
"prefer-gzip-encoding-to-backend": { "prefer-gzip-encoding-to-backend": {
"title": "Prefer gzip Encoding for Backend", "title": "Prefer gzip Encoding for Backend",
"description": "If set to true, frontend will rewrite Accept-Encoding request header to simply 'gzip' for all variants of Accept-Encoding containing 'gzip', in order to maximize cache hits for resources cached with Vary: Accept-Encoding when enable_cache is used", "description": "If set to true, frontend will rewrite Accept-Encoding request header to simply 'gzip' for all variants of Accept-Encoding containing 'gzip', in order to maximize cache hits for resources cached with Vary: Accept-Encoding when enable_cache is used",
"type": "string", "type": "string",
"default": "false", "default": "false",
"enum": ["false", "true"] "enum": [
"false",
"true"
]
}, },
"disabled-cookie-list": { "disabled-cookie-list": {
"title": "Disabled Cookies", "title": "Disabled Cookies",
"description": "List of Cookies separated by space that will not be sent to cache and backend servers. This is especially useful to discard analytics tracking cookies when using Vary: Cookie cache headers", "description": "List of Cookies separated by space that will not be sent to cache and backend servers. This is especially useful to discard analytics tracking cookies when using Vary: Cookie cache headers",
"type": "string", "type": "string",
"default": "" "default": ""
}, },
"apache_custom_http": { "apache_custom_http": {
"title": "HTTP configuration", "title": "HTTP configuration",
"description": "Raw http configuration in python template format. Your site will be rejected if you use it without notification and approval of frontend administrators", "description": "Raw http configuration in python template format. Your site will be rejected if you use it without notification and approval of frontend administrators",
......
...@@ -6,19 +6,19 @@ ...@@ -6,19 +6,19 @@
"description": "Number of nodes the slave is replicated", "description": "Number of nodes the slave is replicated",
"type": "integer" "type": "integer"
}, },
"domain": { "domain": {
"description": "Base domain used by the instance", "description": "Base domain used by the instance",
"type": "string" "type": "string"
}, },
"url": { "url": {
"description": "Default URL provided", "description": "Default URL provided",
"type": "string" "type": "string"
}, },
"site_url": { "site_url": {
"description": "URL for HTTP access", "description": "URL for HTTP access",
"type": "string" "type": "string"
}, },
"secure_access": { "secure_access": {
"description": "URL for HTTP access", "description": "URL for HTTP access",
"type": "string" "type": "string"
}, },
......
{ {
"name": "Apache Frontend", "name": "Apache Frontend",
"description": "Apache Frontend", "description": "Apache Frontend",
"serialisation": "xml", "serialisation": "xml",
"software-type": { "software-type": {
"custom-personal-slave": { "custom-personal-slave": {
"title": "Custom Personal (Slave)", "title": "Custom Personal (Slave)",
"description": "Custom Personal", "description": "Custom Personal",
"request": "instance-slave-apache-input-schema.json", "request": "instance-slave-apache-input-schema.json",
"response": "instance-output-schema.json", "response": "instance-output-schema.json",
"index": 1, "index": 1,
"software-type": "custom-personal", "software-type": "custom-personal",
"shared": true "shared": true
}, },
"custom-personal": { "custom-personal": {
"title": "Custom Personal", "title": "Custom Personal",
"description": "", "description": "",
"request": "instance-apache-input-schema.json", "request": "instance-apache-input-schema.json",
"response": "instance-output-schema.json", "response": "instance-output-schema.json",
"index": 2 "index": 2
}, },
"default": { "default": {
"title": "Default", "title": "Default",
"software-type": "default", "software-type": "default",
"description": "Default", "description": "Default",
"request": "instance-apache-input-schema.json", "request": "instance-apache-input-schema.json",
"response": "instance-output-schema.json", "response": "instance-output-schema.json",
"index": 3 "index": 3
}, },
"default-slave": { "default-slave": {
"title": "Default (slave)", "title": "Default (slave)",
"software-type": "default", "software-type": "default",
"description": "Default", "description": "Default",
"request": "instance-slave-apache-input-schema.json", "request": "instance-slave-apache-input-schema.json",
"response": "instance-output-schema.json", "response": "instance-output-schema.json",
"index": 4, "index": 4,
"shared": true "shared": true
} }
} }
} }
...@@ -121,9 +121,9 @@ eggs = ...@@ -121,9 +121,9 @@ eggs =
${rdiff-backup-build-1.3.4:egg} ${rdiff-backup-build-1.3.4:egg}
[versions] [versions]
# 1.3.4nxd2 is invalid version string, thus pached version string is not '1.3.4nxd2+SlapOSPatched001' # 1.3.4nxd5 is invalid version string, thus pached version string is not '1.3.4nxd5+SlapOSPatched001'
# but '1.3.4nxd2-SlapOSPatched001'. # but '1.3.4nxd5-SlapOSPatched001'.
rdiff-backup = 1.3.4nxd2-SlapOSPatched001 rdiff-backup = 1.3.4nxd5-SlapOSPatched001
gunicorn = 19.1.1 gunicorn = 19.1.1
plone.recipe.command = 1.1 plone.recipe.command = 1.1
slapos.recipe.template = 2.4.2 slapos.recipe.template = 2.4.2
......
...@@ -7,7 +7,11 @@ ...@@ -7,7 +7,11 @@
"publish": { "publish": {
"description": "Upload built packages automatically to a Debian repository when successful.", "description": "Upload built packages automatically to a Debian repository when successful.",
"type": "object", "type": "object",
"required": ["suite", "host", "key"], "required": [
"suite",
"host",
"key"
],
"properties": { "properties": {
"suite": { "suite": {
"type": "string" "type": "string"
......
...@@ -13,11 +13,6 @@ Generally things to be done with ``caddy-frontend``: ...@@ -13,11 +13,6 @@ Generally things to be done with ``caddy-frontend``:
* **Jérome Perrin**: *For event source, if I understand https://github.com/mholt/caddy/issues/1355 correctly, we could use caddy as a proxy in front of nginx-push-stream . If we have a "central shared" caddy instance, can it handle keeping connections opens for many clients ?* * **Jérome Perrin**: *For event source, if I understand https://github.com/mholt/caddy/issues/1355 correctly, we could use caddy as a proxy in front of nginx-push-stream . If we have a "central shared" caddy instance, can it handle keeping connections opens for many clients ?*
* ``ssl_ca_crt`` * ``ssl_ca_crt``
* ``disabled-cookie-list`` (requires writing middleware plugin for Caddy)::
RequestHeader edit Cookie "(^%(disabled_cookie)s=[^;]*; |; %(disabled_cookie)s=[^;]*|^%(disabled_cookie)s=[^;]*$)" ""' % dict(disabled_cookie=disabled_cookie) }}
* there is already `MR <https://github.com/mholt/caddy/pull/2144>`_ which will allow regexp modification of headers, thus cookies
* ``ssl_proxy_ca_crt`` for ``ssl_proxy_verify``, this is related to bug `#1550 <https://github.com/mholt/caddy/issues/1550>`_, proposed solution `just adding your CA to the system's trust store` * ``ssl_proxy_ca_crt`` for ``ssl_proxy_verify``, this is related to bug `#1550 <https://github.com/mholt/caddy/issues/1550>`_, proposed solution `just adding your CA to the system's trust store`
* ``check-error-on-caddy-log`` like ``check-error-on-apache-log`` * ``check-error-on-caddy-log`` like ``check-error-on-apache-log``
* cover test suite like resilient tests for KVM and prove it works the same way as Caddy * cover test suite like resilient tests for KVM and prove it works the same way as Caddy
......
...@@ -58,7 +58,7 @@ md5sum = f20d6c3d2d94fb685f8d26dfca1e822b ...@@ -58,7 +58,7 @@ md5sum = f20d6c3d2d94fb685f8d26dfca1e822b
[template-default-slave-virtualhost] [template-default-slave-virtualhost]
filename = templates/default-virtualhost.conf.in filename = templates/default-virtualhost.conf.in
md5sum = 8ed87061b9e20e2ad74aae9f80d1b53d md5sum = d9269cc085752e09f4acce37a18e160c
[template-cached-slave-virtualhost] [template-cached-slave-virtualhost]
filename = templates/cached-virtualhost.conf.in filename = templates/cached-virtualhost.conf.in
......
{ {
"$schema": "http://json-schema.org/draft-04/schema", "$schema": "http://json-schema.org/draft-04/schema",
"properties": { "properties": {
"-frontend-authorized-slave-string": { "-frontend-authorized-slave-string": {
"description": "List of SOFTINST-XXX of Slaves, separated by space which is allowed to use custom configuration.", "description": "List of SOFTINST-XXX of Slaves, separated by space which is allowed to use custom configuration.",
"title": "Authorized Slave String", "title": "Authorized Slave String",
"type": "string" "type": "string"
},
"-frontend-quantity": {
"description": "Quantity of Frontends Replicate.",
"title": "Frontend Replication Quantity",
"type": "integer"
},
"apache-ca-certificate": {
"description": "[NOT IMPLEMENTED] SSL CA Certificate used by the server.",
"textarea": true,
"title": "[NOT IMPLEMENTED] SSL CA Certificate",
"type": "string"
},
"apache-certificate": {
"description": "SSL Certificate used by the server.",
"textarea": true,
"title": "SSL Certificate",
"type": "string"
},
"apache-key": {
"description": "SSL Key used by the server.",
"textarea": true,
"title": "SSL Key",
"type": "string"
},
"domain": {
"description": "Base Domain for create subdomains (ie.: example.com).",
"pattern": "^([a-zA-Z0-9]([a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,6}$",
"title": "Domain",
"type": "string"
},
"enable-http2-by-default": {
"default": "true",
"description": "Use HTTP2 as default Protocol",
"enum": [
"true",
"false"
],
"title": "Enable HTTP2 by Default",
"type": "string"
},
"mpm-graceful-shutdown-timeout": {
"default": 5,
"description": "Value passed to -grace parameter of Caddy, see https://caddyserver.com/docs/cli .",
"title": "Duration of the graceful shutdown period",
"type": "integer"
},
"nginx-domain": {
"description": "Base Domain for create subdomains (ie.: example2.com) for websocket, notebook and eventsource.",
"pattern": "^([a-zA-Z0-9]([a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,6}$",
"title": "Nginx Domain",
"type": "string"
},
"public-ipv4": {
"description": "Public ipv4 of the frontend (the one Caddy will be indirectly listening to).",
"title": "Public IPv4",
"type": "string"
},
"re6st-verification-url": {
"description": "Url to verify if the internet and/or re6stnet is working.",
"title": "Test Verification URL",
"type": "string"
},
"enable-quic": {
"default": "false",
"description": "Enables QUIC - Quick UDP Internet Connections. Note that this is experimental feature, thus can result in undefined behaviour.",
"enum": [
"true",
"false"
],
"title": "Enable QUIC",
"type": "string"
}
}, },
"title": "Input Parameters", "-frontend-quantity": {
"type": "object" "description": "Quantity of Frontends Replicate.",
"title": "Frontend Replication Quantity",
"type": "integer"
},
"apache-ca-certificate": {
"description": "[NOT IMPLEMENTED] SSL CA Certificate used by the server.",
"textarea": true,
"title": "[NOT IMPLEMENTED] SSL CA Certificate",
"type": "string"
},
"apache-certificate": {
"description": "SSL Certificate used by the server.",
"textarea": true,
"title": "SSL Certificate",
"type": "string"
},
"apache-key": {
"description": "SSL Key used by the server.",
"textarea": true,
"title": "SSL Key",
"type": "string"
},
"domain": {
"description": "Base Domain for create subdomains (ie.: example.com).",
"pattern": "^([a-zA-Z0-9]([a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,6}$",
"title": "Domain",
"type": "string"
},
"enable-http2-by-default": {
"default": "true",
"description": "Use HTTP2 as default Protocol",
"enum": [
"true",
"false"
],
"title": "Enable HTTP2 by Default",
"type": "string"
},
"mpm-graceful-shutdown-timeout": {
"default": 5,
"description": "Value passed to -grace parameter of Caddy, see https://caddyserver.com/docs/cli .",
"title": "Duration of the graceful shutdown period",
"type": "integer"
},
"nginx-domain": {
"description": "Base Domain for create subdomains (ie.: example2.com) for websocket, notebook and eventsource.",
"pattern": "^([a-zA-Z0-9]([a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,6}$",
"title": "Nginx Domain",
"type": "string"
},
"public-ipv4": {
"description": "Public ipv4 of the frontend (the one Caddy will be indirectly listening to).",
"title": "Public IPv4",
"type": "string"
},
"re6st-verification-url": {
"description": "Url to verify if the internet and/or re6stnet is working.",
"title": "Test Verification URL",
"type": "string"
},
"enable-quic": {
"default": "false",
"description": "Enables QUIC - Quick UDP Internet Connections. Note that this is experimental feature, thus can result in undefined behaviour.",
"enum": [
"true",
"false"
],
"title": "Enable QUIC",
"type": "string"
}
},
"title": "Input Parameters",
"type": "object"
} }
{ {
"$schema": "http://json-schema.org/draft-04/schema#", "$schema": "http://json-schema.org/draft-04/schema#",
"description": "Values returned by Caddy Frontend instanciation", "description": "Values returned by Caddy Frontend instanciation",
"properties": { "properties": {
"accepted-slave-amount": { "accepted-slave-amount": {
"description": "Amount of Slaves allocated to the Instance which are deployed", "description": "Amount of Slaves allocated to the Instance which are deployed",
"type": "integer" "type": "integer"
}, },
"domain": { "domain": {
"description": "Base domain used by the instance", "description": "Base domain used by the instance",
"type": "string" "type": "string"
}, },
"monitor-base-url": { "monitor-base-url": {
"description": "Base url for monitor", "description": "Base url for monitor",
"type": "string" "type": "string"
}, },
"monitor-password": { "monitor-password": {
"description": "Password to access the monitor", "description": "Password to access the monitor",
"type": "string" "type": "string"
}, },
"monitor-url": { "monitor-url": {
"description": "Url of Monitor (opml)", "description": "Url of Monitor (opml)",
"type": "string" "type": "string"
}, },
"monitor-user": { "monitor-user": {
"description": "User to access the monitor", "description": "User to access the monitor",
"type": "string" "type": "string"
}, },
"reject-slave-amount": { "reject-slave-amount": {
"description": "Rejected Amount of Slaves allocated to the Instance which are not deployed", "description": "Rejected Amount of Slaves allocated to the Instance which are not deployed",
"type": "integer" "type": "integer"
}, },
"rejected-slave-list": { "rejected-slave-list": {
"description": "List of slave instances references which are rejected", "description": "List of slave instances references which are rejected",
"type": "array" "type": "array"
}, },
"slave-amount": { "slave-amount": {
"description": "Total amount of Slaves allocated to the Instance (include blocked ones)", "description": "Total amount of Slaves allocated to the Instance (include blocked ones)",
"type": "integer" "type": "integer"
} }
}, },
"type": "object" "type": "object"
} }
{ {
"$schema": "http://json-schema.org/draft-04/schema", "$schema": "http://json-schema.org/draft-04/schema",
"properties": { "properties": {
"caddy_custom_http": { "caddy_custom_http": {
"default": "", "default": "",
"description": "Raw http configuration in python template format. Your site will be rejected if you use it without notification and approval of frontend administrators", "description": "Raw http configuration in python template format. Your site will be rejected if you use it without notification and approval of frontend administrators",
"textarea": true, "textarea": true,
"title": "HTTP configuration", "title": "HTTP configuration",
"type": "string" "type": "string"
}, },
"caddy_custom_https": { "caddy_custom_https": {
"default": "", "default": "",
"description": "Raw https configuration in python template format. Your site will be rejected if you use it without notification and approval of frontend administrators", "description": "Raw https configuration in python template format. Your site will be rejected if you use it without notification and approval of frontend administrators",
"textarea": true, "textarea": true,
"title": "HTTPS configuration", "title": "HTTPS configuration",
"type": "string" "type": "string"
}, },
"custom_domain": { "custom_domain": {
"description": "Custom Domain to use for the website", "description": "Custom Domain to use for the website",
"pattern": "^([a-zA-Z0-9]([a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,6}$", "pattern": "^([a-zA-Z0-9]([a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,6}$",
"title": "Custom Domain", "title": "Custom Domain",
"type": "string" "type": "string"
}, },
"default-path": { "default-path": {
"default": "", "default": "",
"description": "Provide default path to redirect user to when user access / (the site root)", "description": "Provide default path to redirect user to when user access / (the site root)",
"title": "type:zope Default Path", "title": "type:zope Default Path",
"type": "string" "type": "string"
}, },
"disable-no-cache-request": { "disable-no-cache-request": {
"default": "false", "default": "false",
"description": "If set to true, Cache-Control and Pragma requests headers will not be sent to cache and backend servers. This prevents clients from bypassing cache when enable_cache is true", "description": "If set to true, Cache-Control and Pragma requests headers will not be sent to cache and backend servers. This prevents clients from bypassing cache when enable_cache is true",
"enum": [ "enum": [
"false", "false",
"true" "true"
], ],
"title": "enable_cache: Disable 'no-cache' requests", "title": "enable_cache: Disable 'no-cache' requests",
"type": "string" "type": "string"
}, },
"disable-via-header": { "disable-via-header": {
"default": "false", "default": "false",
"description": "If set to true, Via response headers will not be sent to client", "description": "If set to true, Via response headers will not be sent to client",
"enum": [ "enum": [
"false", "false",
"true" "true"
], ],
"title": "enable_cache: Disable 'Via' headers from cache", "title": "enable_cache: Disable 'Via' headers from cache",
"type": "string" "type": "string"
}, },
"disabled-cookie-list": { "disabled-cookie-list": {
"default": "", "default": "",
"description": "[NOT Implemented] List of Cookies separated by space that will not be sent to cache and backend servers. This is especially useful to discard analytics tracking cookies when using Vary: Cookie cache headers", "description": "List of Cookies separated by space that will not be sent to cache and backend servers. This is especially useful to discard analytics tracking cookies when using Vary: Cookie cache headers",
"title": "[NOT Implemented] Disabled Cookies", "title": "Disabled Cookies",
"type": "string" "type": "string"
}, },
"enable-http2": { "enable-http2": {
"default": "true", "default": "true",
"description": "Use HTTP2 Protocol for the site", "description": "Use HTTP2 Protocol for the site",
"enum": [ "enum": [
"true", "true",
"false" "false"
], ],
"title": "Enable HTTP2 Protocol", "title": "Enable HTTP2 Protocol",
"type": "string" "type": "string"
}, },
"enable_cache": { "enable_cache": {
"default": "false", "default": "false",
"description": "If set to true, http caching server (Apache Traffic Server) will be used between frontend Caddy and backend", "description": "If set to true, http caching server (Apache Traffic Server) will be used between frontend Caddy and backend",
"enum": [ "enum": [
"false", "false",
"true" "true"
], ],
"title": "Enable Cache", "title": "Enable Cache",
"type": "string" "type": "string"
}, },
"https-only": { "https-only": {
"default": "false", "default": "false",
"description": "If set to true, http requests will be redirected to https", "description": "If set to true, http requests will be redirected to https",
"enum": [ "enum": [
"false", "false",
"true" "true"
], ],
"title": "HTTPS Only", "title": "HTTPS Only",
"type": "string" "type": "string"
}, },
"https-url": { "https-url": {
"description": "HTTPS Url of the backend if it is diferent from url parameter", "description": "HTTPS Url of the backend if it is diferent from url parameter",
"pattern": "^(http|https|ftp)://", "pattern": "^(http|https|ftp)://",
"title": "HTTPS Backend URL", "title": "HTTPS Backend URL",
"type": "string" "type": "string"
}, },
"monitor-ipv4-test": { "monitor-ipv4-test": {
"default": "", "default": "",
"description": "IPv4 Address for the frontend keep monitoring with ping", "description": "IPv4 Address for the frontend keep monitoring with ping",
"title": "IPv4 Address to Monitor Packet Lost", "title": "IPv4 Address to Monitor Packet Lost",
"type": "string" "type": "string"
}, },
"monitor-ipv6-test": { "monitor-ipv6-test": {
"default": "", "default": "",
"description": "IPv6 Address for the frontend keep monitoring with ping6 (without brackets)", "description": "IPv6 Address for the frontend keep monitoring with ping6 (without brackets)",
"title": "IPv6 Address to Monitor Packet Lost", "title": "IPv6 Address to Monitor Packet Lost",
"type": "string" "type": "string"
}, },
"path": { "path": {
"default": "", "default": "",
"description": "Path to proxy to in the backend", "description": "Path to proxy to in the backend",
"title": "type:zope Backend Path", "title": "type:zope Backend Path",
"type": "string" "type": "string"
}, },
"prefer-gzip-encoding-to-backend": { "prefer-gzip-encoding-to-backend": {
"default": "false", "default": "false",
"description": "[NOT Implemented] If set to true, frontend will rewrite Accept-Encoding request header to simply 'gzip' for all variants of Accept-Encoding containing 'gzip', in order to maximize cache hits for resources cached with Vary: Accept-Encoding when enable_cache is used", "description": "If set to true, frontend will rewrite Accept-Encoding request header to simply 'gzip' for all variants of Accept-Encoding containing 'gzip', in order to maximize cache hits for resources cached with Vary: Accept-Encoding when enable_cache is used",
"enum": [ "enum": [
"false", "false",
"true" "true"
], ],
"title": "[NOT Implemented] Prefer gzip Encoding for Backend", "title": "Prefer gzip Encoding for Backend",
"type": "string" "type": "string"
}, },
"re6st-optimal-test": { "re6st-optimal-test": {
"default": "", "default": "",
"description": "IPv6 and IPv6 Address for the frontend test if re6st is on the optimal status (use ipv6,ipv4)", "description": "IPv6 and IPv6 Address for the frontend test if re6st is on the optimal status (use ipv6,ipv4)",
"title": "IPv6 and IPv4 Address to test Re6st", "title": "IPv6 and IPv4 Address to test Re6st",
"type": "string" "type": "string"
}, },
"server-alias": { "server-alias": {
"default": "", "default": "",
"description": "Server Alias List separated by space", "description": "Server Alias List separated by space",
"title": "Server Alias", "title": "Server Alias",
"type": "string" "type": "string"
}, },
"ssl-proxy-verify": { "ssl-proxy-verify": {
"default": "false", "default": "false",
"description": "[NOT Implemented] If set to true, Backend SSL Certificates will be checked and frontend will refuse to proxy if certificate is invalid", "description": "[NOT Implemented] If set to true, Backend SSL Certificates will be checked and frontend will refuse to proxy if certificate is invalid",
"enum": [ "enum": [
"false", "false",
"true" "true"
], ],
"title": "[NOT Implemented] Verify Backend Certificates", "title": "[NOT Implemented] Verify Backend Certificates",
"type": "string" "type": "string"
}, },
"ssl_ca_crt": { "ssl_ca_crt": {
"default": "", "default": "",
"description": "[NOT Implemented] Content of the CA certificate file", "description": "[NOT Implemented] Content of the CA certificate file",
"textarea": true, "textarea": true,
"title": "[NOT Implemented] SSL Certificate Authority's Certificate", "title": "[NOT Implemented] SSL Certificate Authority's Certificate",
"type": "string" "type": "string"
}, },
"ssl_crt": { "ssl_crt": {
"default": "", "default": "",
"description": "Content of the SSL Certificate file", "description": "Content of the SSL Certificate file",
"textarea": true, "textarea": true,
"title": "SSL Certificate", "title": "SSL Certificate",
"type": "string" "type": "string"
}, },
"ssl_key": { "ssl_key": {
"default": "", "default": "",
"description": "Content of the SSL Key file", "description": "Content of the SSL Key file",
"textarea": true, "textarea": true,
"title": "SSL Key", "title": "SSL Key",
"type": "string" "type": "string"
}, },
"ssl_proxy_ca_crt": { "ssl_proxy_ca_crt": {
"default": "", "default": "",
"description": "[NOT Implemented] Content of the SSL Certificate Authority file of the backend (to be used with ssl-proxy-verify)", "description": "[NOT Implemented] Content of the SSL Certificate Authority file of the backend (to be used with ssl-proxy-verify)",
"title": "[NOT Implemented] SSL Backend Authority's Certificate", "title": "[NOT Implemented] SSL Backend Authority's Certificate",
"type": "string" "type": "string"
}, },
"type": { "type": {
"default": "", "default": "",
"description": "Type of slave. If redirect, the slave will redirect to the given url. If zope, the rewrite rules will be compatible with Virtual Host Monster. Implemented are default, zope and redirect, not implemneted are notebook and eventsource.", "description": "Type of slave. If redirect, the slave will redirect to the given url. If zope, the rewrite rules will be compatible with Virtual Host Monster. Implemented are default, zope and redirect, not implemneted are notebook and eventsource.",
"enum": [ "enum": [
"", "",
"zope", "zope",
"redirect", "redirect",
"notebook", "notebook",
"eventsource" "eventsource"
], ],
"title": "Backend Type", "title": "Backend Type",
"type": "string" "type": "string"
}, },
"url": { "url": {
"description": "Url of the backend", "description": "Url of the backend",
"pattern": "^(http|https|ftp)://", "pattern": "^(http|https|ftp)://",
"title": "Backend URL", "title": "Backend URL",
"type": "string" "type": "string"
}, },
"virtualhostroot-http-port": { "virtualhostroot-http-port": {
"default": 80, "default": 80,
"description": "Port where http requests to frontend will be redirected.", "description": "Port where http requests to frontend will be redirected.",
"title": "type:zope virtualhostroot-http-port", "title": "type:zope virtualhostroot-http-port",
"type": "integer" "type": "integer"
}, },
"virtualhostroot-https-port": { "virtualhostroot-https-port": {
"default": 443, "default": 443,
"description": "Port where https requests to frontend will be redirected.", "description": "Port where https requests to frontend will be redirected.",
"title": "type:zope virtualhostroot-https-port", "title": "type:zope virtualhostroot-https-port",
"type": "integer" "type": "integer"
} }
}, },
"title": "Input Parameters", "title": "Input Parameters",
"type": "object" "type": "object"
} }
{ {
"$schema": "http://json-schema.org/draft-04/schema#", "$schema": "http://json-schema.org/draft-04/schema#",
"description": "Values returned by Caddy Frontend instanciation", "description": "Values returned by Caddy Frontend instanciation",
"properties": { "properties": {
"domain": { "domain": {
"description": "Base domain used by the instance", "description": "Base domain used by the instance",
"type": "string" "type": "string"
},
"log-access-url": {
"description": "List of URLs to access logs",
"type": "array"
},
"public-ipv4": {
"description": "Public IPv4 to be included on DNS",
"type": "string"
},
"replication_number": {
"description": "Number of nodes the slave is replicated",
"type": "integer"
},
"secure_access": {
"description": "URL for HTTP access",
"type": "string"
},
"site_url": {
"description": "URL for HTTP access",
"type": "string"
},
"url": {
"description": "Default URL provided",
"type": "string"
}
}, },
"type": "object" "log-access-url": {
"description": "List of URLs to access logs",
"type": "array"
},
"public-ipv4": {
"description": "Public IPv4 to be included on DNS",
"type": "string"
},
"replication_number": {
"description": "Number of nodes the slave is replicated",
"type": "integer"
},
"secure_access": {
"description": "URL for HTTP access",
"type": "string"
},
"site_url": {
"description": "URL for HTTP access",
"type": "string"
},
"url": {
"description": "Default URL provided",
"type": "string"
}
},
"type": "object"
} }
{ {
"description": "Caddy Frontend", "description": "Caddy Frontend",
"name": "Caddy Frontend", "name": "Caddy Frontend",
"serialisation": "xml", "serialisation": "xml",
"software-type": { "software-type": {
"custom-personal": { "custom-personal": {
"description": "", "description": "",
"index": 2, "index": 2,
"request": "instance-caddy-input-schema.json", "request": "instance-caddy-input-schema.json",
"response": "instance-output-schema.json", "response": "instance-output-schema.json",
"title": "Custom Personal" "title": "Custom Personal"
}, },
"custom-personal-slave": { "custom-personal-slave": {
"description": "Custom Personal", "description": "Custom Personal",
"index": 1, "index": 1,
"request": "instance-slave-caddy-input-schema.json", "request": "instance-slave-caddy-input-schema.json",
"response": "instance-output-schema.json", "response": "instance-output-schema.json",
"shared": true, "shared": true,
"software-type": "custom-personal", "software-type": "custom-personal",
"title": "Custom Personal (Slave)" "title": "Custom Personal (Slave)"
}, },
"default": { "default": {
"description": "Default", "description": "Default",
"index": 3, "index": 3,
"request": "instance-caddy-input-schema.json", "request": "instance-caddy-input-schema.json",
"response": "instance-output-schema.json", "response": "instance-output-schema.json",
"software-type": "default", "software-type": "default",
"title": "Default" "title": "Default"
}, },
"default-slave": { "default-slave": {
"description": "Default", "description": "Default",
"index": 4, "index": 4,
"request": "instance-slave-caddy-input-schema.json", "request": "instance-slave-caddy-input-schema.json",
"response": "instance-output-schema.json", "response": "instance-output-schema.json",
"shared": true, "shared": true,
"software-type": "default", "software-type": "default",
"title": "Default (slave)" "title": "Default (slave)"
}
} }
}
} }
...@@ -45,9 +45,6 @@ ...@@ -45,9 +45,6 @@
log / {{ slave_parameter.get('access_log') }} "{remote} {>REMOTE_USER} [{when}] \"{method} {uri} {proto}\" {status} {size} \"{>Referer}\" \"{>User-Agent}\" {latency_ms}" log / {{ slave_parameter.get('access_log') }} "{remote} {>REMOTE_USER} [{when}] \"{method} {uri} {proto}\" {status} {size} \"{>Referer}\" \"{>User-Agent}\" {latency_ms}"
errors {{ slave_parameter.get('error_log') }} errors {{ slave_parameter.get('error_log') }}
{%- for disabled_cookie in disabled_cookie_list %}
{%- endfor %} {#- for disabled_cookie in disabled_cookie_list #}
{%- if prefer_gzip %} {%- if prefer_gzip %}
rewrite { rewrite {
if {>Accept-Encoding} match "(^gzip,.*|.*, gzip,.*|.*, gzip$|^gzip$)" if {>Accept-Encoding} match "(^gzip,.*|.*, gzip,.*|.*, gzip$|^gzip$)"
...@@ -66,6 +63,10 @@ ...@@ -66,6 +63,10 @@
{%- endif %} {#- if proxy_name == 'prefer-gzip' #} {%- endif %} {#- if proxy_name == 'prefer-gzip' #}
# As backend is trusting REMOTE_USER header unset it always # As backend is trusting REMOTE_USER header unset it always
header_upstream -REMOTE_USER header_upstream -REMOTE_USER
{%- for disabled_cookie in disabled_cookie_list %}
# Remove cookie {{ disabled_cookie }} from client Cookies
header_upstream Cookie "(.*)(^{{ disabled_cookie }}=[^;]*; |; {{ disabled_cookie }}=[^;]*|^{{ disabled_cookie }}=[^;]*$)(.*)" "$1 $3"
{%- endfor %} {#- for disabled_cookie in disabled_cookie_list #}
{%- if disable_via_header %} {%- if disable_via_header %}
header_downstream -Via header_downstream -Via
...@@ -119,6 +120,10 @@ ...@@ -119,6 +120,10 @@
{%- endif %} {#- if proxy_name == 'prefer-gzip' #} {%- endif %} {#- if proxy_name == 'prefer-gzip' #}
# As backend is trusting REMOTE_USER header unset it always # As backend is trusting REMOTE_USER header unset it always
header_upstream -REMOTE_USER header_upstream -REMOTE_USER
{%- for disabled_cookie in disabled_cookie_list %}
# Remove cookie {{ disabled_cookie }} from client Cookies
header_upstream Cookie "(.*)(^{{ disabled_cookie }}=[^;]*; |; {{ disabled_cookie }}=[^;]*|^{{ disabled_cookie }}=[^;]*$)(.*)" "$1 $3"
{%- endfor %} {#- for disabled_cookie in disabled_cookie_list #}
{%- if disable_via_header %} {%- if disable_via_header %}
header_downstream -Via header_downstream -Via
...@@ -154,9 +159,6 @@ ...@@ -154,9 +159,6 @@
log / {{ slave_parameter.get('access_log') }} "{remote} {>REMOTE_USER} [{when}] \"{method} {uri} {proto}\" {status} {size} \"{>Referer}\" \"{>User-Agent}\" {latency_ms}" log / {{ slave_parameter.get('access_log') }} "{remote} {>REMOTE_USER} [{when}] \"{method} {uri} {proto}\" {status} {size} \"{>Referer}\" \"{>User-Agent}\" {latency_ms}"
errors {{ slave_parameter.get('error_log') }} errors {{ slave_parameter.get('error_log') }}
{%- for disabled_cookie in disabled_cookie_list %}
{%- endfor %} {#- for disabled_cookie in disabled_cookie_list #}
{%- if prefer_gzip %} {%- if prefer_gzip %}
rewrite { rewrite {
if {>Accept-Encoding} match "(^gzip,.*|.*, gzip,.*|.*, gzip$|^gzip$)" if {>Accept-Encoding} match "(^gzip,.*|.*, gzip,.*|.*, gzip$|^gzip$)"
...@@ -183,6 +185,10 @@ ...@@ -183,6 +185,10 @@
{%- endif %} {#- if proxy_name == 'prefer-gzip' #} {%- endif %} {#- if proxy_name == 'prefer-gzip' #}
# As backend is trusting REMOTE_USER header unset it always # As backend is trusting REMOTE_USER header unset it always
header_upstream -REMOTE_USER header_upstream -REMOTE_USER
{%- for disabled_cookie in disabled_cookie_list %}
# Remove cookie {{ disabled_cookie }} from client Cookies
header_upstream Cookie "(.*)(^{{ disabled_cookie }}=[^;]*; |; {{ disabled_cookie }}=[^;]*|^{{ disabled_cookie }}=[^;]*$)(.*)" "$1 $3"
{%- endfor %} {#- for disabled_cookie in disabled_cookie_list #}
{%- if disable_via_header %} {%- if disable_via_header %}
header_downstream -Via header_downstream -Via
...@@ -230,6 +236,10 @@ ...@@ -230,6 +236,10 @@
{%- endif %} {#- if proxy_name == 'prefer-gzip' #} {%- endif %} {#- if proxy_name == 'prefer-gzip' #}
# As backend is trusting REMOTE_USER header unset it always # As backend is trusting REMOTE_USER header unset it always
header_upstream -REMOTE_USER header_upstream -REMOTE_USER
{%- for disabled_cookie in disabled_cookie_list %}
# Remove cookie {{ disabled_cookie }} from client Cookies
header_upstream Cookie "(.*)(^{{ disabled_cookie }}=[^;]*; |; {{ disabled_cookie }}=[^;]*|^{{ disabled_cookie }}=[^;]*$)(.*)" "$1 $3"
{%- endfor %} {#- for disabled_cookie in disabled_cookie_list #}
{%- if disable_via_header %} {%- if disable_via_header %}
header_downstream -Via header_downstream -Via
......
...@@ -43,11 +43,15 @@ import subprocess ...@@ -43,11 +43,15 @@ import subprocess
from unittest import skipIf, skip from unittest import skipIf, skip
import ssl import ssl
from BaseHTTPServer import HTTPServer from BaseHTTPServer import HTTPServer
from BaseHTTPServer import BaseHTTPRequestHandler
from forcediphttpsadapter.adapters import ForcedIPHTTPSAdapter from forcediphttpsadapter.adapters import ForcedIPHTTPSAdapter
import time import time
import utils from utils import SlapOSInstanceTestCase
from utils import findFreeTCPPort
LOCAL_IPV4 = os.environ['LOCAL_IPV4']
GLOBAL_IPV6 = os.environ['GLOBAL_IPV6']
# ports chosen to not collide with test systems # ports chosen to not collide with test systems
HTTP_PORT = '11080' HTTP_PORT = '11080'
...@@ -177,11 +181,21 @@ if os.environ.get('DEBUG'): ...@@ -177,11 +181,21 @@ if os.environ.get('DEBUG'):
unittest.installHandler() unittest.installHandler()
def der2pem(der):
certificate, error = subprocess.Popen(
'openssl x509 -inform der'.split(), stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE
).communicate(der)
if error:
raise ValueError(error)
return certificate
def isHTTP2(domain, ip): def isHTTP2(domain, ip):
curl_command = '%(curl)s --http2 -v -k -H "Host: %(domain)s" ' \ curl_command = 'curl --http2 -v -k -H "Host: %(domain)s" ' \
'https://%(domain)s:%(https_port)s/ '\ 'https://%(domain)s:%(https_port)s/ '\
'--resolve %(domain)s:%(https_port)s:%(ip)s' % dict( '--resolve %(domain)s:%(https_port)s:%(ip)s' % dict(
ip=ip, domain=domain, curl=os.environ['CURL'], https_port=HTTPS_PORT) ip=ip, domain=domain, https_port=HTTPS_PORT)
prc = subprocess.Popen( prc = subprocess.Popen(
curl_command.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE curl_command.split(), stdout=subprocess.PIPE, stderr=subprocess.PIPE
) )
...@@ -221,6 +235,16 @@ class TestDataMixin(object): ...@@ -221,6 +235,16 @@ class TestDataMixin(object):
finally: finally:
self.maxDiff = maxDiff self.maxDiff = maxDiff
def test_plugin_list(self):
runtime_data = '\n'.join(sorted([
q[len(self.instance_path) + 1:]
for q in glob.glob(os.path.join(
self.instance_path, '*', 'etc', 'plugin', '*'))
if not q.endswith('pyc') # ignore compiled python
]))
self.assertTestData(runtime_data)
def test_promise_list(self): def test_promise_list(self):
runtime_data = '\n'.join(sorted([ runtime_data = '\n'.join(sorted([
q[len(self.instance_path) + 1:] q[len(self.instance_path) + 1:]
...@@ -275,9 +299,26 @@ class TestDataMixin(object): ...@@ -275,9 +299,26 @@ class TestDataMixin(object):
self.assertTestData(runtime_data) self.assertTestData(runtime_data)
class HttpFrontendTestCase(utils.SlapOSInstanceTestCase): class HttpFrontendTestCase(SlapOSInstanceTestCase):
frontend_type = 'CADDY' if IS_CADDY else 'APACHE' frontend_type = 'CADDY' if IS_CADDY else 'APACHE'
@classmethod
def getSoftwareURLList(cls):
return [os.path.realpath(os.environ['TEST_SR'])]
@classmethod
def setUpClass(cls):
super(HttpFrontendTestCase, cls).setUpClass()
# extra class attributes used in HttpFrontendTestCase
# expose instance directory
cls.instance_path = os.path.join(
cls.config['working_directory'],
'inst')
# expose software directory, extract from found computer partition
cls.software_path = os.path.realpath(os.path.join(
cls.computer_partition_root_path, 'software_release'))
def assertLogAccessUrlWithPop(self, parameter_dict, reference): def assertLogAccessUrlWithPop(self, parameter_dict, reference):
log_access_url = parameter_dict.pop('log-access-url') log_access_url = parameter_dict.pop('log-access-url')
try: try:
...@@ -373,16 +414,30 @@ class TestMasterRequestDomain(HttpFrontendTestCase, TestDataMixin): ...@@ -373,16 +414,30 @@ class TestMasterRequestDomain(HttpFrontendTestCase, TestDataMixin):
) )
class TestHandler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header("Content-type", "application/json")
self.send_header('Set-Cookie', 'secured=value;secure')
self.send_header('Set-Cookie', 'nonsecured=value')
self.end_headers()
response = {
'Path': self.path,
'Incoming Headers': self.headers.dict
}
self.wfile.write(json.dumps(response, indent=2))
class SlaveHttpFrontendTestCase(HttpFrontendTestCase): class SlaveHttpFrontendTestCase(HttpFrontendTestCase):
@classmethod @classmethod
def startServerProcess(cls): def startServerProcess(cls):
server = HTTPServer( server = HTTPServer(
(utils.LOCAL_IPV4, utils.findFreeTCPPort(utils.LOCAL_IPV4)), (LOCAL_IPV4, findFreeTCPPort(LOCAL_IPV4)),
utils.TestHandler) TestHandler)
server_https = HTTPServer( server_https = HTTPServer(
(utils.LOCAL_IPV4, utils.findFreeTCPPort(utils.LOCAL_IPV4)), (LOCAL_IPV4, findFreeTCPPort(LOCAL_IPV4)),
utils.TestHandler) TestHandler)
server_https.socket = ssl.wrap_socket( server_https.socket = ssl.wrap_socket(
server_https.socket, server_https.socket,
...@@ -526,7 +581,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -526,7 +581,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
return { return {
'domain': 'example.com', 'domain': 'example.com',
'nginx-domain': 'nginx.example.com', 'nginx-domain': 'nginx.example.com',
'public-ipv4': utils.LOCAL_IPV4, 'public-ipv4': LOCAL_IPV4,
'apache-certificate': open('wildcard.example.com.crt').read(), 'apache-certificate': open('wildcard.example.com.crt').read(),
'apache-key': open('wildcard.example.com.key').read(), 'apache-key': open('wildcard.example.com.key').read(),
'-frontend-authorized-slave-string': '-frontend-authorized-slave-string':
...@@ -742,13 +797,23 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -742,13 +797,23 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
self.assertEqual( self.assertEqual(
set([ set([
'check-free-disk-space',
'monitor-http-frontend', 'monitor-http-frontend',
'monitor-httpd-listening-on-tcp', 'monitor-httpd-listening-on-tcp',
'promise-monitor-httpd-is-process-older-than-dependency-set', 'promise-monitor-httpd-is-process-older-than-dependency-set',
]), ]),
set(os.listdir(os.path.join(partition_path, 'etc', 'promise')))) set(os.listdir(os.path.join(partition_path, 'etc', 'promise'))))
self.assertEqual(
set([
'monitor-bootstrap-status.py',
'check-free-disk-space.py',
'buildout-TestSlave-0-status.py',
'__init__.py',
]),
set([
q for q in os.listdir(os.path.join(partition_path, 'etc', 'plugin'))
if not q.endswith('.pyc')]))
self.assertEqual( self.assertEqual(
set(), set(),
set(os.listdir(os.path.join(partition_path, 'etc', 'monitor-promise')))) set(os.listdir(os.path.join(partition_path, 'etc', 'monitor-promise'))))
...@@ -797,7 +862,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -797,7 +862,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
'url': 'http://empty.example.com', 'url': 'http://empty.example.com',
'site_url': 'http://empty.example.com', 'site_url': 'http://empty.example.com',
'secure_access': 'https://empty.example.com', 'secure_access': 'https://empty.example.com',
'public-ipv4': utils.LOCAL_IPV4, 'public-ipv4': LOCAL_IPV4,
} }
) )
...@@ -805,7 +870,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -805,7 +870,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path') parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path')
self.assertEqual( self.assertEqual(
utils.der2pem(result.peercert), der2pem(result.peercert),
open('wildcard.example.com.crt').read()) open('wildcard.example.com.crt').read())
self.assertEqual(result.status_code, no_backend_response_code) self.assertEqual(result.status_code, no_backend_response_code)
...@@ -854,7 +919,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -854,7 +919,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
'url': 'http://url.example.com', 'url': 'http://url.example.com',
'site_url': 'http://url.example.com', 'site_url': 'http://url.example.com',
'secure_access': 'https://url.example.com', 'secure_access': 'https://url.example.com',
'public-ipv4': utils.LOCAL_IPV4, 'public-ipv4': LOCAL_IPV4,
} }
) )
...@@ -862,7 +927,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -862,7 +927,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path') parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path')
self.assertEqual( self.assertEqual(
utils.der2pem(result.peercert), der2pem(result.peercert),
open('wildcard.example.com.crt').read()) open('wildcard.example.com.crt').read())
self.assertEqualResultJson(result, 'Path', '/test-path') self.assertEqualResultJson(result, 'Path', '/test-path')
...@@ -916,21 +981,21 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -916,21 +981,21 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
'url': 'http://url.example.com', 'url': 'http://url.example.com',
'site_url': 'http://url.example.com', 'site_url': 'http://url.example.com',
'secure_access': 'https://url.example.com', 'secure_access': 'https://url.example.com',
'public-ipv4': utils.LOCAL_IPV4, 'public-ipv4': LOCAL_IPV4,
} }
) )
result_ipv6 = self.fakeHTTPSResult( result_ipv6 = self.fakeHTTPSResult(
parameter_dict['domain'], utils.GLOBAL_IPV6, 'test-path', parameter_dict['domain'], GLOBAL_IPV6, 'test-path',
source_ip=utils.GLOBAL_IPV6) source_ip=GLOBAL_IPV6)
self.assertEqual( self.assertEqual(
result_ipv6.json()['Incoming Headers']['x-forwarded-for'], result_ipv6.json()['Incoming Headers']['x-forwarded-for'],
utils.GLOBAL_IPV6 GLOBAL_IPV6
) )
self.assertEqual( self.assertEqual(
utils.der2pem(result_ipv6.peercert), der2pem(result_ipv6.peercert),
open('wildcard.example.com.crt').read()) open('wildcard.example.com.crt').read())
self.assertEqualResultJson(result_ipv6, 'Path', '/test-path') self.assertEqualResultJson(result_ipv6, 'Path', '/test-path')
...@@ -947,7 +1012,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -947,7 +1012,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
'url': 'http://typezopepath.example.com', 'url': 'http://typezopepath.example.com',
'site_url': 'http://typezopepath.example.com', 'site_url': 'http://typezopepath.example.com',
'secure_access': 'https://typezopepath.example.com', 'secure_access': 'https://typezopepath.example.com',
'public-ipv4': utils.LOCAL_IPV4, 'public-ipv4': LOCAL_IPV4,
} }
) )
...@@ -955,7 +1020,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -955,7 +1020,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path') parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path')
self.assertEqual( self.assertEqual(
utils.der2pem(result.peercert), der2pem(result.peercert),
open('wildcard.example.com.crt').read()) open('wildcard.example.com.crt').read())
self.assertEqualResultJson( self.assertEqualResultJson(
...@@ -977,7 +1042,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -977,7 +1042,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
'url': 'http://typezopedefaultpath.example.com', 'url': 'http://typezopedefaultpath.example.com',
'site_url': 'http://typezopedefaultpath.example.com', 'site_url': 'http://typezopedefaultpath.example.com',
'secure_access': 'https://typezopedefaultpath.example.com', 'secure_access': 'https://typezopedefaultpath.example.com',
'public-ipv4': utils.LOCAL_IPV4, 'public-ipv4': LOCAL_IPV4,
} }
) )
...@@ -985,7 +1050,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -985,7 +1050,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
parameter_dict['domain'], parameter_dict['public-ipv4'], '') parameter_dict['domain'], parameter_dict['public-ipv4'], '')
self.assertEqual( self.assertEqual(
utils.der2pem(result.peercert), der2pem(result.peercert),
open('wildcard.example.com.crt').read()) open('wildcard.example.com.crt').read())
self.assertEqual( self.assertEqual(
...@@ -1005,7 +1070,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -1005,7 +1070,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
'url': 'http://serveralias.example.com', 'url': 'http://serveralias.example.com',
'site_url': 'http://serveralias.example.com', 'site_url': 'http://serveralias.example.com',
'secure_access': 'https://serveralias.example.com', 'secure_access': 'https://serveralias.example.com',
'public-ipv4': utils.LOCAL_IPV4, 'public-ipv4': LOCAL_IPV4,
} }
) )
...@@ -1013,7 +1078,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -1013,7 +1078,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path') parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path')
self.assertEqual( self.assertEqual(
utils.der2pem(result.peercert), der2pem(result.peercert),
open('wildcard.example.com.crt').read()) open('wildcard.example.com.crt').read())
self.assertEqualResultJson(result, 'Path', '/test-path') self.assertEqualResultJson(result, 'Path', '/test-path')
...@@ -1022,7 +1087,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -1022,7 +1087,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
'alias1.example.com', parameter_dict['public-ipv4'], 'test-path') 'alias1.example.com', parameter_dict['public-ipv4'], 'test-path')
self.assertEqual( self.assertEqual(
utils.der2pem(result.peercert), der2pem(result.peercert),
open('wildcard.example.com.crt').read()) open('wildcard.example.com.crt').read())
self.assertEqualResultJson(result, 'Path', '/test-path') self.assertEqualResultJson(result, 'Path', '/test-path')
...@@ -1031,7 +1096,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -1031,7 +1096,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
'alias2.example.com', parameter_dict['public-ipv4'], 'test-path') 'alias2.example.com', parameter_dict['public-ipv4'], 'test-path')
self.assertEqual( self.assertEqual(
utils.der2pem(result.peercert), der2pem(result.peercert),
open('wildcard.example.com.crt').read()) open('wildcard.example.com.crt').read())
self.assertEqualResultJson(result, 'Path', '/test-path') self.assertEqualResultJson(result, 'Path', '/test-path')
...@@ -1061,7 +1126,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -1061,7 +1126,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
'url': 'http://httpsonly.example.com', 'url': 'http://httpsonly.example.com',
'site_url': 'http://httpsonly.example.com', 'site_url': 'http://httpsonly.example.com',
'secure_access': 'https://httpsonly.example.com', 'secure_access': 'https://httpsonly.example.com',
'public-ipv4': utils.LOCAL_IPV4, 'public-ipv4': LOCAL_IPV4,
} }
) )
...@@ -1069,7 +1134,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -1069,7 +1134,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path') parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path')
self.assertEqual( self.assertEqual(
utils.der2pem(result.peercert), der2pem(result.peercert),
open('wildcard.example.com.crt').read()) open('wildcard.example.com.crt').read())
self.assertEqualResultJson(result, 'Path', '/test-path') self.assertEqualResultJson(result, 'Path', '/test-path')
...@@ -1094,7 +1159,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -1094,7 +1159,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
'url': 'http://customdomain.example.com', 'url': 'http://customdomain.example.com',
'site_url': 'http://customdomain.example.com', 'site_url': 'http://customdomain.example.com',
'secure_access': 'https://customdomain.example.com', 'secure_access': 'https://customdomain.example.com',
'public-ipv4': utils.LOCAL_IPV4, 'public-ipv4': LOCAL_IPV4,
} }
) )
...@@ -1102,7 +1167,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -1102,7 +1167,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path') parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path')
self.assertEqual( self.assertEqual(
utils.der2pem(result.peercert), der2pem(result.peercert),
open('wildcard.example.com.crt').read()) open('wildcard.example.com.crt').read())
self.assertEqualResultJson(result, 'Path', '/test-path') self.assertEqualResultJson(result, 'Path', '/test-path')
...@@ -1119,7 +1184,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -1119,7 +1184,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
'url': 'http://customdomainsslcrtsslkey.example.com', 'url': 'http://customdomainsslcrtsslkey.example.com',
'site_url': 'http://customdomainsslcrtsslkey.example.com', 'site_url': 'http://customdomainsslcrtsslkey.example.com',
'secure_access': 'https://customdomainsslcrtsslkey.example.com', 'secure_access': 'https://customdomainsslcrtsslkey.example.com',
'public-ipv4': utils.LOCAL_IPV4, 'public-ipv4': LOCAL_IPV4,
} }
) )
...@@ -1127,7 +1192,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -1127,7 +1192,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path') parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path')
self.assertEqual( self.assertEqual(
utils.der2pem(result.peercert), der2pem(result.peercert),
open('customdomainsslcrtsslkey.example.com.crt').read()) open('customdomainsslcrtsslkey.example.com.crt').read())
self.assertEqualResultJson(result, 'Path', '/test-path') self.assertEqualResultJson(result, 'Path', '/test-path')
...@@ -1144,7 +1209,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -1144,7 +1209,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
'url': 'http://typezope.example.com', 'url': 'http://typezope.example.com',
'site_url': 'http://typezope.example.com', 'site_url': 'http://typezope.example.com',
'secure_access': 'https://typezope.example.com', 'secure_access': 'https://typezope.example.com',
'public-ipv4': utils.LOCAL_IPV4, 'public-ipv4': LOCAL_IPV4,
} }
) )
...@@ -1152,7 +1217,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -1152,7 +1217,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path') parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path')
self.assertEqual( self.assertEqual(
utils.der2pem(result.peercert), der2pem(result.peercert),
open('wildcard.example.com.crt').read()) open('wildcard.example.com.crt').read())
try: try:
...@@ -1192,7 +1257,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -1192,7 +1257,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
'site_url': 'http://typezopevirtualhostroothttpport.example.com', 'site_url': 'http://typezopevirtualhostroothttpport.example.com',
'secure_access': 'secure_access':
'https://typezopevirtualhostroothttpport.example.com', 'https://typezopevirtualhostroothttpport.example.com',
'public-ipv4': utils.LOCAL_IPV4, 'public-ipv4': LOCAL_IPV4,
} }
) )
...@@ -1220,7 +1285,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -1220,7 +1285,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
'site_url': 'http://typezopevirtualhostroothttpsport.example.com', 'site_url': 'http://typezopevirtualhostroothttpsport.example.com',
'secure_access': 'secure_access':
'https://typezopevirtualhostroothttpsport.example.com', 'https://typezopevirtualhostroothttpsport.example.com',
'public-ipv4': utils.LOCAL_IPV4, 'public-ipv4': LOCAL_IPV4,
} }
) )
...@@ -1228,7 +1293,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -1228,7 +1293,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path') parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path')
self.assertEqual( self.assertEqual(
utils.der2pem(result.peercert), der2pem(result.peercert),
open('wildcard.example.com.crt').read()) open('wildcard.example.com.crt').read())
self.assertEqualResultJson( self.assertEqualResultJson(
...@@ -1250,7 +1315,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -1250,7 +1315,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
'url': 'http://typenotebook.nginx.example.com', 'url': 'http://typenotebook.nginx.example.com',
'site_url': 'http://typenotebook.nginx.example.com', 'site_url': 'http://typenotebook.nginx.example.com',
'secure_access': 'https://typenotebook.nginx.example.com', 'secure_access': 'https://typenotebook.nginx.example.com',
'public-ipv4': utils.LOCAL_IPV4, 'public-ipv4': LOCAL_IPV4,
} }
) )
...@@ -1259,7 +1324,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -1259,7 +1324,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
NGINX_HTTPS_PORT) NGINX_HTTPS_PORT)
self.assertEqual( self.assertEqual(
utils.der2pem(result.peercert), der2pem(result.peercert),
open('wildcard.example.com.crt').read()) open('wildcard.example.com.crt').read())
self.assertEqualResultJson(result, 'Path', '/test-path') self.assertEqualResultJson(result, 'Path', '/test-path')
...@@ -1292,7 +1357,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -1292,7 +1357,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
'url': 'http://typeeventsource.nginx.example.com', 'url': 'http://typeeventsource.nginx.example.com',
'site_url': 'http://typeeventsource.nginx.example.com', 'site_url': 'http://typeeventsource.nginx.example.com',
'secure_access': 'https://typeeventsource.nginx.example.com', 'secure_access': 'https://typeeventsource.nginx.example.com',
'public-ipv4': utils.LOCAL_IPV4, 'public-ipv4': LOCAL_IPV4,
} }
) )
...@@ -1301,7 +1366,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -1301,7 +1366,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
NGINX_HTTPS_PORT) NGINX_HTTPS_PORT)
self.assertEqual( self.assertEqual(
utils.der2pem(result.peercert), der2pem(result.peercert),
open('wildcard.example.com.crt').read()) open('wildcard.example.com.crt').read())
self.assertEqual( self.assertEqual(
...@@ -1334,7 +1399,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -1334,7 +1399,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
'url': 'http://typeredirect.example.com', 'url': 'http://typeredirect.example.com',
'site_url': 'http://typeredirect.example.com', 'site_url': 'http://typeredirect.example.com',
'secure_access': 'https://typeredirect.example.com', 'secure_access': 'https://typeredirect.example.com',
'public-ipv4': utils.LOCAL_IPV4, 'public-ipv4': LOCAL_IPV4,
} }
) )
...@@ -1342,7 +1407,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -1342,7 +1407,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path') parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path')
self.assertEqual( self.assertEqual(
utils.der2pem(result.peercert), der2pem(result.peercert),
open('wildcard.example.com.crt').read()) open('wildcard.example.com.crt').read())
self.assertEqual( self.assertEqual(
...@@ -1364,7 +1429,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -1364,7 +1429,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
'url': 'http://sslproxyverifysslproxycacrt.example.com', 'url': 'http://sslproxyverifysslproxycacrt.example.com',
'site_url': 'http://sslproxyverifysslproxycacrt.example.com', 'site_url': 'http://sslproxyverifysslproxycacrt.example.com',
'secure_access': 'https://sslproxyverifysslproxycacrt.example.com', 'secure_access': 'https://sslproxyverifysslproxycacrt.example.com',
'public-ipv4': utils.LOCAL_IPV4, 'public-ipv4': LOCAL_IPV4,
} }
) )
...@@ -1372,7 +1437,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -1372,7 +1437,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path') parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path')
self.assertEqual( self.assertEqual(
utils.der2pem(result.peercert), der2pem(result.peercert),
open('wildcard.example.com.crt').read()) open('wildcard.example.com.crt').read())
if IS_CADDY: if IS_CADDY:
...@@ -1441,7 +1506,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -1441,7 +1506,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
'url': 'http://sslproxyverifyunverified.example.com', 'url': 'http://sslproxyverifyunverified.example.com',
'site_url': 'http://sslproxyverifyunverified.example.com', 'site_url': 'http://sslproxyverifyunverified.example.com',
'secure_access': 'https://sslproxyverifyunverified.example.com', 'secure_access': 'https://sslproxyverifyunverified.example.com',
'public-ipv4': utils.LOCAL_IPV4, 'public-ipv4': LOCAL_IPV4,
} }
) )
...@@ -1449,7 +1514,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -1449,7 +1514,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path') parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path')
self.assertEqual( self.assertEqual(
utils.der2pem(result.peercert), der2pem(result.peercert),
open('wildcard.example.com.crt').read()) open('wildcard.example.com.crt').read())
self.assertEqual( self.assertEqual(
...@@ -1473,7 +1538,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -1473,7 +1538,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
'http://enablecachesslproxyverifysslproxycacrt.example.com', 'http://enablecachesslproxyverifysslproxycacrt.example.com',
'secure_access': 'secure_access':
'https://enablecachesslproxyverifysslproxycacrt.example.com', 'https://enablecachesslproxyverifysslproxycacrt.example.com',
'public-ipv4': utils.LOCAL_IPV4, 'public-ipv4': LOCAL_IPV4,
} }
) )
...@@ -1481,7 +1546,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -1481,7 +1546,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path') parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path')
self.assertEqual( self.assertEqual(
utils.der2pem(result.peercert), der2pem(result.peercert),
open('wildcard.example.com.crt').read()) open('wildcard.example.com.crt').read())
if IS_CADDY: if IS_CADDY:
...@@ -1558,7 +1623,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -1558,7 +1623,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
'site_url': 'http://enablecachesslproxyverifyunverified.example.com', 'site_url': 'http://enablecachesslproxyverifyunverified.example.com',
'secure_access': 'secure_access':
'https://enablecachesslproxyverifyunverified.example.com', 'https://enablecachesslproxyverifyunverified.example.com',
'public-ipv4': utils.LOCAL_IPV4, 'public-ipv4': LOCAL_IPV4,
} }
) )
...@@ -1566,7 +1631,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -1566,7 +1631,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path') parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path')
self.assertEqual( self.assertEqual(
utils.der2pem(result.peercert), der2pem(result.peercert),
open('wildcard.example.com.crt').read()) open('wildcard.example.com.crt').read())
self.assertEqual( self.assertEqual(
...@@ -1589,7 +1654,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -1589,7 +1654,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
'site_url': 'http://typezopesslproxyverifysslproxycacrt.example.com', 'site_url': 'http://typezopesslproxyverifysslproxycacrt.example.com',
'secure_access': 'secure_access':
'https://typezopesslproxyverifysslproxycacrt.example.com', 'https://typezopesslproxyverifysslproxycacrt.example.com',
'public-ipv4': utils.LOCAL_IPV4, 'public-ipv4': LOCAL_IPV4,
} }
) )
...@@ -1597,7 +1662,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -1597,7 +1662,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path') parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path')
self.assertEqual( self.assertEqual(
utils.der2pem(result.peercert), der2pem(result.peercert),
open('wildcard.example.com.crt').read()) open('wildcard.example.com.crt').read())
if IS_CADDY: if IS_CADDY:
...@@ -1652,7 +1717,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -1652,7 +1717,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
'site_url': 'http://typezopesslproxyverifyunverified.example.com', 'site_url': 'http://typezopesslproxyverifyunverified.example.com',
'secure_access': 'secure_access':
'https://typezopesslproxyverifyunverified.example.com', 'https://typezopesslproxyverifyunverified.example.com',
'public-ipv4': utils.LOCAL_IPV4, 'public-ipv4': LOCAL_IPV4,
} }
) )
...@@ -1660,7 +1725,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -1660,7 +1725,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path') parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path')
self.assertEqual( self.assertEqual(
utils.der2pem(result.peercert), der2pem(result.peercert),
open('wildcard.example.com.crt').read()) open('wildcard.example.com.crt').read())
self.assertEqual( self.assertEqual(
...@@ -1680,7 +1745,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -1680,7 +1745,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
'url': 'http://monitoripv6test.example.com', 'url': 'http://monitoripv6test.example.com',
'site_url': 'http://monitoripv6test.example.com', 'site_url': 'http://monitoripv6test.example.com',
'secure_access': 'https://monitoripv6test.example.com', 'secure_access': 'https://monitoripv6test.example.com',
'public-ipv4': utils.LOCAL_IPV4, 'public-ipv4': LOCAL_IPV4,
} }
) )
...@@ -1688,7 +1753,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -1688,7 +1753,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path') parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path')
self.assertEqual( self.assertEqual(
utils.der2pem(result.peercert), der2pem(result.peercert),
open('wildcard.example.com.crt').read()) open('wildcard.example.com.crt').read())
self.assertEqual(result.status_code, no_backend_response_code) self.assertEqual(result.status_code, no_backend_response_code)
...@@ -1723,7 +1788,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -1723,7 +1788,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
'url': 'http://monitoripv4test.example.com', 'url': 'http://monitoripv4test.example.com',
'site_url': 'http://monitoripv4test.example.com', 'site_url': 'http://monitoripv4test.example.com',
'secure_access': 'https://monitoripv4test.example.com', 'secure_access': 'https://monitoripv4test.example.com',
'public-ipv4': utils.LOCAL_IPV4, 'public-ipv4': LOCAL_IPV4,
} }
) )
...@@ -1731,7 +1796,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -1731,7 +1796,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path') parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path')
self.assertEqual( self.assertEqual(
utils.der2pem(result.peercert), der2pem(result.peercert),
open('wildcard.example.com.crt').read()) open('wildcard.example.com.crt').read())
self.assertEqual(result.status_code, no_backend_response_code) self.assertEqual(result.status_code, no_backend_response_code)
...@@ -1766,7 +1831,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -1766,7 +1831,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
'url': 'http://re6stoptimaltest.example.com', 'url': 'http://re6stoptimaltest.example.com',
'site_url': 'http://re6stoptimaltest.example.com', 'site_url': 'http://re6stoptimaltest.example.com',
'secure_access': 'https://re6stoptimaltest.example.com', 'secure_access': 'https://re6stoptimaltest.example.com',
'public-ipv4': utils.LOCAL_IPV4, 'public-ipv4': LOCAL_IPV4,
} }
) )
...@@ -1774,7 +1839,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -1774,7 +1839,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path') parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path')
self.assertEqual( self.assertEqual(
utils.der2pem(result.peercert), der2pem(result.peercert),
open('wildcard.example.com.crt').read()) open('wildcard.example.com.crt').read())
self.assertEqual(result.status_code, no_backend_response_code) self.assertEqual(result.status_code, no_backend_response_code)
...@@ -1810,7 +1875,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -1810,7 +1875,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
'url': 'http://enablecache.example.com', 'url': 'http://enablecache.example.com',
'site_url': 'http://enablecache.example.com', 'site_url': 'http://enablecache.example.com',
'secure_access': 'https://enablecache.example.com', 'secure_access': 'https://enablecache.example.com',
'public-ipv4': utils.LOCAL_IPV4, 'public-ipv4': LOCAL_IPV4,
} }
) )
...@@ -1818,7 +1883,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -1818,7 +1883,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path') parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path')
self.assertEqual( self.assertEqual(
utils.der2pem(result.peercert), der2pem(result.peercert),
open('wildcard.example.com.crt').read()) open('wildcard.example.com.crt').read())
self.assertEqualResultJson(result, 'Path', '/test-path') self.assertEqualResultJson(result, 'Path', '/test-path')
...@@ -1902,7 +1967,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -1902,7 +1967,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
'site_url': 'http://enablecachedisablenocacherequest.example.com', 'site_url': 'http://enablecachedisablenocacherequest.example.com',
'secure_access': 'secure_access':
'https://enablecachedisablenocacherequest.example.com', 'https://enablecachedisablenocacherequest.example.com',
'public-ipv4': utils.LOCAL_IPV4, 'public-ipv4': LOCAL_IPV4,
} }
) )
...@@ -1911,7 +1976,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -1911,7 +1976,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
headers={'Pragma': 'no-cache', 'Cache-Control': 'something'}) headers={'Pragma': 'no-cache', 'Cache-Control': 'something'})
self.assertEqual( self.assertEqual(
utils.der2pem(result.peercert), der2pem(result.peercert),
open('wildcard.example.com.crt').read()) open('wildcard.example.com.crt').read())
self.assertEqualResultJson(result, 'Path', '/test-path') self.assertEqualResultJson(result, 'Path', '/test-path')
...@@ -1955,7 +2020,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -1955,7 +2020,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
'site_url': 'http://enablecachedisableviaheader.example.com', 'site_url': 'http://enablecachedisableviaheader.example.com',
'secure_access': 'secure_access':
'https://enablecachedisableviaheader.example.com', 'https://enablecachedisableviaheader.example.com',
'public-ipv4': utils.LOCAL_IPV4, 'public-ipv4': LOCAL_IPV4,
} }
) )
...@@ -1963,7 +2028,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -1963,7 +2028,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path') parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path')
self.assertEqual( self.assertEqual(
utils.der2pem(result.peercert), der2pem(result.peercert),
open('wildcard.example.com.crt').read()) open('wildcard.example.com.crt').read())
self.assertEqualResultJson(result, 'Path', '/test-path') self.assertEqualResultJson(result, 'Path', '/test-path')
...@@ -2000,7 +2065,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -2000,7 +2065,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
'site_url': 'http://enablehttp2false.example.com', 'site_url': 'http://enablehttp2false.example.com',
'secure_access': 'secure_access':
'https://enablehttp2false.example.com', 'https://enablehttp2false.example.com',
'public-ipv4': utils.LOCAL_IPV4, 'public-ipv4': LOCAL_IPV4,
} }
) )
...@@ -2008,7 +2073,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -2008,7 +2073,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path') parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path')
self.assertEqual( self.assertEqual(
utils.der2pem(result.peercert), der2pem(result.peercert),
open('wildcard.example.com.crt').read()) open('wildcard.example.com.crt').read())
self.assertEqualResultJson(result, 'Path', '/test-path') self.assertEqualResultJson(result, 'Path', '/test-path')
...@@ -2050,7 +2115,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -2050,7 +2115,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
'site_url': 'http://enablehttp2default.example.com', 'site_url': 'http://enablehttp2default.example.com',
'secure_access': 'secure_access':
'https://enablehttp2default.example.com', 'https://enablehttp2default.example.com',
'public-ipv4': utils.LOCAL_IPV4, 'public-ipv4': LOCAL_IPV4,
} }
) )
...@@ -2058,7 +2123,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -2058,7 +2123,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path') parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path')
self.assertEqual( self.assertEqual(
utils.der2pem(result.peercert), der2pem(result.peercert),
open('wildcard.example.com.crt').read()) open('wildcard.example.com.crt').read())
self.assertEqualResultJson(result, 'Path', '/test-path') self.assertEqualResultJson(result, 'Path', '/test-path')
...@@ -2101,7 +2166,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -2101,7 +2166,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
'site_url': 'http://prefergzipencodingtobackend.example.com', 'site_url': 'http://prefergzipencodingtobackend.example.com',
'secure_access': 'secure_access':
'https://prefergzipencodingtobackend.example.com', 'https://prefergzipencodingtobackend.example.com',
'public-ipv4': utils.LOCAL_IPV4, 'public-ipv4': LOCAL_IPV4,
} }
) )
...@@ -2110,7 +2175,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -2110,7 +2175,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
headers={'Accept-Encoding': 'gzip, deflate'}) headers={'Accept-Encoding': 'gzip, deflate'})
self.assertEqual( self.assertEqual(
utils.der2pem(result.peercert), der2pem(result.peercert),
open('wildcard.example.com.crt').read()) open('wildcard.example.com.crt').read())
self.assertEqualResultJson(result, 'Path', '/test-path') self.assertEqualResultJson(result, 'Path', '/test-path')
...@@ -2127,7 +2192,6 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -2127,7 +2192,6 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
self.assertEqual( self.assertEqual(
result.json()['Incoming Headers']['accept-encoding'], 'deflate') result.json()['Incoming Headers']['accept-encoding'], 'deflate')
@skipIf(IS_CADDY, 'Feature postponed')
def test_disabled_cookie_list(self): def test_disabled_cookie_list(self):
parameter_dict = self.slave_connection_parameter_dict_dict[ parameter_dict = self.slave_connection_parameter_dict_dict[
'disabled-cookie-list'] 'disabled-cookie-list']
...@@ -2140,7 +2204,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -2140,7 +2204,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
'url': 'http://disabledcookielist.example.com', 'url': 'http://disabledcookielist.example.com',
'site_url': 'http://disabledcookielist.example.com', 'site_url': 'http://disabledcookielist.example.com',
'secure_access': 'https://disabledcookielist.example.com', 'secure_access': 'https://disabledcookielist.example.com',
'public-ipv4': utils.LOCAL_IPV4, 'public-ipv4': LOCAL_IPV4,
} }
) )
...@@ -2153,7 +2217,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -2153,7 +2217,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
)) ))
self.assertEqual( self.assertEqual(
utils.der2pem(result.peercert), der2pem(result.peercert),
open('wildcard.example.com.crt').read()) open('wildcard.example.com.crt').read())
self.assertEqualResultJson(result, 'Path', '/test-path') self.assertEqualResultJson(result, 'Path', '/test-path')
...@@ -2185,7 +2249,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -2185,7 +2249,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
parameter_dict, 'apache_custom_http_s-accepted') parameter_dict, 'apache_custom_http_s-accepted')
self.assertEqual( self.assertEqual(
parameter_dict, parameter_dict,
{'replication_number': '1', 'public-ipv4': utils.LOCAL_IPV4} {'replication_number': '1', 'public-ipv4': LOCAL_IPV4}
) )
result = self.fakeHTTPSResult( result = self.fakeHTTPSResult(
...@@ -2193,7 +2257,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -2193,7 +2257,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
parameter_dict['public-ipv4'], 'test-path') parameter_dict['public-ipv4'], 'test-path')
self.assertEqual( self.assertEqual(
utils.der2pem(result.peercert), der2pem(result.peercert),
open('wildcard.example.com.crt').read()) open('wildcard.example.com.crt').read())
self.assertEqualResultJson(result, 'Path', '/test-path') self.assertEqualResultJson(result, 'Path', '/test-path')
...@@ -2271,7 +2335,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -2271,7 +2335,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
parameter_dict, 'caddy_custom_http_s-accepted') parameter_dict, 'caddy_custom_http_s-accepted')
self.assertEqual( self.assertEqual(
parameter_dict, parameter_dict,
{'replication_number': '1', 'public-ipv4': utils.LOCAL_IPV4} {'replication_number': '1', 'public-ipv4': LOCAL_IPV4}
) )
result = self.fakeHTTPSResult( result = self.fakeHTTPSResult(
...@@ -2279,7 +2343,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -2279,7 +2343,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
parameter_dict['public-ipv4'], 'test-path') parameter_dict['public-ipv4'], 'test-path')
self.assertEqual( self.assertEqual(
utils.der2pem(result.peercert), der2pem(result.peercert),
open('wildcard.example.com.crt').read()) open('wildcard.example.com.crt').read())
self.assertEqualResultJson(result, 'Path', '/test-path') self.assertEqualResultJson(result, 'Path', '/test-path')
...@@ -2333,7 +2397,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -2333,7 +2397,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
'url': 'http://urlhttpsurl.example.com', 'url': 'http://urlhttpsurl.example.com',
'site_url': 'http://urlhttpsurl.example.com', 'site_url': 'http://urlhttpsurl.example.com',
'secure_access': 'https://urlhttpsurl.example.com', 'secure_access': 'https://urlhttpsurl.example.com',
'public-ipv4': utils.LOCAL_IPV4, 'public-ipv4': LOCAL_IPV4,
} }
) )
...@@ -2341,7 +2405,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -2341,7 +2405,7 @@ class TestSlave(SlaveHttpFrontendTestCase, TestDataMixin):
parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path') parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path')
self.assertEqual( self.assertEqual(
utils.der2pem(result.peercert), der2pem(result.peercert),
open('wildcard.example.com.crt').read()) open('wildcard.example.com.crt').read())
self.assertEqualResultJson(result, 'Path', '/https/test-path') self.assertEqualResultJson(result, 'Path', '/https/test-path')
...@@ -2357,7 +2421,7 @@ class TestReplicateSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -2357,7 +2421,7 @@ class TestReplicateSlave(SlaveHttpFrontendTestCase, TestDataMixin):
return { return {
'domain': 'example.com', 'domain': 'example.com',
'nginx-domain': 'nginx.example.com', 'nginx-domain': 'nginx.example.com',
'public-ipv4': utils.LOCAL_IPV4, 'public-ipv4': LOCAL_IPV4,
'apache-certificate': open('wildcard.example.com.crt').read(), 'apache-certificate': open('wildcard.example.com.crt').read(),
'apache-key': open('wildcard.example.com.key').read(), 'apache-key': open('wildcard.example.com.key').read(),
'-frontend-quantity': 2, '-frontend-quantity': 2,
...@@ -2392,7 +2456,7 @@ class TestReplicateSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -2392,7 +2456,7 @@ class TestReplicateSlave(SlaveHttpFrontendTestCase, TestDataMixin):
'url': 'http://replicate.example.com', 'url': 'http://replicate.example.com',
'site_url': 'http://replicate.example.com', 'site_url': 'http://replicate.example.com',
'secure_access': 'https://replicate.example.com', 'secure_access': 'https://replicate.example.com',
'public-ipv4': utils.LOCAL_IPV4, 'public-ipv4': LOCAL_IPV4,
} }
) )
...@@ -2400,7 +2464,7 @@ class TestReplicateSlave(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -2400,7 +2464,7 @@ class TestReplicateSlave(SlaveHttpFrontendTestCase, TestDataMixin):
parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path') parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path')
self.assertEqual( self.assertEqual(
utils.der2pem(result.peercert), der2pem(result.peercert),
open('wildcard.example.com.crt').read()) open('wildcard.example.com.crt').read())
self.assertEqualResultJson(result, 'Path', '/test-path') self.assertEqualResultJson(result, 'Path', '/test-path')
...@@ -2430,7 +2494,7 @@ class TestEnableHttp2ByDefaultFalseSlave(SlaveHttpFrontendTestCase, ...@@ -2430,7 +2494,7 @@ class TestEnableHttp2ByDefaultFalseSlave(SlaveHttpFrontendTestCase,
return { return {
'domain': 'example.com', 'domain': 'example.com',
'nginx-domain': 'nginx.example.com', 'nginx-domain': 'nginx.example.com',
'public-ipv4': utils.LOCAL_IPV4, 'public-ipv4': LOCAL_IPV4,
'apache-certificate': open('wildcard.example.com.crt').read(), 'apache-certificate': open('wildcard.example.com.crt').read(),
'apache-key': open('wildcard.example.com.key').read(), 'apache-key': open('wildcard.example.com.key').read(),
'enable-http2-by-default': 'false', 'enable-http2-by-default': 'false',
...@@ -2468,7 +2532,7 @@ class TestEnableHttp2ByDefaultFalseSlave(SlaveHttpFrontendTestCase, ...@@ -2468,7 +2532,7 @@ class TestEnableHttp2ByDefaultFalseSlave(SlaveHttpFrontendTestCase,
'site_url': 'http://enablehttp2default.example.com', 'site_url': 'http://enablehttp2default.example.com',
'secure_access': 'secure_access':
'https://enablehttp2default.example.com', 'https://enablehttp2default.example.com',
'public-ipv4': utils.LOCAL_IPV4, 'public-ipv4': LOCAL_IPV4,
} }
) )
...@@ -2488,7 +2552,7 @@ class TestEnableHttp2ByDefaultFalseSlave(SlaveHttpFrontendTestCase, ...@@ -2488,7 +2552,7 @@ class TestEnableHttp2ByDefaultFalseSlave(SlaveHttpFrontendTestCase,
'site_url': 'http://enablehttp2false.example.com', 'site_url': 'http://enablehttp2false.example.com',
'secure_access': 'secure_access':
'https://enablehttp2false.example.com', 'https://enablehttp2false.example.com',
'public-ipv4': utils.LOCAL_IPV4, 'public-ipv4': LOCAL_IPV4,
} }
) )
...@@ -2508,7 +2572,7 @@ class TestEnableHttp2ByDefaultFalseSlave(SlaveHttpFrontendTestCase, ...@@ -2508,7 +2572,7 @@ class TestEnableHttp2ByDefaultFalseSlave(SlaveHttpFrontendTestCase,
'site_url': 'http://enablehttp2true.example.com', 'site_url': 'http://enablehttp2true.example.com',
'secure_access': 'secure_access':
'https://enablehttp2true.example.com', 'https://enablehttp2true.example.com',
'public-ipv4': utils.LOCAL_IPV4, 'public-ipv4': LOCAL_IPV4,
} }
) )
...@@ -2524,7 +2588,7 @@ class TestEnableHttp2ByDefaultDefaultSlave(SlaveHttpFrontendTestCase, ...@@ -2524,7 +2588,7 @@ class TestEnableHttp2ByDefaultDefaultSlave(SlaveHttpFrontendTestCase,
return { return {
'domain': 'example.com', 'domain': 'example.com',
'nginx-domain': 'nginx.example.com', 'nginx-domain': 'nginx.example.com',
'public-ipv4': utils.LOCAL_IPV4, 'public-ipv4': LOCAL_IPV4,
'apache-certificate': open('wildcard.example.com.crt').read(), 'apache-certificate': open('wildcard.example.com.crt').read(),
'apache-key': open('wildcard.example.com.key').read(), 'apache-key': open('wildcard.example.com.key').read(),
'port': HTTPS_PORT, 'port': HTTPS_PORT,
...@@ -2561,7 +2625,7 @@ class TestEnableHttp2ByDefaultDefaultSlave(SlaveHttpFrontendTestCase, ...@@ -2561,7 +2625,7 @@ class TestEnableHttp2ByDefaultDefaultSlave(SlaveHttpFrontendTestCase,
'site_url': 'http://enablehttp2default.example.com', 'site_url': 'http://enablehttp2default.example.com',
'secure_access': 'secure_access':
'https://enablehttp2default.example.com', 'https://enablehttp2default.example.com',
'public-ipv4': utils.LOCAL_IPV4, 'public-ipv4': LOCAL_IPV4,
} }
) )
...@@ -2581,7 +2645,7 @@ class TestEnableHttp2ByDefaultDefaultSlave(SlaveHttpFrontendTestCase, ...@@ -2581,7 +2645,7 @@ class TestEnableHttp2ByDefaultDefaultSlave(SlaveHttpFrontendTestCase,
'site_url': 'http://enablehttp2false.example.com', 'site_url': 'http://enablehttp2false.example.com',
'secure_access': 'secure_access':
'https://enablehttp2false.example.com', 'https://enablehttp2false.example.com',
'public-ipv4': utils.LOCAL_IPV4, 'public-ipv4': LOCAL_IPV4,
} }
) )
...@@ -2601,7 +2665,7 @@ class TestEnableHttp2ByDefaultDefaultSlave(SlaveHttpFrontendTestCase, ...@@ -2601,7 +2665,7 @@ class TestEnableHttp2ByDefaultDefaultSlave(SlaveHttpFrontendTestCase,
'site_url': 'http://enablehttp2true.example.com', 'site_url': 'http://enablehttp2true.example.com',
'secure_access': 'secure_access':
'https://enablehttp2true.example.com', 'https://enablehttp2true.example.com',
'public-ipv4': utils.LOCAL_IPV4, 'public-ipv4': LOCAL_IPV4,
} }
) )
...@@ -2715,7 +2779,7 @@ class TestMalformedBackenUrlSlave(SlaveHttpFrontendTestCase, ...@@ -2715,7 +2779,7 @@ class TestMalformedBackenUrlSlave(SlaveHttpFrontendTestCase,
return { return {
'domain': 'example.com', 'domain': 'example.com',
'nginx-domain': 'nginx.example.com', 'nginx-domain': 'nginx.example.com',
'public-ipv4': utils.LOCAL_IPV4, 'public-ipv4': LOCAL_IPV4,
'apache-certificate': open('wildcard.example.com.crt').read(), 'apache-certificate': open('wildcard.example.com.crt').read(),
'apache-key': open('wildcard.example.com.key').read(), 'apache-key': open('wildcard.example.com.key').read(),
'port': HTTPS_PORT, 'port': HTTPS_PORT,
...@@ -2768,7 +2832,7 @@ class TestMalformedBackenUrlSlave(SlaveHttpFrontendTestCase, ...@@ -2768,7 +2832,7 @@ class TestMalformedBackenUrlSlave(SlaveHttpFrontendTestCase,
'url': 'http://empty.example.com', 'url': 'http://empty.example.com',
'site_url': 'http://empty.example.com', 'site_url': 'http://empty.example.com',
'secure_access': 'https://empty.example.com', 'secure_access': 'https://empty.example.com',
'public-ipv4': utils.LOCAL_IPV4, 'public-ipv4': LOCAL_IPV4,
} }
) )
...@@ -2776,7 +2840,7 @@ class TestMalformedBackenUrlSlave(SlaveHttpFrontendTestCase, ...@@ -2776,7 +2840,7 @@ class TestMalformedBackenUrlSlave(SlaveHttpFrontendTestCase,
parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path') parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path')
self.assertEqual( self.assertEqual(
utils.der2pem(result.peercert), der2pem(result.peercert),
open('wildcard.example.com.crt').read()) open('wildcard.example.com.crt').read())
self.assertEqual(result.status_code, no_backend_response_code) self.assertEqual(result.status_code, no_backend_response_code)
...@@ -2830,9 +2894,9 @@ class TestDefaultMonitorHttpdPort(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -2830,9 +2894,9 @@ class TestDefaultMonitorHttpdPort(SlaveHttpFrontendTestCase, TestDataMixin):
'monitor-httpd.conf')).read() 'monitor-httpd.conf')).read()
self.assertTrue( self.assertTrue(
'Listen [%s]:8196' % (utils.GLOBAL_IPV6,) in master_monitor_conf) 'Listen [%s]:8196' % (GLOBAL_IPV6,) in master_monitor_conf)
self.assertTrue( self.assertTrue(
'Listen [%s]:8072' % (utils.GLOBAL_IPV6,) in slave_monitor_conf) 'Listen [%s]:8072' % (GLOBAL_IPV6,) in slave_monitor_conf)
class TestQuicEnabled(SlaveHttpFrontendTestCase, TestDataMixin): class TestQuicEnabled(SlaveHttpFrontendTestCase, TestDataMixin):
...@@ -2841,7 +2905,7 @@ class TestQuicEnabled(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -2841,7 +2905,7 @@ class TestQuicEnabled(SlaveHttpFrontendTestCase, TestDataMixin):
return { return {
'domain': 'example.com', 'domain': 'example.com',
'nginx-domain': 'nginx.example.com', 'nginx-domain': 'nginx.example.com',
'public-ipv4': utils.LOCAL_IPV4, 'public-ipv4': LOCAL_IPV4,
'enable-quic': 'true', 'enable-quic': 'true',
'apache-certificate': open('wildcard.example.com.crt').read(), 'apache-certificate': open('wildcard.example.com.crt').read(),
'apache-key': open('wildcard.example.com.key').read(), 'apache-key': open('wildcard.example.com.key').read(),
...@@ -2889,7 +2953,7 @@ class TestQuicEnabled(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -2889,7 +2953,7 @@ class TestQuicEnabled(SlaveHttpFrontendTestCase, TestDataMixin):
'url': 'http://url.example.com', 'url': 'http://url.example.com',
'site_url': 'http://url.example.com', 'site_url': 'http://url.example.com',
'secure_access': 'https://url.example.com', 'secure_access': 'https://url.example.com',
'public-ipv4': utils.LOCAL_IPV4, 'public-ipv4': LOCAL_IPV4,
} }
) )
...@@ -2897,7 +2961,7 @@ class TestQuicEnabled(SlaveHttpFrontendTestCase, TestDataMixin): ...@@ -2897,7 +2961,7 @@ class TestQuicEnabled(SlaveHttpFrontendTestCase, TestDataMixin):
parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path') parameter_dict['domain'], parameter_dict['public-ipv4'], 'test-path')
self.assertEqual( self.assertEqual(
utils.der2pem(result.peercert), der2pem(result.peercert),
open('wildcard.example.com.crt').read()) open('wildcard.example.com.crt').read())
self.assertEqualResultJson(result, 'Path', '/test-path') self.assertEqualResultJson(result, 'Path', '/test-path')
......
TestDefaultMonitorHttpdPort-0/etc/plugin/__init__.py
TestDefaultMonitorHttpdPort-0/etc/plugin/buildout-TestDefaultMonitorHttpdPort-0-status.py
TestDefaultMonitorHttpdPort-0/etc/plugin/check-free-disk-space.py
TestDefaultMonitorHttpdPort-0/etc/plugin/monitor-bootstrap-status.py
TestDefaultMonitorHttpdPort-1/etc/plugin/buildout-TestDefaultMonitorHttpdPort-1-status.py
TestDefaultMonitorHttpdPort-1/etc/plugin/check-free-disk-space.py
TestDefaultMonitorHttpdPort-1/etc/plugin/monitor-bootstrap-status.py
\ No newline at end of file
TestDefaultMonitorHttpdPort-0/etc/promise/check-free-disk-space
TestDefaultMonitorHttpdPort-0/etc/promise/monitor-http-frontend TestDefaultMonitorHttpdPort-0/etc/promise/monitor-http-frontend
TestDefaultMonitorHttpdPort-0/etc/promise/monitor-httpd-listening-on-tcp TestDefaultMonitorHttpdPort-0/etc/promise/monitor-httpd-listening-on-tcp
TestDefaultMonitorHttpdPort-0/etc/promise/promise-monitor-httpd-is-process-older-than-dependency-set TestDefaultMonitorHttpdPort-0/etc/promise/promise-monitor-httpd-is-process-older-than-dependency-set
...@@ -9,7 +8,6 @@ TestDefaultMonitorHttpdPort-1/etc/promise/caddy_frontend_ipv4_https ...@@ -9,7 +8,6 @@ TestDefaultMonitorHttpdPort-1/etc/promise/caddy_frontend_ipv4_https
TestDefaultMonitorHttpdPort-1/etc/promise/caddy_frontend_ipv6_http TestDefaultMonitorHttpdPort-1/etc/promise/caddy_frontend_ipv6_http
TestDefaultMonitorHttpdPort-1/etc/promise/caddy_frontend_ipv6_https TestDefaultMonitorHttpdPort-1/etc/promise/caddy_frontend_ipv6_https
TestDefaultMonitorHttpdPort-1/etc/promise/caddy_ssl_cached TestDefaultMonitorHttpdPort-1/etc/promise/caddy_ssl_cached
TestDefaultMonitorHttpdPort-1/etc/promise/check-free-disk-space
TestDefaultMonitorHttpdPort-1/etc/promise/frontend-caddy-configuration-promise TestDefaultMonitorHttpdPort-1/etc/promise/frontend-caddy-configuration-promise
TestDefaultMonitorHttpdPort-1/etc/promise/monitor-http-frontend TestDefaultMonitorHttpdPort-1/etc/promise/monitor-http-frontend
TestDefaultMonitorHttpdPort-1/etc/promise/monitor-httpd-listening-on-tcp TestDefaultMonitorHttpdPort-1/etc/promise/monitor-httpd-listening-on-tcp
......
TestEnableHttp2ByDefaultDefaultSlave-0/etc/plugin/__init__.py
TestEnableHttp2ByDefaultDefaultSlave-0/etc/plugin/buildout-TestEnableHttp2ByDefaultDefaultSlave-0-status.py
TestEnableHttp2ByDefaultDefaultSlave-0/etc/plugin/check-free-disk-space.py
TestEnableHttp2ByDefaultDefaultSlave-0/etc/plugin/monitor-bootstrap-status.py
TestEnableHttp2ByDefaultDefaultSlave-1/etc/plugin/__init__.py
TestEnableHttp2ByDefaultDefaultSlave-1/etc/plugin/buildout-TestEnableHttp2ByDefaultDefaultSlave-1-status.py
TestEnableHttp2ByDefaultDefaultSlave-1/etc/plugin/check-free-disk-space.py
TestEnableHttp2ByDefaultDefaultSlave-1/etc/plugin/monitor-bootstrap-status.py
\ No newline at end of file
TestEnableHttp2ByDefaultDefaultSlave-0/etc/promise/check-free-disk-space
TestEnableHttp2ByDefaultDefaultSlave-0/etc/promise/monitor-http-frontend TestEnableHttp2ByDefaultDefaultSlave-0/etc/promise/monitor-http-frontend
TestEnableHttp2ByDefaultDefaultSlave-0/etc/promise/monitor-httpd-listening-on-tcp TestEnableHttp2ByDefaultDefaultSlave-0/etc/promise/monitor-httpd-listening-on-tcp
TestEnableHttp2ByDefaultDefaultSlave-0/etc/promise/promise-monitor-httpd-is-process-older-than-dependency-set TestEnableHttp2ByDefaultDefaultSlave-0/etc/promise/promise-monitor-httpd-is-process-older-than-dependency-set
...@@ -9,7 +8,6 @@ TestEnableHttp2ByDefaultDefaultSlave-1/etc/promise/caddy_frontend_ipv4_https ...@@ -9,7 +8,6 @@ TestEnableHttp2ByDefaultDefaultSlave-1/etc/promise/caddy_frontend_ipv4_https
TestEnableHttp2ByDefaultDefaultSlave-1/etc/promise/caddy_frontend_ipv6_http TestEnableHttp2ByDefaultDefaultSlave-1/etc/promise/caddy_frontend_ipv6_http
TestEnableHttp2ByDefaultDefaultSlave-1/etc/promise/caddy_frontend_ipv6_https TestEnableHttp2ByDefaultDefaultSlave-1/etc/promise/caddy_frontend_ipv6_https
TestEnableHttp2ByDefaultDefaultSlave-1/etc/promise/caddy_ssl_cached TestEnableHttp2ByDefaultDefaultSlave-1/etc/promise/caddy_ssl_cached
TestEnableHttp2ByDefaultDefaultSlave-1/etc/promise/check-free-disk-space
TestEnableHttp2ByDefaultDefaultSlave-1/etc/promise/frontend-caddy-configuration-promise TestEnableHttp2ByDefaultDefaultSlave-1/etc/promise/frontend-caddy-configuration-promise
TestEnableHttp2ByDefaultDefaultSlave-1/etc/promise/monitor-http-frontend TestEnableHttp2ByDefaultDefaultSlave-1/etc/promise/monitor-http-frontend
TestEnableHttp2ByDefaultDefaultSlave-1/etc/promise/monitor-httpd-listening-on-tcp TestEnableHttp2ByDefaultDefaultSlave-1/etc/promise/monitor-httpd-listening-on-tcp
......
TestEnableHttp2ByDefaultFalseSlave-0/etc/plugin/__init__.py
TestEnableHttp2ByDefaultFalseSlave-0/etc/plugin/buildout-TestEnableHttp2ByDefaultFalseSlave-0-status.py
TestEnableHttp2ByDefaultFalseSlave-0/etc/plugin/check-free-disk-space.py
TestEnableHttp2ByDefaultFalseSlave-0/etc/plugin/monitor-bootstrap-status.py
TestEnableHttp2ByDefaultFalseSlave-1/etc/plugin/__init__.py
TestEnableHttp2ByDefaultFalseSlave-1/etc/plugin/buildout-TestEnableHttp2ByDefaultFalseSlave-1-status.py
TestEnableHttp2ByDefaultFalseSlave-1/etc/plugin/check-free-disk-space.py
TestEnableHttp2ByDefaultFalseSlave-1/etc/plugin/monitor-bootstrap-status.py
\ No newline at end of file
TestEnableHttp2ByDefaultFalseSlave-0/etc/promise/check-free-disk-space
TestEnableHttp2ByDefaultFalseSlave-0/etc/promise/monitor-http-frontend TestEnableHttp2ByDefaultFalseSlave-0/etc/promise/monitor-http-frontend
TestEnableHttp2ByDefaultFalseSlave-0/etc/promise/monitor-httpd-listening-on-tcp TestEnableHttp2ByDefaultFalseSlave-0/etc/promise/monitor-httpd-listening-on-tcp
TestEnableHttp2ByDefaultFalseSlave-0/etc/promise/promise-monitor-httpd-is-process-older-than-dependency-set TestEnableHttp2ByDefaultFalseSlave-0/etc/promise/promise-monitor-httpd-is-process-older-than-dependency-set
...@@ -9,7 +8,6 @@ TestEnableHttp2ByDefaultFalseSlave-1/etc/promise/caddy_frontend_ipv4_https ...@@ -9,7 +8,6 @@ TestEnableHttp2ByDefaultFalseSlave-1/etc/promise/caddy_frontend_ipv4_https
TestEnableHttp2ByDefaultFalseSlave-1/etc/promise/caddy_frontend_ipv6_http TestEnableHttp2ByDefaultFalseSlave-1/etc/promise/caddy_frontend_ipv6_http
TestEnableHttp2ByDefaultFalseSlave-1/etc/promise/caddy_frontend_ipv6_https TestEnableHttp2ByDefaultFalseSlave-1/etc/promise/caddy_frontend_ipv6_https
TestEnableHttp2ByDefaultFalseSlave-1/etc/promise/caddy_ssl_cached TestEnableHttp2ByDefaultFalseSlave-1/etc/promise/caddy_ssl_cached
TestEnableHttp2ByDefaultFalseSlave-1/etc/promise/check-free-disk-space
TestEnableHttp2ByDefaultFalseSlave-1/etc/promise/frontend-caddy-configuration-promise TestEnableHttp2ByDefaultFalseSlave-1/etc/promise/frontend-caddy-configuration-promise
TestEnableHttp2ByDefaultFalseSlave-1/etc/promise/monitor-http-frontend TestEnableHttp2ByDefaultFalseSlave-1/etc/promise/monitor-http-frontend
TestEnableHttp2ByDefaultFalseSlave-1/etc/promise/monitor-httpd-listening-on-tcp TestEnableHttp2ByDefaultFalseSlave-1/etc/promise/monitor-httpd-listening-on-tcp
......
TestMalformedBackenUrlSlave-0/etc/plugin/__init__.py
TestMalformedBackenUrlSlave-0/etc/plugin/buildout-TestMalformedBackenUrlSlave-0-status.py
TestMalformedBackenUrlSlave-0/etc/plugin/check-free-disk-space.py
TestMalformedBackenUrlSlave-0/etc/plugin/monitor-bootstrap-status.py
TestMalformedBackenUrlSlave-1/etc/plugin/__init__.py
TestMalformedBackenUrlSlave-1/etc/plugin/buildout-TestMalformedBackenUrlSlave-1-status.py
TestMalformedBackenUrlSlave-1/etc/plugin/check-free-disk-space.py
TestMalformedBackenUrlSlave-1/etc/plugin/monitor-bootstrap-status.py
\ No newline at end of file
TestMalformedBackenUrlSlave-0/etc/promise/check-free-disk-space
TestMalformedBackenUrlSlave-0/etc/promise/monitor-http-frontend TestMalformedBackenUrlSlave-0/etc/promise/monitor-http-frontend
TestMalformedBackenUrlSlave-0/etc/promise/monitor-httpd-listening-on-tcp TestMalformedBackenUrlSlave-0/etc/promise/monitor-httpd-listening-on-tcp
TestMalformedBackenUrlSlave-0/etc/promise/promise-monitor-httpd-is-process-older-than-dependency-set TestMalformedBackenUrlSlave-0/etc/promise/promise-monitor-httpd-is-process-older-than-dependency-set
...@@ -9,7 +8,6 @@ TestMalformedBackenUrlSlave-1/etc/promise/caddy_frontend_ipv4_https ...@@ -9,7 +8,6 @@ TestMalformedBackenUrlSlave-1/etc/promise/caddy_frontend_ipv4_https
TestMalformedBackenUrlSlave-1/etc/promise/caddy_frontend_ipv6_http TestMalformedBackenUrlSlave-1/etc/promise/caddy_frontend_ipv6_http
TestMalformedBackenUrlSlave-1/etc/promise/caddy_frontend_ipv6_https TestMalformedBackenUrlSlave-1/etc/promise/caddy_frontend_ipv6_https
TestMalformedBackenUrlSlave-1/etc/promise/caddy_ssl_cached TestMalformedBackenUrlSlave-1/etc/promise/caddy_ssl_cached
TestMalformedBackenUrlSlave-1/etc/promise/check-free-disk-space
TestMalformedBackenUrlSlave-1/etc/promise/frontend-caddy-configuration-promise TestMalformedBackenUrlSlave-1/etc/promise/frontend-caddy-configuration-promise
TestMalformedBackenUrlSlave-1/etc/promise/monitor-http-frontend TestMalformedBackenUrlSlave-1/etc/promise/monitor-http-frontend
TestMalformedBackenUrlSlave-1/etc/promise/monitor-httpd-listening-on-tcp TestMalformedBackenUrlSlave-1/etc/promise/monitor-httpd-listening-on-tcp
......
TestMasterRequest-0/etc/plugin/__init__.py
TestMasterRequest-0/etc/plugin/buildout-TestMasterRequest-0-status.py
TestMasterRequest-0/etc/plugin/check-free-disk-space.py
TestMasterRequest-0/etc/plugin/monitor-bootstrap-status.py
\ No newline at end of file
TestMasterRequest-0/etc/promise/check-free-disk-space
TestMasterRequest-0/etc/promise/monitor-http-frontend TestMasterRequest-0/etc/promise/monitor-http-frontend
TestMasterRequest-0/etc/promise/monitor-httpd-listening-on-tcp TestMasterRequest-0/etc/promise/monitor-httpd-listening-on-tcp
TestMasterRequest-0/etc/promise/promise-monitor-httpd-is-process-older-than-dependency-set TestMasterRequest-0/etc/promise/promise-monitor-httpd-is-process-older-than-dependency-set
......
TestMasterRequestDomain-0/etc/plugin/__init__.py
TestMasterRequestDomain-0/etc/plugin/buildout-TestMasterRequestDomain-0-status.py
TestMasterRequestDomain-0/etc/plugin/check-free-disk-space.py
TestMasterRequestDomain-0/etc/plugin/monitor-bootstrap-status.py
\ No newline at end of file
TestMasterRequestDomain-0/etc/promise/check-free-disk-space
TestMasterRequestDomain-0/etc/promise/monitor-http-frontend TestMasterRequestDomain-0/etc/promise/monitor-http-frontend
TestMasterRequestDomain-0/etc/promise/monitor-httpd-listening-on-tcp TestMasterRequestDomain-0/etc/promise/monitor-httpd-listening-on-tcp
TestMasterRequestDomain-0/etc/promise/promise-monitor-httpd-is-process-older-than-dependency-set TestMasterRequestDomain-0/etc/promise/promise-monitor-httpd-is-process-older-than-dependency-set
......
TestQuicEnabled-0/etc/plugin/__init__.py
TestQuicEnabled-0/etc/plugin/buildout-TestQuicEnabled-0-status.py
TestQuicEnabled-0/etc/plugin/check-free-disk-space.py
TestQuicEnabled-0/etc/plugin/monitor-bootstrap-status.py
TestQuicEnabled-1/etc/plugin/__init__.py
TestQuicEnabled-1/etc/plugin/buildout-TestQuicEnabled-1-status.py
TestQuicEnabled-1/etc/plugin/check-free-disk-space.py
TestQuicEnabled-1/etc/plugin/monitor-bootstrap-status.py
\ No newline at end of file
TestQuicEnabled-0/etc/promise/check-free-disk-space
TestQuicEnabled-0/etc/promise/monitor-http-frontend TestQuicEnabled-0/etc/promise/monitor-http-frontend
TestQuicEnabled-0/etc/promise/monitor-httpd-listening-on-tcp TestQuicEnabled-0/etc/promise/monitor-httpd-listening-on-tcp
TestQuicEnabled-0/etc/promise/promise-monitor-httpd-is-process-older-than-dependency-set TestQuicEnabled-0/etc/promise/promise-monitor-httpd-is-process-older-than-dependency-set
...@@ -9,7 +8,6 @@ TestQuicEnabled-1/etc/promise/caddy_frontend_ipv4_https ...@@ -9,7 +8,6 @@ TestQuicEnabled-1/etc/promise/caddy_frontend_ipv4_https
TestQuicEnabled-1/etc/promise/caddy_frontend_ipv6_http TestQuicEnabled-1/etc/promise/caddy_frontend_ipv6_http
TestQuicEnabled-1/etc/promise/caddy_frontend_ipv6_https TestQuicEnabled-1/etc/promise/caddy_frontend_ipv6_https
TestQuicEnabled-1/etc/promise/caddy_ssl_cached TestQuicEnabled-1/etc/promise/caddy_ssl_cached
TestQuicEnabled-1/etc/promise/check-free-disk-space
TestQuicEnabled-1/etc/promise/frontend-caddy-configuration-promise TestQuicEnabled-1/etc/promise/frontend-caddy-configuration-promise
TestQuicEnabled-1/etc/promise/monitor-http-frontend TestQuicEnabled-1/etc/promise/monitor-http-frontend
TestQuicEnabled-1/etc/promise/monitor-httpd-listening-on-tcp TestQuicEnabled-1/etc/promise/monitor-httpd-listening-on-tcp
......
TestRe6stVerificationUrlDefaultSlave-0/etc/plugin/__init__.py
TestRe6stVerificationUrlDefaultSlave-0/etc/plugin/buildout-TestRe6stVerificationUrlDefaultSlave-0-status.py
TestRe6stVerificationUrlDefaultSlave-0/etc/plugin/check-free-disk-space.py
TestRe6stVerificationUrlDefaultSlave-0/etc/plugin/monitor-bootstrap-status.py
TestRe6stVerificationUrlDefaultSlave-1/etc/plugin/__init__.py
TestRe6stVerificationUrlDefaultSlave-1/etc/plugin/buildout-TestRe6stVerificationUrlDefaultSlave-1-status.py
TestRe6stVerificationUrlDefaultSlave-1/etc/plugin/check-free-disk-space.py
TestRe6stVerificationUrlDefaultSlave-1/etc/plugin/monitor-bootstrap-status.py
\ No newline at end of file
TestRe6stVerificationUrlDefaultSlave-0/etc/promise/check-free-disk-space
TestRe6stVerificationUrlDefaultSlave-0/etc/promise/monitor-http-frontend TestRe6stVerificationUrlDefaultSlave-0/etc/promise/monitor-http-frontend
TestRe6stVerificationUrlDefaultSlave-0/etc/promise/monitor-httpd-listening-on-tcp TestRe6stVerificationUrlDefaultSlave-0/etc/promise/monitor-httpd-listening-on-tcp
TestRe6stVerificationUrlDefaultSlave-0/etc/promise/promise-monitor-httpd-is-process-older-than-dependency-set TestRe6stVerificationUrlDefaultSlave-0/etc/promise/promise-monitor-httpd-is-process-older-than-dependency-set
...@@ -9,7 +8,6 @@ TestRe6stVerificationUrlDefaultSlave-1/etc/promise/caddy_frontend_ipv4_https ...@@ -9,7 +8,6 @@ TestRe6stVerificationUrlDefaultSlave-1/etc/promise/caddy_frontend_ipv4_https
TestRe6stVerificationUrlDefaultSlave-1/etc/promise/caddy_frontend_ipv6_http TestRe6stVerificationUrlDefaultSlave-1/etc/promise/caddy_frontend_ipv6_http
TestRe6stVerificationUrlDefaultSlave-1/etc/promise/caddy_frontend_ipv6_https TestRe6stVerificationUrlDefaultSlave-1/etc/promise/caddy_frontend_ipv6_https
TestRe6stVerificationUrlDefaultSlave-1/etc/promise/caddy_ssl_cached TestRe6stVerificationUrlDefaultSlave-1/etc/promise/caddy_ssl_cached
TestRe6stVerificationUrlDefaultSlave-1/etc/promise/check-free-disk-space
TestRe6stVerificationUrlDefaultSlave-1/etc/promise/frontend-caddy-configuration-promise TestRe6stVerificationUrlDefaultSlave-1/etc/promise/frontend-caddy-configuration-promise
TestRe6stVerificationUrlDefaultSlave-1/etc/promise/monitor-http-frontend TestRe6stVerificationUrlDefaultSlave-1/etc/promise/monitor-http-frontend
TestRe6stVerificationUrlDefaultSlave-1/etc/promise/monitor-httpd-listening-on-tcp TestRe6stVerificationUrlDefaultSlave-1/etc/promise/monitor-httpd-listening-on-tcp
......
TestRe6stVerificationUrlSlave-0/etc/plugin/__init__.py
TestRe6stVerificationUrlSlave-0/etc/plugin/buildout-TestRe6stVerificationUrlSlave-0-status.py
TestRe6stVerificationUrlSlave-0/etc/plugin/check-free-disk-space.py
TestRe6stVerificationUrlSlave-0/etc/plugin/monitor-bootstrap-status.py
TestRe6stVerificationUrlSlave-1/etc/plugin/__init__.py
TestRe6stVerificationUrlSlave-1/etc/plugin/buildout-TestRe6stVerificationUrlSlave-1-status.py
TestRe6stVerificationUrlSlave-1/etc/plugin/check-free-disk-space.py
TestRe6stVerificationUrlSlave-1/etc/plugin/monitor-bootstrap-status.py
\ No newline at end of file
TestRe6stVerificationUrlSlave-0/etc/promise/check-free-disk-space
TestRe6stVerificationUrlSlave-0/etc/promise/monitor-http-frontend TestRe6stVerificationUrlSlave-0/etc/promise/monitor-http-frontend
TestRe6stVerificationUrlSlave-0/etc/promise/monitor-httpd-listening-on-tcp TestRe6stVerificationUrlSlave-0/etc/promise/monitor-httpd-listening-on-tcp
TestRe6stVerificationUrlSlave-0/etc/promise/promise-monitor-httpd-is-process-older-than-dependency-set TestRe6stVerificationUrlSlave-0/etc/promise/promise-monitor-httpd-is-process-older-than-dependency-set
...@@ -9,7 +8,6 @@ TestRe6stVerificationUrlSlave-1/etc/promise/caddy_frontend_ipv4_https ...@@ -9,7 +8,6 @@ TestRe6stVerificationUrlSlave-1/etc/promise/caddy_frontend_ipv4_https
TestRe6stVerificationUrlSlave-1/etc/promise/caddy_frontend_ipv6_http TestRe6stVerificationUrlSlave-1/etc/promise/caddy_frontend_ipv6_http
TestRe6stVerificationUrlSlave-1/etc/promise/caddy_frontend_ipv6_https TestRe6stVerificationUrlSlave-1/etc/promise/caddy_frontend_ipv6_https
TestRe6stVerificationUrlSlave-1/etc/promise/caddy_ssl_cached TestRe6stVerificationUrlSlave-1/etc/promise/caddy_ssl_cached
TestRe6stVerificationUrlSlave-1/etc/promise/check-free-disk-space
TestRe6stVerificationUrlSlave-1/etc/promise/frontend-caddy-configuration-promise TestRe6stVerificationUrlSlave-1/etc/promise/frontend-caddy-configuration-promise
TestRe6stVerificationUrlSlave-1/etc/promise/monitor-http-frontend TestRe6stVerificationUrlSlave-1/etc/promise/monitor-http-frontend
TestRe6stVerificationUrlSlave-1/etc/promise/monitor-httpd-listening-on-tcp TestRe6stVerificationUrlSlave-1/etc/promise/monitor-httpd-listening-on-tcp
......
TestReplicateSlave-0/etc/plugin/__init__.py
TestReplicateSlave-0/etc/plugin/buildout-TestReplicateSlave-0-status.py
TestReplicateSlave-0/etc/plugin/check-free-disk-space.py
TestReplicateSlave-0/etc/plugin/monitor-bootstrap-status.py
TestReplicateSlave-1/etc/plugin/__init__.py
TestReplicateSlave-1/etc/plugin/buildout-TestReplicateSlave-1-status.py
TestReplicateSlave-1/etc/plugin/check-free-disk-space.py
TestReplicateSlave-1/etc/plugin/monitor-bootstrap-status.py
TestReplicateSlave-2/etc/plugin/buildout-TestReplicateSlave-2-status.py
TestReplicateSlave-2/etc/plugin/check-free-disk-space.py
TestReplicateSlave-2/etc/plugin/monitor-bootstrap-status.py
\ No newline at end of file
TestReplicateSlave-0/etc/promise/check-free-disk-space
TestReplicateSlave-0/etc/promise/monitor-http-frontend TestReplicateSlave-0/etc/promise/monitor-http-frontend
TestReplicateSlave-0/etc/promise/monitor-httpd-listening-on-tcp TestReplicateSlave-0/etc/promise/monitor-httpd-listening-on-tcp
TestReplicateSlave-0/etc/promise/promise-monitor-httpd-is-process-older-than-dependency-set TestReplicateSlave-0/etc/promise/promise-monitor-httpd-is-process-older-than-dependency-set
...@@ -9,7 +8,6 @@ TestReplicateSlave-1/etc/promise/caddy_frontend_ipv4_https ...@@ -9,7 +8,6 @@ TestReplicateSlave-1/etc/promise/caddy_frontend_ipv4_https
TestReplicateSlave-1/etc/promise/caddy_frontend_ipv6_http TestReplicateSlave-1/etc/promise/caddy_frontend_ipv6_http
TestReplicateSlave-1/etc/promise/caddy_frontend_ipv6_https TestReplicateSlave-1/etc/promise/caddy_frontend_ipv6_https
TestReplicateSlave-1/etc/promise/caddy_ssl_cached TestReplicateSlave-1/etc/promise/caddy_ssl_cached
TestReplicateSlave-1/etc/promise/check-free-disk-space
TestReplicateSlave-1/etc/promise/frontend-caddy-configuration-promise TestReplicateSlave-1/etc/promise/frontend-caddy-configuration-promise
TestReplicateSlave-1/etc/promise/monitor-http-frontend TestReplicateSlave-1/etc/promise/monitor-http-frontend
TestReplicateSlave-1/etc/promise/monitor-httpd-listening-on-tcp TestReplicateSlave-1/etc/promise/monitor-httpd-listening-on-tcp
...@@ -30,7 +28,6 @@ TestReplicateSlave-2/etc/promise/caddy_frontend_ipv4_https ...@@ -30,7 +28,6 @@ TestReplicateSlave-2/etc/promise/caddy_frontend_ipv4_https
TestReplicateSlave-2/etc/promise/caddy_frontend_ipv6_http TestReplicateSlave-2/etc/promise/caddy_frontend_ipv6_http
TestReplicateSlave-2/etc/promise/caddy_frontend_ipv6_https TestReplicateSlave-2/etc/promise/caddy_frontend_ipv6_https
TestReplicateSlave-2/etc/promise/caddy_ssl_cached TestReplicateSlave-2/etc/promise/caddy_ssl_cached
TestReplicateSlave-2/etc/promise/check-free-disk-space
TestReplicateSlave-2/etc/promise/frontend-caddy-configuration-promise TestReplicateSlave-2/etc/promise/frontend-caddy-configuration-promise
TestReplicateSlave-2/etc/promise/monitor-http-frontend TestReplicateSlave-2/etc/promise/monitor-http-frontend
TestReplicateSlave-2/etc/promise/monitor-httpd-listening-on-tcp TestReplicateSlave-2/etc/promise/monitor-httpd-listening-on-tcp
......
TestSlave-0/etc/plugin/__init__.py
TestSlave-0/etc/plugin/buildout-TestSlave-0-status.py
TestSlave-0/etc/plugin/check-free-disk-space.py
TestSlave-0/etc/plugin/monitor-bootstrap-status.py
TestSlave-1/etc/plugin/__init__.py
TestSlave-1/etc/plugin/buildout-TestSlave-1-status.py
TestSlave-1/etc/plugin/check-free-disk-space.py
TestSlave-1/etc/plugin/monitor-bootstrap-status.py
\ No newline at end of file
TestSlave-0/etc/promise/check-free-disk-space
TestSlave-0/etc/promise/monitor-http-frontend TestSlave-0/etc/promise/monitor-http-frontend
TestSlave-0/etc/promise/monitor-httpd-listening-on-tcp TestSlave-0/etc/promise/monitor-httpd-listening-on-tcp
TestSlave-0/etc/promise/promise-monitor-httpd-is-process-older-than-dependency-set TestSlave-0/etc/promise/promise-monitor-httpd-is-process-older-than-dependency-set
...@@ -9,7 +8,6 @@ TestSlave-1/etc/promise/caddy_frontend_ipv4_https ...@@ -9,7 +8,6 @@ TestSlave-1/etc/promise/caddy_frontend_ipv4_https
TestSlave-1/etc/promise/caddy_frontend_ipv6_http TestSlave-1/etc/promise/caddy_frontend_ipv6_http
TestSlave-1/etc/promise/caddy_frontend_ipv6_https TestSlave-1/etc/promise/caddy_frontend_ipv6_https
TestSlave-1/etc/promise/caddy_ssl_cached TestSlave-1/etc/promise/caddy_ssl_cached
TestSlave-1/etc/promise/check-free-disk-space
TestSlave-1/etc/promise/frontend-caddy-configuration-promise TestSlave-1/etc/promise/frontend-caddy-configuration-promise
TestSlave-1/etc/promise/monitor-http-frontend TestSlave-1/etc/promise/monitor-http-frontend
TestSlave-1/etc/promise/monitor-httpd-listening-on-tcp TestSlave-1/etc/promise/monitor-httpd-listening-on-tcp
......
...@@ -28,35 +28,17 @@ ...@@ -28,35 +28,17 @@
import unittest import unittest
import os import os
import socket import socket
import subprocess
from contextlib import closing from contextlib import closing
import logging import logging
import StringIO import StringIO
import json
from BaseHTTPServer import HTTPServer
from BaseHTTPServer import BaseHTTPRequestHandler
import xmlrpclib import xmlrpclib
import supervisor.xmlrpc
import supervisor.xmlrpc
from erp5.util.testnode.SlapOSControler import SlapOSControler from erp5.util.testnode.SlapOSControler import SlapOSControler
from erp5.util.testnode.ProcessManager import ProcessManager from erp5.util.testnode.ProcessManager import ProcessManager
LOCAL_IPV4 = os.environ['LOCAL_IPV4'] # Utility functions
GLOBAL_IPV6 = os.environ['GLOBAL_IPV6']
def der2pem(der):
certificate, error = subprocess.Popen(
'openssl x509 -inform der'.split(), stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE
).communicate(der)
if error:
raise ValueError(error)
return certificate
def findFreeTCPPort(ip=''): def findFreeTCPPort(ip=''):
"""Find a free TCP port to listen to. """Find a free TCP port to listen to.
""" """
...@@ -66,7 +48,57 @@ def findFreeTCPPort(ip=''): ...@@ -66,7 +48,57 @@ def findFreeTCPPort(ip=''):
return s.getsockname()[1] return s.getsockname()[1]
# TODO:
# - allow requesting multiple instances ?
class SlapOSInstanceTestCase(unittest.TestCase): class SlapOSInstanceTestCase(unittest.TestCase):
"""Install one slapos instance.
This test case install software(s) and request one instance during `setUpClass`
and destroy the instance during `tearDownClass`.
Software Release URL, Instance Software Type and Instance Parameters can be defined
on the class.
All tests from the test class will run with the same instance.
The following class attributes are available:
* `computer_partition`: the computer partition instance, implementing
`slapos.slap.interface.slap.IComputerPartition`.
* `computer_partition_root_path`: the path of the instance root directory.
"""
# Methods to be defined by subclasses.
@classmethod
def getSoftwareURLList(cls):
"""Return URL of software releases to install.
To be defined by subclasses.
"""
raise NotImplementedError()
@classmethod
def getInstanceParameterDict(cls):
"""Return instance parameters
To be defined by subclasses if they need to request instance with specific
parameters.
"""
return {}
@classmethod
def getInstanceSoftwareType(cls):
"""Return software type for instance, default "default"
To be defined by subclasses if they need to request instance with specific
software type.
"""
return "default"
# Utility methods.
def getSupervisorRPCServer(self): def getSupervisorRPCServer(self):
"""Returns a XML-RPC connection to the supervisor used by slapos node """Returns a XML-RPC connection to the supervisor used by slapos node
...@@ -79,30 +111,52 @@ class SlapOSInstanceTestCase(unittest.TestCase): ...@@ -79,30 +111,52 @@ class SlapOSInstanceTestCase(unittest.TestCase):
None, None,
None, None,
# XXX hardcoded socket path # XXX hardcoded socket path
serverurl="unix://{working_directory}/inst/supervisord.socket" serverurl="unix://{working_directory}/inst/supervisord.socket".format(
.format(**self.config))) **self.config)))
# Unittest methods
@classmethod @classmethod
def getSoftwareURLList(cls): def setUpClass(cls):
"""Return URL of software releases to install. """Setup the class, build software and request an instance.
To be defined by subclasses. If you have to override this method, do not forget to call this method on
parent class.
""" """
return [os.path.realpath(os.environ['TEST_SR'])] try:
cls.setUpWorkingDirectory()
cls.setUpConfig()
cls.setUpSlapOSController()
@classmethod cls.runSoftwareRelease()
def getInstanceParameterDict(cls): # XXX instead of "runSoftwareRelease", it would be better to be closer to slapos usage:
"""Return instance parameters # cls.supplySoftwares()
# cls.installSoftwares()
To be defined by subclasses if they need to request instance with specific cls.runComputerPartition()
parameters. # XXX instead of "runComputerPartition", it would be better to be closer to slapos usage:
# cls.requestInstances()
# cls.createInstances()
# cls.requestInstances()
except Exception:
cls.stopSlapOSProcesses()
raise
@classmethod
def tearDownClass(cls):
"""Tear down class, stop the processes and destroy instance.
""" """
return {} cls.stopSlapOSProcesses()
# TODO: allow subclasses to request a specific software type ? # Implementation
@classmethod
def stopSlapOSProcesses(cls):
if hasattr(cls, '_process_manager'):
cls._process_manager.killPreviousRun()
@classmethod @classmethod
def setUpWorkingDirectory(cls): def setUpWorkingDirectory(cls):
"""Initialise the directories"""
cls.working_directory = os.environ.get( cls.working_directory = os.environ.get(
'SLAPOS_TEST_WORKING_DIR', 'SLAPOS_TEST_WORKING_DIR',
os.path.join(os.path.dirname(__file__), '.slapos')) os.path.join(os.path.dirname(__file__), '.slapos'))
...@@ -110,16 +164,18 @@ class SlapOSInstanceTestCase(unittest.TestCase): ...@@ -110,16 +164,18 @@ class SlapOSInstanceTestCase(unittest.TestCase):
# AF_UNIX path too long This `working_directory` should not be too deep. # AF_UNIX path too long This `working_directory` should not be too deep.
# Socket path is 108 char max on linux # Socket path is 108 char max on linux
# https://github.com/torvalds/linux/blob/3848ec5/net/unix/af_unix.c#L234-L238 # https://github.com/torvalds/linux/blob/3848ec5/net/unix/af_unix.c#L234-L238
# Supervisord socket name contains the pid number, which is why we add
# .xxxxxxx in this check.
if len(cls.working_directory + '/inst/supervisord.socket.xxxxxxx') > 108: if len(cls.working_directory + '/inst/supervisord.socket.xxxxxxx') > 108:
raise RuntimeError( raise RuntimeError('working directory ( {} ) is too deep, try setting '
'working directory ( {} ) is too deep, try setting ' 'SLAPOS_TEST_WORKING_DIR'.format(cls.working_directory))
'SLAPOS_TEST_WORKING_DIR'.format(cls.working_directory))
if not os.path.exists(cls.working_directory): if not os.path.exists(cls.working_directory):
os.mkdir(cls.working_directory) os.mkdir(cls.working_directory)
@classmethod @classmethod
def setUpConfig(cls): def setUpConfig(cls):
"""Create slapos configuration"""
cls.config = { cls.config = {
"working_directory": cls.working_directory, "working_directory": cls.working_directory,
"slapos_directory": cls.working_directory, "slapos_directory": cls.working_directory,
...@@ -130,7 +186,8 @@ class SlapOSInstanceTestCase(unittest.TestCase): ...@@ -130,7 +186,8 @@ class SlapOSInstanceTestCase(unittest.TestCase):
# "proper" slapos command must be in $PATH # "proper" slapos command must be in $PATH
'slapos_binary': 'slapos', 'slapos_binary': 'slapos',
} }
ipv4_address = LOCAL_IPV4 # Some tests are expecting that local IP is not set to 127.0.0.1
ipv4_address = os.environ.get('LOCAL_IPV4', '127.0.1.1')
ipv6_address = os.environ['GLOBAL_IPV6'] ipv6_address = os.environ['GLOBAL_IPV6']
cls.config['proxy_host'] = cls.config['ipv4_address'] = ipv4_address cls.config['proxy_host'] = cls.config['ipv4_address'] = ipv4_address
...@@ -141,6 +198,15 @@ class SlapOSInstanceTestCase(unittest.TestCase): ...@@ -141,6 +198,15 @@ class SlapOSInstanceTestCase(unittest.TestCase):
@classmethod @classmethod
def setUpSlapOSController(cls): def setUpSlapOSController(cls):
"""Create the a "slapos controller" and supply softwares from `getSoftwareURLList`.
This is equivalent to:
slapos proxy start
for sr in getSoftwareURLList; do
slapos supply $SR $COMP
done
"""
cls._process_manager = ProcessManager() cls._process_manager = ProcessManager()
# XXX this code is copied from testnode code # XXX this code is copied from testnode code
...@@ -160,12 +226,21 @@ class SlapOSInstanceTestCase(unittest.TestCase): ...@@ -160,12 +226,21 @@ class SlapOSInstanceTestCase(unittest.TestCase):
reset_software=False, reset_software=False,
software_path_list=cls.software_url_list) software_path_list=cls.software_url_list)
# XXX we should check *earlier* if that pidfile exist and if supervisord
# process still running, because if developer started supervisord (or bugs?)
# then another supervisord will start and starting services a second time
# will fail.
cls._process_manager.supervisord_pid_file = os.path.join( cls._process_manager.supervisord_pid_file = os.path.join(
cls.slapos_controler.instance_root, 'var', 'run', 'supervisord.pid') cls.slapos_controler.instance_root, 'var', 'run', 'supervisord.pid')
@classmethod @classmethod
def runSoftwareRelease(cls): def runSoftwareRelease(cls):
"""Run all the software releases that were supplied before.
This is the equivalent of `slapos node software`.
The tests will be marked file if software building fail.
"""
logger = logging.getLogger() logger = logging.getLogger()
logger.level = logging.DEBUG logger.level = logging.DEBUG
stream = StringIO.StringIO() stream = StringIO.StringIO()
...@@ -183,14 +258,29 @@ class SlapOSInstanceTestCase(unittest.TestCase): ...@@ -183,14 +258,29 @@ class SlapOSInstanceTestCase(unittest.TestCase):
logger.removeHandler(stream_handler) logger.removeHandler(stream_handler)
del stream del stream
@classmethod @classmethod
def runComputerPartition(cls): def runComputerPartition(cls):
"""Instanciate the software.
This is the equivalent of doing:
slapos request --type=getInstanceSoftwareType --parameters=getInstanceParameterDict
slapos node instance
and return the slapos request instance parameters.
This can be called by tests to simulate re-request with different parameters.
"""
logger = logging.getLogger() logger = logging.getLogger()
logger.level = logging.DEBUG logger.level = logging.DEBUG
stream = StringIO.StringIO() stream = StringIO.StringIO()
stream_handler = logging.StreamHandler(stream) stream_handler = logging.StreamHandler(stream)
logger.addHandler(stream_handler) logger.addHandler(stream_handler)
if cls.getInstanceSoftwareType() != 'default':
raise NotImplementedError
instance_parameter_dict = cls.getInstanceParameterDict() instance_parameter_dict = cls.getInstanceParameterDict()
try: try:
cls.instance_status_dict = cls.slapos_controler.runComputerPartition( cls.instance_status_dict = cls.slapos_controler.runComputerPartition(
...@@ -221,53 +311,11 @@ class SlapOSInstanceTestCase(unittest.TestCase): ...@@ -221,53 +311,11 @@ class SlapOSInstanceTestCase(unittest.TestCase):
# the ComputerPartition instances, to getInstanceParameterDict # the ComputerPartition instances, to getInstanceParameterDict
cls.computer_partition = computer_partition_list[0] cls.computer_partition = computer_partition_list[0]
# expose instance directory
cls.instance_path = os.path.join(
cls.config['working_directory'],
'inst')
# the path of the instance on the filesystem, for low level inspection # the path of the instance on the filesystem, for low level inspection
cls.computer_partition_root_path = os.path.join( cls.computer_partition_root_path = os.path.join(
cls.instance_path, cls.config['working_directory'],
'inst',
cls.computer_partition.getId()) cls.computer_partition.getId())
# expose software directory, extract from found computer partition
cls.software_path = os.path.realpath(os.path.join(
cls.computer_partition_root_path, 'software_release'))
@classmethod
def setUpClass(cls):
try:
cls.setUpWorkingDirectory()
cls.setUpConfig()
cls.setUpSlapOSController()
cls.runSoftwareRelease()
cls.runComputerPartition()
except Exception:
cls.tearDownClass()
raise
@classmethod
def tearDownClass(cls):
if getattr(cls, '_process_manager', None) is not None:
cls._process_manager.killPreviousRun()
class TestHandler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header("Content-type", "application/json")
self.send_header('Set-Cookie', 'secured=value;secure')
self.send_header('Set-Cookie', 'nonsecured=value')
self.end_headers()
response = {
'Path': self.path,
'Incoming Headers': self.headers.dict
}
self.wfile.write(json.dumps(response, indent=2))
if __name__ == '__main__':
ip = LOCAL_IPV4
port = 8888
server = HTTPServer((ip, port), TestHandler)
print 'http://%s:%s' % server.server_address
server.serve_forever()
...@@ -5,22 +5,28 @@ ...@@ -5,22 +5,28 @@
"title": "Input Parameters", "title": "Input Parameters",
"properties": { "properties": {
"server-port": { "server-port": {
"allOf": [{ "allOf": [
"$ref": "#/definitions/tcpv4port" {
}, { "$ref": "#/definitions/tcpv4port"
"title": "http port to use", },
"description": "Caucase http port to use.", {
"default": 8009 "title": "http port to use",
}] "description": "Caucase http port to use.",
"default": 8009
}
]
}, },
"server-https-port": { "server-https-port": {
"allOf": [{ "allOf": [
"$ref": "#/definitions/tcpv4port" {
}, { "$ref": "#/definitions/tcpv4port"
"title": "https port to use", },
"description": "Caucase port to use for https connexion.", {
"default": 8010 "title": "https port to use",
}] "description": "Caucase port to use for https connexion.",
"default": 8010
}
]
}, },
"external-url": { "external-url": {
"title": "External http url", "title": "External http url",
...@@ -73,4 +79,4 @@ ...@@ -73,4 +79,4 @@
"type": "integer" "type": "integer"
} }
} }
} }
\ No newline at end of file
{ {
"name": "Caucase", "name": "Caucase",
"description": "Caucase certificate authority", "description": "Caucase certificate authority",
"serialisation": "json-in-xml", "serialisation": "json-in-xml",
"software-type": { "software-type": {
"default": { "default": {
"title": "Default", "title": "Default",
"description": "Single caucase instance", "description": "Single caucase instance",
"request": "instance-caucase-input-schema.json", "request": "instance-caucase-input-schema.json",
"response": "instance-caucase-output-schema.json", "response": "instance-caucase-output-schema.json",
"index": 0 "index": 0
}
} }
} }
\ No newline at end of file }
{ {
"type": "object", "type": "object",
"$schema": "http://json-schema.org/draft-04/schema", "$schema": "http://json-schema.org/draft-04/schema",
"title": "Input Parameters", "title": "Input Parameters",
"properties": { "properties": {
"port": { "port": {
...@@ -16,36 +15,35 @@ ...@@ -16,36 +15,35 @@
"type": "string", "type": "string",
"pattern": "^([a-zA-Z0-9]([a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,6}$" "pattern": "^([a-zA-Z0-9]([a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,6}$"
}, },
"frontend-server-alias": { "frontend-server-alias": {
"title": "Server Alias", "title": "Server Alias",
"description": "Server Alias List separated by space", "description": "Server Alias List separated by space",
"type": "string", "type": "string",
"default": "" "default": ""
}, },
"frontend-type": { "frontend-type": {
"title": "Backend Type", "title": "Backend Type",
"description": "Type of slave. If redirect, the slave will redirect to the given url. If zope, the rewrite rules will be compatible with Virtual Host Monster", "description": "Type of slave. If redirect, the slave will redirect to the given url. If zope, the rewrite rules will be compatible with Virtual Host Monster",
"type": "string", "type": "string",
"default": "", "default": "",
"enum": ["", "zope", "redirect"] "enum": [
"",
"zope",
"redirect"
]
}, },
"frontend-path": { "frontend-path": {
"title": "Backend Path", "title": "Backend Path",
"description": "Path to proxy to in the backend", "description": "Path to proxy to in the backend",
"type": "string", "type": "string",
"default": "" "default": ""
}, },
"frontend-default-path": { "frontend-default-path": {
"title": "Default Path", "title": "Default Path",
"description": "Provide default path to redirect user to", "description": "Provide default path to redirect user to",
"type": "string", "type": "string",
"default": "" "default": ""
}, },
"frontend-ssl_crt": { "frontend-ssl_crt": {
"title": "SSL Certificate", "title": "SSL Certificate",
"description": "SSL Certificate", "description": "SSL Certificate",
...@@ -60,7 +58,6 @@ ...@@ -60,7 +58,6 @@
"textarea": true, "textarea": true,
"default": "" "default": ""
}, },
"frontend-ssl_ca_crt": { "frontend-ssl_ca_crt": {
"title": "SSL Certificate Authority's Certificate", "title": "SSL Certificate Authority's Certificate",
"description": "SSL Key", "description": "SSL Key",
...@@ -74,14 +71,12 @@ ...@@ -74,14 +71,12 @@
"type": "boolean", "type": "boolean",
"default": false "default": false
}, },
"frontend-ssl-proxy-verify": { "frontend-ssl-proxy-verify": {
"title": "Verify Backend Certificates", "title": "Verify Backend Certificates",
"description": "If set to true, Backend Certificates are checked", "description": "If set to true, Backend Certificates are checked",
"type": "boolean", "type": "boolean",
"default": false "default": false
}, },
"frontend-ssl_proxy_ca_crt": { "frontend-ssl_proxy_ca_crt": {
"title": "SSL Backend Authority's Certificate", "title": "SSL Backend Authority's Certificate",
"description": "SSL Certificate Authority of the backen (to be used with ssl-proxy-verify)", "description": "SSL Certificate Authority of the backen (to be used with ssl-proxy-verify)",
...@@ -89,35 +84,30 @@ ...@@ -89,35 +84,30 @@
"textarea": true, "textarea": true,
"default": "" "default": ""
}, },
"frontend-enable_cache": { "frontend-enable_cache": {
"title": "Enable Cache", "title": "Enable Cache",
"description": "If set to true, the cache is used", "description": "If set to true, the cache is used",
"type": "boolean", "type": "boolean",
"default": false "default": false
}, },
"frontend-disable-no-cache-request": { "frontend-disable-no-cache-request": {
"title": "Disable 'no-cache' requests", "title": "Disable 'no-cache' requests",
"description": "If set to true, no-cache control headers will be disabled", "description": "If set to true, no-cache control headers will be disabled",
"type": "boolean", "type": "boolean",
"default": false "default": false
}, },
"frontend-disable-via-header": { "frontend-disable-via-header": {
"title": "Disable 'Via' headers from cache", "title": "Disable 'Via' headers from cache",
"description": "If set to true, via headers will be disabled", "description": "If set to true, via headers will be disabled",
"type": "boolean", "type": "boolean",
"default": false "default": false
}, },
"frontend-prefer-gzip-encoding-to-backend": { "frontend-prefer-gzip-encoding-to-backend": {
"title": "Prefer gzip Encoding for Backend", "title": "Prefer gzip Encoding for Backend",
"description": "If set to true, if a request is made with accept encoding 'gzip', only that one will be transferred to the backend", "description": "If set to true, if a request is made with accept encoding 'gzip', only that one will be transferred to the backend",
"type": "boolean", "type": "boolean",
"default": false "default": false
}, },
"frontend-disabled-cookie-list": { "frontend-disabled-cookie-list": {
"title": "Disabled Cookies", "title": "Disabled Cookies",
"description": "List of Cookies separated by space that will not be sent to the backend", "description": "List of Cookies separated by space that will not be sent to the backend",
......
{ {
"type": "object", "type": "object",
"$schema": "http://json-schema.org/draft-04/schema", "$schema": "http://json-schema.org/draft-04/schema",
"title": "Input Parameters", "title": "Input Parameters",
"properties": { "properties": {
"port": { "port": {
...@@ -16,43 +15,41 @@ ...@@ -16,43 +15,41 @@
"type": "string", "type": "string",
"pattern": "^([a-zA-Z0-9]([a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,6}$" "pattern": "^([a-zA-Z0-9]([a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,6}$"
}, },
"frontend-server-alias": { "frontend-server-alias": {
"title": "Server Alias", "title": "Server Alias",
"description": "Server Alias List separated by space", "description": "Server Alias List separated by space",
"type": "string", "type": "string",
"default": "" "default": ""
}, },
"frontend-type": { "frontend-type": {
"title": "Backend Type", "title": "Backend Type",
"description": "Type of slave. If redirect, the slave will redirect to the given url. If zope, the rewrite rules will be compatible with Virtual Host Monster", "description": "Type of slave. If redirect, the slave will redirect to the given url. If zope, the rewrite rules will be compatible with Virtual Host Monster",
"type": "string", "type": "string",
"default": "", "default": "",
"enum": ["", "zope", "redirect"] "enum": [
"",
"zope",
"redirect"
]
}, },
"frontend-path": { "frontend-path": {
"title": "Backend Path", "title": "Backend Path",
"description": "Path to proxy to in the backend", "description": "Path to proxy to in the backend",
"type": "string", "type": "string",
"default": "" "default": ""
}, },
"frontend-default-path": { "frontend-default-path": {
"title": "Default Path", "title": "Default Path",
"description": "Provide default path to redirect user to", "description": "Provide default path to redirect user to",
"type": "string", "type": "string",
"default": "" "default": ""
}, },
"frontend-https-only": { "frontend-https-only": {
"title": "HTTPS Only", "title": "HTTPS Only",
"description": "If set to true, http request are redirect to https", "description": "If set to true, http request are redirect to https",
"type": "boolean", "type": "boolean",
"default": false "default": false
}, },
"frontend-enable_cache": { "frontend-enable_cache": {
"title": "Enable Cache", "title": "Enable Cache",
"description": "If set to true, the cache is used", "description": "If set to true, the cache is used",
......
{ {
"name": "CDN ME", "name": "CDN ME",
"description": "CDN ME", "description": "CDN ME",
"serialisation": "xml", "serialisation": "xml",
"software-type": { "software-type": {
"default": { "default": {
"title": "Default", "title": "Default",
"description": "Re6st registry", "description": "Re6st registry",
"request": "instance-cdn-me-simplified-input-schema.json", "request": "instance-cdn-me-simplified-input-schema.json",
"response": "instance-cdn-me-output-schema.json", "response": "instance-cdn-me-output-schema.json",
"index": 0 "index": 0
}, },
"default-advanced": { "default-advanced": {
"title": "Default (Advanced Form)", "title": "Default (Advanced Form)",
"software-type": "default", "software-type": "default",
"description": "Re6st registry", "description": "Re6st registry",
"request": "instance-cdn-me-input-schema.json", "request": "instance-cdn-me-input-schema.json",
"response": "instance-cdn-me-output-schema.json", "response": "instance-cdn-me-output-schema.json",
"index": 1 "index": 1
} }
} }
} }
...@@ -3,12 +3,15 @@ ...@@ -3,12 +3,15 @@
"extends": "./schema-definitions.json#", "extends": "./schema-definitions.json#",
"properties": { "properties": {
"tcpv4-port": { "tcpv4-port": {
"allOf": [{ "allOf": [
"$ref": "#/definitions/tcpv4port" {
}, { "$ref": "#/definitions/tcpv4port"
"description": "Start allocating ports at this value, going upward", },
"default": 23000 {
}] "description": "Start allocating ports at this value, going upward",
"default": 23000
}
]
}, },
"backend-count": { "backend-count": {
"description": "Number of backend cloudooo instances", "description": "Number of backend cloudooo instances",
......
{ {
"name": "cloudooo", "name": "cloudooo",
"description": "Clusterised cloudooo", "description": "Clusterised cloudooo",
"serialisation": "xml", "serialisation": "xml",
"software-type": { "software-type": {
"default": { "default": {
"title": "Default", "title": "Default",
"description": "Cloudooo", "description": "Cloudooo",
"request": "instance-cloudooo-input-schema.json", "request": "instance-cloudooo-input-schema.json",
"response": "instance-cloudooo-output-schema.json", "response": "instance-cloudooo-output-schema.json",
"index": 0 "index": 0
}
} }
}
} }
...@@ -7,7 +7,9 @@ ...@@ -7,7 +7,9 @@
"description": "Where to request instances. Each key is a query string for criterions (e.g. \"computer_guid=foo\"), and each value is a list of partition references (note: Zope partitions reference must be prefixed with \"zope-\").", "description": "Where to request instances. Each key is a query string for criterions (e.g. \"computer_guid=foo\"), and each value is a list of partition references (note: Zope partitions reference must be prefixed with \"zope-\").",
"additionalProperties": { "additionalProperties": {
"type": "array", "type": "array",
"items": { "type": "string" }, "items": {
"type": "string"
},
"uniqueItems": true "uniqueItems": true
}, },
"type": "object" "type": "object"
...@@ -89,22 +91,24 @@ ...@@ -89,22 +91,24 @@
"default": "RootSoftwareInstance", "default": "RootSoftwareInstance",
"type": "object" "type": "object"
}, },
"virtualhostroot-http-port": { "virtualhostroot-http-port": {
"description": "Front-end slave http port. Port where http requests to frontend will be redirected.", "description": "Front-end slave http port. Port where http requests to frontend will be redirected.",
"default": 80, "default": 80,
"type": "integer" "type": "integer"
}, },
"virtualhostroot-https-port": { "virtualhostroot-https-port": {
"description": "Front-end slave https port. Port where https requests to frontend will be redirected.", "description": "Front-end slave https port. Port where https requests to frontend will be redirected.",
"default": 443, "default": 443,
"type": "integer" "type": "integer"
} }
}, },
"type": "object" "type": "object"
}, },
"zope-partition-dict": { "zope-partition-dict": {
"description": "Zope layout definition", "description": "Zope layout definition",
"default": {"1": {}}, "default": {
"1": {}
},
"patternProperties": { "patternProperties": {
".*": { ".*": {
"additionalProperties": false, "additionalProperties": false,
...@@ -160,12 +164,15 @@ ...@@ -160,12 +164,15 @@
"type": "string" "type": "string"
}, },
"port-base": { "port-base": {
"allOf": [{ "allOf": [
"$ref": "#/definitions/tcpv4port" {
}, { "$ref": "#/definitions/tcpv4port"
"description": "Start allocating ports at this value. Useful if one needs to make several partitions share the same port range (ie, several partitions bound to a single address)", },
"default": 2200 {
}] "description": "Start allocating ports at this value. Useful if one needs to make several partitions share the same port range (ie, several partitions bound to a single address)",
"default": 2200
}
]
} }
}, },
"type": "object" "type": "object"
...@@ -215,11 +222,14 @@ ...@@ -215,11 +222,14 @@
"description": "Common settings ZEO servers", "description": "Common settings ZEO servers",
"properties": { "properties": {
"tcpv4-port": { "tcpv4-port": {
"allOf": [{ "allOf": [
"$ref": "#/definitions/tcpv4port" {
}, { "$ref": "#/definitions/tcpv4port"
"description": "Start allocating ports at this value, going upward" },
}] {
"description": "Start allocating ports at this value, going upward"
}
]
}, },
"backup-periodicity": { "backup-periodicity": {
"description": "When to backup, specified in the same format as for systemd.time(7) calendar events (years & seconds not supported, DoW & DoM can not be combined). Enter 'never' to disable backups.", "description": "When to backup, specified in the same format as for systemd.time(7) calendar events (years & seconds not supported, DoW & DoM can not be combined). Enter 'never' to disable backups.",
...@@ -237,7 +247,9 @@ ...@@ -237,7 +247,9 @@
"zodb": { "zodb": {
"description": "Zope Object DataBase mountpoints. See https://github.com/zopefoundation/ZODB/blob/3.10/src/ZODB/component.xml for extra options.", "description": "Zope Object DataBase mountpoints. See https://github.com/zopefoundation/ZODB/blob/3.10/src/ZODB/component.xml for extra options.",
"items": { "items": {
"required": ["type"], "required": [
"type"
],
"properties": { "properties": {
"name": { "name": {
"description": "Database name", "description": "Database name",
...@@ -251,14 +263,21 @@ ...@@ -251,14 +263,21 @@
}, },
"type": { "type": {
"description": "Storage type", "description": "Storage type",
"enum": ["zeo", "neo"], "enum": [
"zeo",
"neo"
],
"type": "string" "type": "string"
}, },
"server": { "server": {
"description": "Instantiate a server. If missing, 'storage-dict' must contain the necessary properties to mount the ZODB. For ZEO, the partition reference is 'zodb'. For NEO, they are 'neo-0', 'neo-1', ...", "description": "Instantiate a server. If missing, 'storage-dict' must contain the necessary properties to mount the ZODB. For ZEO, the partition reference is 'zodb'. For NEO, they are 'neo-0', 'neo-1', ...",
"anyOf": [ "anyOf": [
{"$ref": "./instance-zeo-schema.json"}, {
{"$ref": "../neoppod/instance-neo-input-schema.json"} "$ref": "./instance-zeo-schema.json"
},
{
"$ref": "../neoppod/instance-neo-input-schema.json"
}
] ]
}, },
"storage-dict": { "storage-dict": {
...@@ -270,11 +289,15 @@ ...@@ -270,11 +289,15 @@
"type": "boolean" "type": "boolean"
} }
}, },
"additionalProperties": {"type": "string"}, "additionalProperties": {
"type": "string"
},
"type": "object" "type": "object"
} }
}, },
"additionalProperties": {"type": "string"}, "additionalProperties": {
"type": "string"
},
"type": "object" "type": "object"
}, },
"type": "array" "type": "array"
...@@ -311,10 +334,10 @@ ...@@ -311,10 +334,10 @@
"format": "uri" "format": "uri"
}, },
"crl-update-periodicity": { "crl-update-periodicity": {
"title": "Periodicity of CRL update", "title": "Periodicity of CRL update",
"description": "Periodicity of CRL update, in cron format. The CRL will be downloaded from caucase URL and the new content will be saved if there was a change. Everytime a new CRL is writen, Apache reload will be called.", "description": "Periodicity of CRL update, in cron format. The CRL will be downloaded from caucase URL and the new content will be saved if there was a change. Everytime a new CRL is writen, Apache reload will be called.",
"type": "string", "type": "string",
"default": "0 0 * * *" "default": "0 0 * * *"
} }
}, },
"additionalProperties": { "additionalProperties": {
......
...@@ -51,7 +51,7 @@ ...@@ -51,7 +51,7 @@
"mariadb-test-database-list": { "mariadb-test-database-list": {
"description": "Relational database access information", "description": "Relational database access information",
"items": { "items": {
"pattern": "^mysql://", "pattern": "^mysql://",
"type": "string" "type": "string"
}, },
"uniqueItems": true, "uniqueItems": true,
......
{ {
"$schema": "http://json-schema.org/draft-04/schema#", "$schema": "http://json-schema.org/draft-04/schema#",
"required": ["tcpv4-port"], "required": [
"tcpv4-port"
],
"properties": { "properties": {
"tcpv4-port": { "tcpv4-port": {
"allOf": [{ "allOf": [
"$ref": "#/definitions/tcpv4port" {
}, { "$ref": "#/definitions/tcpv4port"
"description": "Start allocating ports at this value, going upward" },
}] {
"description": "Start allocating ports at this value, going upward"
}
]
}, },
"ram-storage-size": { "ram-storage-size": {
"description": "If 0 use disk storage, otherwise use ram and limit data size to this many megabytes", "description": "If 0 use disk storage, otherwise use ram and limit data size to this many megabytes",
......
{ {
"$schema": "http://json-schema.org/draft-04/schema#", "$schema": "http://json-schema.org/draft-04/schema#",
"required": ["tcpv4-port"], "required": [
"tcpv4-port"
],
"properties": { "properties": {
"tcpv4-port": { "tcpv4-port": {
"allOf": [{ "allOf": [
"$ref": "#/definitions/tcpv4port" {
}, { "$ref": "#/definitions/tcpv4port"
"description": "Start allocating ports at this value, going downward" },
}] {
"description": "Start allocating ports at this value, going downward"
}
]
}, },
"database-list": { "database-list": {
"description": "Databases to create and respective user credentials getting all privileges on it", "description": "Databases to create and respective user credentials getting all privileges on it",
"default": [{ "default": [
"name": "erp5", {
"user": "user", "name": "erp5",
"password": "insecure" "user": "user",
}], "password": "insecure"
}
],
"minItems": 1, "minItems": 1,
"items": { "items": {
"required": ["name", "user", "password"], "required": [
"name",
"user",
"password"
],
"properties": { "properties": {
"name": { "name": {
"description": "Database name", "description": "Database name",
...@@ -135,6 +146,5 @@ ...@@ -135,6 +146,5 @@
}, },
"type": "array" "type": "array"
} }
} }
} }
{ {
"$schema": "http://json-schema.org/draft-04/schema#", "$schema": "http://json-schema.org/draft-04/schema#",
"extends": "./schema-definitions.json#", "extends": "./schema-definitions.json#",
"required": ["tcpv4-port"], "required": [
"tcpv4-port"
],
"properties": { "properties": {
"tcpv4-port": { "tcpv4-port": {
"allOf": [{ "allOf": [
"$ref": "#/definitions/tcpv4port" {
}, { "$ref": "#/definitions/tcpv4port"
"description": "Start allocating ports at this value, going upward" },
}] {
"description": "Start allocating ports at this value, going upward"
}
]
}, },
"postmaster": { "postmaster": {
"description": "Mail address to send technical mails to. Non-empty value required for smptd relay service to be deployed. Values will be put in alias-dict as 'postmaster' key (alias-dict takes precedence)", "description": "Mail address to send technical mails to. Non-empty value required for smptd relay service to be deployed. Values will be put in alias-dict as 'postmaster' key (alias-dict takes precedence)",
...@@ -29,7 +34,9 @@ ...@@ -29,7 +34,9 @@
"relay": { "relay": {
"description": "Forward outgoing mails to a specific relay. If enabled, relay must support TLS-encrypted SASL authentication.", "description": "Forward outgoing mails to a specific relay. If enabled, relay must support TLS-encrypted SASL authentication.",
"dependencies": { "dependencies": {
"host": ["sasl-credential"] "host": [
"sasl-credential"
]
}, },
"properties": { "properties": {
"host": { "host": {
......
{ {
"type": "object", "type": "object",
"$schema": "http://json-schema.org/draft-04/schema", "$schema": "http://json-schema.org/draft-04/schema",
"title": "Input Parameters", "title": "Input Parameters",
"properties": { "properties": {
"test-node-title": { "test-node-title": {
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
"description": "Password to access shellinabox.", "description": "Password to access shellinabox.",
"type": "string" "type": "string"
}, },
"url": { "url": {
"description": "IPv6 URL to access the shell in a box.", "description": "IPv6 URL to access the shell in a box.",
"type": "string" "type": "string"
} }
......
{ {
"name": "ERP5 Test Node", "name": "ERP5 Test Node",
"description": "ERP5 Test Node Runner", "description": "ERP5 Test Node Runner",
"serialisation": "xml", "serialisation": "xml",
"software-type": { "software-type": {
"default": { "default": {
"title": "Default", "title": "Default",
"description": "Default setup for ERP5TestNode Instance.", "description": "Default setup for ERP5TestNode Instance.",
"request": "instance-erp5testnode-input-schema.json", "request": "instance-erp5testnode-input-schema.json",
"response": "instance-output-schema.json" "response": "instance-output-schema.json"
} }
} }
} }
...@@ -15,4 +15,4 @@ ...@@ -15,4 +15,4 @@
[template] [template]
filename = instance.cfg filename = instance.cfg
md5sum = 2eba374ea5b7ec6c95a1f79066cfb46b md5sum = a345d46655c3e841c2ecf4e3a0446c8f
...@@ -36,10 +36,9 @@ command-line = ...@@ -36,10 +36,9 @@ command-line =
--source_code_path_list=$${slapos:location}/software/caddy-frontend/test --source_code_path_list=$${slapos:location}/software/caddy-frontend/test
# XXX slapos.cookbook:wrapper does not allow extending env, so we add some default $PATH entries ( not sure they are needed ) # XXX slapos.cookbook:wrapper does not allow extending env, so we add some default $PATH entries ( not sure they are needed )
# PATH=${buildout:bin-directory}:/usr/bin/:/bin/
environment = environment =
PATH=${curl:location}/bin/:${openssl:location}/bin/:/usr/bin/:/bin
LOCAL_IPV4=$${slap-configuration:ipv4-random} LOCAL_IPV4=$${slap-configuration:ipv4-random}
GLOBAL_IPV6=$${slap-configuration:ipv6-random} GLOBAL_IPV6=$${slap-configuration:ipv6-random}
CURL=${curl:location}/bin/curl
SLAPOS_TEST_WORKING_DIR=$${create-directory:working-dir} SLAPOS_TEST_WORKING_DIR=$${create-directory:working-dir}
TEST_SR=${template:test_software_release} TEST_SR=${template:test_software_release}
{ {
"type": "object", "type": "object",
"$schema": "http://json-schema.org/draft-04/schema", "$schema": "http://json-schema.org/draft-04/schema",
"title": "Input Parameters", "title": "Input Parameters",
"properties": { "properties": {
"image-to-test-url": { "image-to-test-url": {
...@@ -23,7 +22,10 @@ ...@@ -23,7 +22,10 @@
"title": "Type of the test.", "title": "Type of the test.",
"type": "string", "type": "string",
"default": "script-from-url", "default": "script-from-url",
"enum" : ["script-from-url", "cloned-playbook"] "enum": [
"script-from-url",
"cloned-playbook"
]
}, },
"script-to-test-url": { "script-to-test-url": {
"title": "Optional URL of script to test, used for test-type=script-from-url.", "title": "Optional URL of script to test, used for test-type=script-from-url.",
...@@ -36,5 +38,9 @@ ...@@ -36,5 +38,9 @@
"type": "string" "type": "string"
} }
}, },
"required": ["image-to-test-url", "image-to-test-md5sum", "test-type"] "required": [
"image-to-test-url",
"image-to-test-md5sum",
"test-type"
]
} }
{ {
"name": "Deploy Test", "name": "Deploy Test",
"description": "Deploy Testing software release", "description": "Deploy Testing software release",
"serialisation": "xml", "serialisation": "xml",
"software-type": { "software-type": {
"default": { "default": {
"title": "Default", "title": "Default",
"description": "Standard ERP5TestNode hooked", "description": "Standard ERP5TestNode hooked",
"request": "instance-input-schema.json", "request": "instance-input-schema.json",
"index": 0 "index": 0
}
} }
}
} }
...@@ -8,11 +8,11 @@ ...@@ -8,11 +8,11 @@
"type": "string" "type": "string"
}, },
"smtp-username": { "smtp-username": {
"description": "Username to connect to SMTP server", "description": "Username to connect to SMTP server",
"type": "string" "type": "string"
}, },
"smtp-password": { "smtp-password": {
"description": "Password to connect to SMTP server", "description": "Password to connect to SMTP server",
"type": "string" "type": "string"
}, },
"smtp-verify-ssl": { "smtp-verify-ssl": {
......
# THIS IS NOT A BUILDOUT FILE, despite purposedly using a compatible syntax.
# The only allowed lines here are (regexes):
# - "^#" comments, copied verbatim
# - "^[" section beginings, copied verbatim
# - lines containing an "=" sign which must fit in the following categorie.
# - "^\s*filename\s*=\s*path\s*$" where "path" is relative to this file
# Copied verbatim.
# - "^\s*hashtype\s*=.*" where "hashtype" is one of the values supported
# by the re-generation script.
# Re-generated.
# - other lines are copied verbatim
# Substitution (${...:...}), extension ([buildout] extends = ...) and
# section inheritance (< = ...) are NOT supported (but you should really
# not need these here).
[instance]
filename = instance.cfg.in
md5sum = 7c907db5f803b03a218b49888a3a3799
[template-nginx-service]
filename = template-nginx-service.sh.in
md5sum = 529532e1240a66bdf39e3cbbef90ba87
[template-nginx-configuration]
filename = template-nginx.cfg.in
md5sum = 9f22db89a2679534aa8fd37dbca86782
[template-runTestSuite]
filename = runTestSuite.in
md5sum = af6985e2192b43b5b1dfd37bb538df72
...@@ -94,8 +94,8 @@ def main(): ...@@ -94,8 +94,8 @@ def main():
firefox_capabilities = webdriver.common.desired_capabilities.DesiredCapabilities.FIREFOX firefox_capabilities = webdriver.common.desired_capabilities.DesiredCapabilities.FIREFOX
firefox_capabilities['marionette'] = True firefox_capabilities['marionette'] = True
browser = webdriver.Firefox(capabilities=firefox_capabilities, browser = webdriver.Firefox(capabilities=firefox_capabilities,
firefox_binary='${firefox:location}/firefox-slapos', firefox_binary='${firefox-wrapper:location}',
executable_path='${firefox:location}/geckodriver') executable_path='${geckodriver:location}')
elif args.target in ['iOS', 'Android']: elif args.target in ['iOS', 'Android']:
# parameters for mobile emulators have different names then parameters for # parameters for mobile emulators have different names then parameters for
# desktop OSes # desktop OSes
......
...@@ -10,6 +10,7 @@ extends = ...@@ -10,6 +10,7 @@ extends =
../../component/nginx/buildout.cfg ../../component/nginx/buildout.cfg
../../component/openssl/buildout.cfg ../../component/openssl/buildout.cfg
../../component/curl/buildout.cfg ../../component/curl/buildout.cfg
./buildout.hash.cfg
parts = parts =
slapos-cookbook slapos-cookbook
...@@ -31,13 +32,6 @@ parts = ...@@ -31,13 +32,6 @@ parts =
[nodejs-output] [nodejs-output]
<= nodejs-8.6.0-output <= nodejs-8.6.0-output
[instance]
recipe = slapos.recipe.template
md5sum = 7c907db5f803b03a218b49888a3a3799
url = ${:_profile_base_location_}/instance.cfg.in
output = ${buildout:directory}/instance.cfg
mode = 0644
[eggs] [eggs]
recipe = zc.recipe.egg recipe = zc.recipe.egg
eggs = eggs =
...@@ -98,26 +92,26 @@ stop-on-error = true ...@@ -98,26 +92,26 @@ stop-on-error = true
command = cd ${uritemplate-repository.git:location} && PATH=${git:location}/bin/:${nodejs:location}/bin/:$PATH ${nodejs:location}/bin/npm install . command = cd ${uritemplate-repository.git:location} && PATH=${git:location}/bin/:${nodejs:location}/bin/:$PATH ${nodejs:location}/bin/npm install .
update-command = ${:command} update-command = ${:command}
[template-nginx-service] [macro-template]
recipe = slapos.recipe.template recipe = slapos.recipe.template
url = ${:_profile_base_location_}/template-nginx-service.sh.in url = ${:_profile_base_location_}/${:filename}
md5sum = 529532e1240a66bdf39e3cbbef90ba87
output = ${buildout:directory}/template-nginx-service.sh.in
mode = 0644 mode = 0644
[instance]
<= macro-template
output = ${buildout:directory}/instance.cfg
[template-nginx-service]
<= macro-template
output = ${buildout:directory}/template-nginx-service.sh.in
[template-nginx-configuration] [template-nginx-configuration]
recipe = slapos.recipe.template <= macro-template
url = ${:_profile_base_location_}/template-nginx.cfg.in
md5sum = 9f22db89a2679534aa8fd37dbca86782
output = ${buildout:directory}/template-nginx.cfg.in output = ${buildout:directory}/template-nginx.cfg.in
mode = 0644
[template-runTestSuite] [template-runTestSuite]
recipe = slapos.recipe.template <= macro-template
url = ${:_profile_base_location_}/runTestSuite.in
md5sum = 2898d62902351e6df9ce887bd98e2ca1
output = ${buildout:directory}/runTestSuite.in output = ${buildout:directory}/runTestSuite.in
mode = 0644
[versions] [versions]
erp5.util = 0.4.51 erp5.util = 0.4.51
......
...@@ -110,14 +110,17 @@ ...@@ -110,14 +110,17 @@
"title": "Scheme of HTTP service into the VM (require: kvm-name).", "title": "Scheme of HTTP service into the VM (require: kvm-name).",
"description": "Say If HTTP service to run/or running into the Virtual Machine will use http or https. Possible values: http, https.", "description": "Say If HTTP service to run/or running into the Virtual Machine will use http or https. Possible values: http, https.",
"type": "string", "type": "string",
"enum": ["http", "https"], "enum": [
"http",
"https"
],
"default": "http" "default": "http"
} }
}, },
"type": "object" "type": "object"
} }
}, },
"type": "object" "type": "object"
} }
}, },
"type": "object" "type": "object"
...@@ -126,20 +129,23 @@ ...@@ -126,20 +129,23 @@
"title": "Restrict all access to VM with firewall.", "title": "Restrict all access to VM with firewall.",
"description": "When Firewall is enabled, this parameter define if only vm of this cluster and authorized sources ip should have access to cluster.", "description": "When Firewall is enabled, this parameter define if only vm of this cluster and authorized sources ip should have access to cluster.",
"type": "string", "type": "string",
"enum": ["on", "off"], "enum": [
"on",
"off"
],
"default": "off" "default": "off"
}, },
"fw-authorized-sources": { "fw-authorized-sources": {
"title": "List of IP/Network address authorized to cluster.", "title": "List of IP/Network address authorized to cluster.",
"description": "When Firewall is enabled, this contain the list of IP address to authorize for access to all VM of this cluster.", "description": "When Firewall is enabled, this contain the list of IP address to authorize for access to all VM of this cluster.",
"type": "array", "type": "array",
"optional": true "optional": true
}, },
"fw-reject-sources": { "fw-reject-sources": {
"title": "List of IP/Network address rejected, if 'Restrict all access' is off.", "title": "List of IP/Network address rejected, if 'Restrict all access' is off.",
"description": "When Firewall is enabled, this contain the list of IP address which should not access to all VM of this cluster.", "description": "When Firewall is enabled, this contain the list of IP address which should not access to all VM of this cluster.",
"type": "array", "type": "array",
"optional": true "optional": true
}, },
"authorized-keys": { "authorized-keys": {
"title": "Public keys for virtual machines.", "title": "Public keys for virtual machines.",
...@@ -158,17 +164,17 @@ ...@@ -158,17 +164,17 @@
"type": "string" "type": "string"
}, },
"monitor-interface-url": { "monitor-interface-url": {
"title": "Monitor Web Interface URL", "title": "Monitor Web Interface URL",
"description": "Give Url of HTML web interface that will be used to render this monitor instance.", "description": "Give Url of HTML web interface that will be used to render this monitor instance.",
"type": "string", "type": "string",
"format": "uri", "format": "uri",
"default": "https://monitor.app.officejs.com" "default": "https://monitor.app.officejs.com"
}, },
"monitor-cors-domains": { "monitor-cors-domains": {
"title": "Monitor CORS domains", "title": "Monitor CORS domains",
"description": "List of cors domains separated with space. Needed for ajax query on this monitor instance from a different domain.", "description": "List of cors domains separated with space. Needed for ajax query on this monitor instance from a different domain.",
"type": "string", "type": "string",
"default": "monitor.app.officejs.com" "default": "monitor.app.officejs.com"
}, },
"kvm-partition-dict": { "kvm-partition-dict": {
"title": "kvm instances definition", "title": "kvm instances definition",
...@@ -187,7 +193,10 @@ ...@@ -187,7 +193,10 @@
"description": "Define if SlapOS should start or stop this VM.", "description": "Define if SlapOS should start or stop this VM.",
"type": "string", "type": "string",
"default": "started", "default": "started",
"enum": ["started", "stopped"] "enum": [
"started",
"stopped"
]
}, },
"enable-device-hotplug": { "enable-device-hotplug": {
"title": "Enable device hotplug mode", "title": "Enable device hotplug mode",
...@@ -237,7 +246,14 @@ ...@@ -237,7 +246,14 @@
"description": "Type of QEMU disk drive, to create.", "description": "Type of QEMU disk drive, to create.",
"type": "string", "type": "string",
"default": "qcow2", "default": "qcow2",
"enum": ["qcow2", "raw", "vdi", "vmdk", "cloop", "qed"] "enum": [
"qcow2",
"raw",
"vdi",
"vmdk",
"cloop",
"qed"
]
}, },
"disk-type": { "disk-type": {
"title": "Disk type", "title": "Disk type",
...@@ -259,14 +275,23 @@ ...@@ -259,14 +275,23 @@
"description": "Disk cache controls how the host cache is used to access block data.", "description": "Disk cache controls how the host cache is used to access block data.",
"type": "string", "type": "string",
"default": "writeback", "default": "writeback",
"enum": ["none", "writeback", "unsafe", "directsync", "writethrough"] "enum": [
"none",
"writeback",
"unsafe",
"directsync",
"writethrough"
]
}, },
"disk-aio": { "disk-aio": {
"title": "Disk aio to use.", "title": "Disk aio to use.",
"description": "Selects between pthread based disk I/O and native Linux AIO.", "description": "Selects between pthread based disk I/O and native Linux AIO.",
"type": "string", "type": "string",
"default": "threads", "default": "threads",
"enum": ["threads", "native"] "enum": [
"threads",
"native"
]
}, },
"cpu-count": { "cpu-count": {
"title": "CPU count", "title": "CPU count",
...@@ -302,7 +327,41 @@ ...@@ -302,7 +327,41 @@
"title": "Use keyboard layout language", "title": "Use keyboard layout language",
"description": "Use keyboard layout language (for example fr for French). Can be usefull with VNC display", "description": "Use keyboard layout language (for example fr for French). Can be usefull with VNC display",
"type": "string", "type": "string",
"enum": ["ar", "da", "de", "de-ch", "en-gb", "en-us", "es", "et", "fi", "fo", "fr", "fr-be", "fr-ca", "fr-ch", "hr", "hu", "is", "it", "ja", "lt", "lv", "mk", "nl", "nl-be", "no", "pl", "pt", "pt-br", "ru", "sl", "sv", "th", "tr"], "enum": [
"ar",
"da",
"de",
"de-ch",
"en-gb",
"en-us",
"es",
"et",
"fi",
"fo",
"fr",
"fr-be",
"fr-ca",
"fr-ch",
"hr",
"hu",
"is",
"it",
"ja",
"lt",
"lv",
"mk",
"nl",
"nl-be",
"no",
"pl",
"pt",
"pt-br",
"ru",
"sl",
"sv",
"th",
"tr"
],
"default": "fr" "default": "fr"
}, },
"nbd-host": { "nbd-host": {
...@@ -366,7 +425,14 @@ ...@@ -366,7 +425,14 @@
"description": "Type of QEMU disk drive, to create.", "description": "Type of QEMU disk drive, to create.",
"type": "string", "type": "string",
"default": "qcow2", "default": "qcow2",
"enum": ["qcow2", "raw", "vdi", "vmdk", "cloop", "qed"] "enum": [
"qcow2",
"raw",
"vdi",
"vmdk",
"cloop",
"qed"
]
}, },
"wipe-disk-ondestroy": { "wipe-disk-ondestroy": {
"title": "Wipe disks when destroy the VM", "title": "Wipe disks when destroy the VM",
......
{ {
"type": "object", "type": "object",
"$schema": "http://json-schema.org/draft-04/schema", "$schema": "http://json-schema.org/draft-04/schema",
"title": "Input Parameters", "title": "Input Parameters",
"properties": { "properties": {
"enable-device-hotplug": { "enable-device-hotplug": {
...@@ -53,31 +52,53 @@ ...@@ -53,31 +52,53 @@
"description": "Type of QEMU disk drive.", "description": "Type of QEMU disk drive.",
"type": "string", "type": "string",
"default": "virtio", "default": "virtio",
"enum": ["ide", "scsi", "sd", "mtd", "floppy", "pflash", "virtio"] "enum": [
"ide",
"scsi",
"sd",
"mtd",
"floppy",
"pflash",
"virtio"
]
}, },
"disk-format": { "disk-format": {
"title": "Type of disk drive to create by QEMU.", "title": "Type of disk drive to create by QEMU.",
"description": "Type of QEMU disk drive, to create.", "description": "Type of QEMU disk drive, to create.",
"type": "string", "type": "string",
"default": "qcow2", "default": "qcow2",
"enum": ["qcow2", "raw", "vdi", "vmdk", "cloop", "qed"] "enum": [
"qcow2",
"raw",
"vdi",
"vmdk",
"cloop",
"qed"
]
}, },
"disk-cache": { "disk-cache": {
"title": "Cache option to use with Disk.", "title": "Cache option to use with Disk.",
"description": "Disk cache controls how the host cache is used to access block data.", "description": "Disk cache controls how the host cache is used to access block data.",
"type": "string", "type": "string",
"default": "writeback", "default": "writeback",
"enum": ["none", "writeback", "unsafe", "directsync", "writethrough"] "enum": [
"none",
"writeback",
"unsafe",
"directsync",
"writethrough"
]
}, },
"disk-aio": { "disk-aio": {
"title": "Disk aio to use.", "title": "Disk aio to use.",
"description": "Selects between pthread based disk I/O and native Linux AIO.", "description": "Selects between pthread based disk I/O and native Linux AIO.",
"type": "string", "type": "string",
"default": "threads", "default": "threads",
"enum": ["threads", "native"] "enum": [
"threads",
"native"
]
}, },
"cpu-count": { "cpu-count": {
"title": "CPU count", "title": "CPU count",
"description": "Number of CPU cores.", "description": "Number of CPU cores.",
...@@ -107,19 +128,55 @@ ...@@ -107,19 +128,55 @@
"description": "Select the emulated CPU model. Ex: SandyBridge,+erms,+smep,+smx,+vmx", "description": "Select the emulated CPU model. Ex: SandyBridge,+erms,+smep,+smx,+vmx",
"type": "string" "type": "string"
}, },
"keyboard-layout-language": { "keyboard-layout-language": {
"title": "Use keyboard layout language", "title": "Use keyboard layout language",
"description": "Use keyboard layout language (for example fr for French). Can be usefull with VNC display", "description": "Use keyboard layout language (for example fr for French). Can be usefull with VNC display",
"type": "string", "type": "string",
"enum": ["ar", "da", "de", "de-ch", "en-gb", "en-us", "es", "et", "fi", "fo", "fr", "fr-be", "fr-ca", "fr-ch", "hr", "hu", "is", "it", "ja", "lt", "lv", "mk", "nl", "nl-be", "no", "pl", "pt", "pt-br", "ru", "sl", "sv", "th", "tr"] "enum": [
"ar",
"da",
"de",
"de-ch",
"en-gb",
"en-us",
"es",
"et",
"fi",
"fo",
"fr",
"fr-be",
"fr-ca",
"fr-ch",
"hr",
"hu",
"is",
"it",
"ja",
"lt",
"lv",
"mk",
"nl",
"nl-be",
"no",
"pl",
"pt",
"pt-br",
"ru",
"sl",
"sv",
"th",
"tr"
]
}, },
"nbd-host": { "nbd-host": {
"title": "NBD hostname", "title": "NBD hostname",
"description": "hostname (or IP) of the NBD server containing the boot image.", "description": "hostname (or IP) of the NBD server containing the boot image.",
"type": "string", "type": "string",
"format": ["host-name", "ip-address", "ipv6"], "format": [
"host-name",
"ip-address",
"ipv6"
],
"default": "debian.nbd.vifib.net" "default": "debian.nbd.vifib.net"
}, },
"nbd-port": { "nbd-port": {
...@@ -130,12 +187,15 @@ ...@@ -130,12 +187,15 @@
"minimum": 1, "minimum": 1,
"maximum": 65535 "maximum": 65535
}, },
"nbd2-host": { "nbd2-host": {
"title": "Second NBD hostname", "title": "Second NBD hostname",
"description": "hostname (or IP) of the second NBD server (containing drivers for example).", "description": "hostname (or IP) of the second NBD server (containing drivers for example).",
"type": "string", "type": "string",
"format": ["host-name", "ip-address", "ipv6"] "format": [
"host-name",
"ip-address",
"ipv6"
]
}, },
"nbd2-port": { "nbd2-port": {
"title": "Second NBD port", "title": "Second NBD port",
...@@ -144,7 +204,6 @@ ...@@ -144,7 +204,6 @@
"minimum": 1, "minimum": 1,
"maximum": 65535 "maximum": 65535
}, },
"virtual-hard-drive-url": { "virtual-hard-drive-url": {
"title": "Existing disk image URL", "title": "Existing disk image URL",
"description": "If specified, will download an existing disk image (qcow2, raw, ...), and will use it as main virtual hard drive. Can be used to download and use an already installed and customized virtual hard drive.", "description": "If specified, will download an existing disk image (qcow2, raw, ...), and will use it as main virtual hard drive. Can be used to download and use an already installed and customized virtual hard drive.",
...@@ -168,7 +227,6 @@ ...@@ -168,7 +227,6 @@
"type": "boolean", "type": "boolean",
"default": true "default": true
}, },
"external-disk-number": { "external-disk-number": {
"title": "Number of additional disk to create for virtual machine", "title": "Number of additional disk to create for virtual machine",
"description": "Specify the number of additional disk to create for virtual machine in data folder of SlapOS Node. Requires instance_storage_home to be configured on SlapOS Node.", "description": "Specify the number of additional disk to create for virtual machine in data folder of SlapOS Node. Requires instance_storage_home to be configured on SlapOS Node.",
...@@ -189,9 +247,15 @@ ...@@ -189,9 +247,15 @@
"description": "Type of QEMU disk drive, to create.", "description": "Type of QEMU disk drive, to create.",
"type": "string", "type": "string",
"default": "qcow2", "default": "qcow2",
"enum": ["qcow2", "raw", "vdi", "vmdk", "cloop", "qed"] "enum": [
"qcow2",
"raw",
"vdi",
"vmdk",
"cloop",
"qed"
]
}, },
"wipe-disk-ondestroy": { "wipe-disk-ondestroy": {
"title": "Wipe disks when destroy the VM", "title": "Wipe disks when destroy the VM",
"description": "Say if disks should be wiped by writing new data over every single bit before delete them. This option is used to securely delete VM disks", "description": "Say if disks should be wiped by writing new data over every single bit before delete them. This option is used to securely delete VM disks",
...@@ -206,7 +270,6 @@ ...@@ -206,7 +270,6 @@
"minimum": 1, "minimum": 1,
"maximum": 5 "maximum": 5
}, },
"use-tap": { "use-tap": {
"title": "Use QEMU TAP network interface", "title": "Use QEMU TAP network interface",
"description": "Use QEMU TAP network interface, might require a bridge on SlapOS Node.", "description": "Use QEMU TAP network interface, might require a bridge on SlapOS Node.",
...@@ -221,7 +284,7 @@ ...@@ -221,7 +284,7 @@
}, },
"nat-rules": { "nat-rules": {
"title": "List of rules for NAT of QEMU user mode network stack.", "title": "List of rules for NAT of QEMU user mode network stack.",
"description": "List of rules for NAT of QEMU user mode network stack, as comma-separated list of ports. For each port specified, it will redirect port x of the VM (example: 80) to the port x + 10000 of the public IPv6 (example: 10080). Defaults to \"22 80 443\". Ignored if \"use-tap\" parameter is enabled.", "description": "List of rules for NAT of QEMU user mode network stack, as comma-separated list of ports (with optional protocol). For each port specified, it will redirect port x of the VM (example: 80, udp:53) to the port x + 10000 of the public IPv6 (example: 10080, udp:10053). Defaults to \"22 80 443\". Ignored if \"use-tap\" parameter is enabled.",
"type": "string" "type": "string"
}, },
"nat-restrict-mode": { "nat-restrict-mode": {
...@@ -237,17 +300,17 @@ ...@@ -237,17 +300,17 @@
"default": false "default": false
}, },
"monitor-interface-url": { "monitor-interface-url": {
"title": "Monitor Web Interface URL", "title": "Monitor Web Interface URL",
"description": "Give Url of HTML web interface that will be used to render this monitor instance.", "description": "Give Url of HTML web interface that will be used to render this monitor instance.",
"type": "string", "type": "string",
"format": "uri", "format": "uri",
"default": "https://monitor.app.officejs.com" "default": "https://monitor.app.officejs.com"
}, },
"monitor-cors-domains": { "monitor-cors-domains": {
"title": "Monitor CORS domains", "title": "Monitor CORS domains",
"description": "List of cors domains separated with space. Needed for ajax query on this monitor instance from a different domain.", "description": "List of cors domains separated with space. Needed for ajax query on this monitor instance from a different domain.",
"type": "string", "type": "string",
"default": "monitor.app.officejs.com" "default": "monitor.app.officejs.com"
}, },
"enable-http-server": { "enable-http-server": {
"title": "Enable local http server", "title": "Enable local http server",
......
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
"format": "uri", "format": "uri",
"require": true "require": true
}, },
"url": { "url": {
"title": "URL", "title": "URL",
"description": "URL used to connect to the service.", "description": "URL used to connect to the service.",
......
{ {
"type": "object", "type": "object",
"$schema": "http://json-schema.org/draft-04/schema", "$schema": "http://json-schema.org/draft-04/schema",
"allOf": [ "allOf": [
{ {
"$ref": "instance-kvm-input-schema.json#/" "$ref": "instance-kvm-input-schema.json#/"
},
{
"properties": {
"resilient-clone-number": {
"title": "Amount of backup(s) to create",
"description": "Amount of backup(s) to create. Each backup consists of a Pull Backup Server and a clone.",
"type": "integer",
"default": 1,
"optional": true
}, },
{ "-sla-0-computer_guid": {
"properties": { "title": "Target computer for main instance",
"resilient-clone-number": { "description": "Target computer GUID for main instance.",
"title": "Amount of backup(s) to create", "type": "string",
"description": "Amount of backup(s) to create. Each backup consists of a Pull Backup Server and a clone.", "optional": true
"type": "integer", },
"default": 1, "-sla-1-computer_guid": {
"optional": true "title": "Target computer for first clone",
}, "description": "Target computer for first clone and PBS.",
"-sla-0-computer_guid": { "type": "string",
"title": "Target computer for main instance", "optional": true
"description": "Target computer GUID for main instance.", },
"type": "string", "-sla-pbs1-computer_guid": {
"optional": true "title": "Target computer for first PBS",
}, "description": "Target computer for first PBS instance.",
"-sla-1-computer_guid": { "type": "string",
"title": "Target computer for first clone", "optional": true
"description": "Target computer for first clone and PBS.", },
"type": "string", "-sla-2-computer_guid": {
"optional": true "title": "Target computer for second clone",
}, "description": "Target computer for second clone and PBS.",
"-sla-pbs1-computer_guid": { "type": "string",
"title": "Target computer for first PBS", "optional": true
"description": "Target computer for first PBS instance.", },
"type": "string", "-sla-pbs2-computer_guid": {
"optional": true "title": "Target computer for second PBS",
}, "description": "Target computer for second PBS instance.",
"-sla-2-computer_guid": { "type": "string",
"title": "Target computer for second clone", "optional": true
"description": "Target computer for second clone and PBS.", },
"type": "string", "resiliency-backup-periodicity": {
"optional": true "title": "Periodicity of backup",
}, "description": "Periodicity of backup, in cron format.",
"-sla-pbs2-computer_guid": { "type": "string",
"title": "Target computer for second PBS", "optional": true
"description": "Target computer for second PBS instance.", },
"type": "string", "remove-backup-older-than": {
"optional": true "title": "Remove backups older than...",
}, "description": "Remove all the backups in PBS that are older than specified value. It should be rdiff-backup-compatible.",
"resiliency-backup-periodicity": { "type": "string",
"title": "Periodicity of backup", "default": "2W",
"description": "Periodicity of backup, in cron format.", "optional": true
"type": "string", },
"optional": true "ignore-known-hosts-file": {
}, "title": "Ignore known_hosts file",
"remove-backup-older-than": { "description": "Set either to fill known_hosts file for ssh or not. Useful if main instance and PBS are using the same IP (slapos proxy, webrunner).",
"title": "Remove backups older than...", "type": "boolean",
"description": "Remove all the backups in PBS that are older than specified value. It should be rdiff-backup-compatible.", "default": false,
"type": "string", "optional": true
"default": "2W",
"optional": true
},
"ignore-known-hosts-file": {
"title": "Ignore known_hosts file",
"description": "Set either to fill known_hosts file for ssh or not. Useful if main instance and PBS are using the same IP (slapos proxy, webrunner).",
"type": "boolean",
"default": false,
"optional": true
}
}
} }
] }
}
]
} }
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
{% set instance_type = slapparameter_dict.get('type', 'standalone') -%} {% set instance_type = slapparameter_dict.get('type', 'standalone') -%}
{% set nat_rule_list = slapparameter_dict.get('nat-rules', '22 80 443') -%} {% set nat_rule_list = slapparameter_dict.get('nat-rules', '22 80 443') -%}
{% set frontend_software_type = 'default' -%} {% set frontend_software_type = 'default' -%}
{% set disk_device_path = slapparameter_dict.get('disk-device-path', None) -%}
{% set extends_list = [] -%} {% set extends_list = [] -%}
{% set part_list = [] -%} {% set part_list = [] -%}
...@@ -633,6 +634,19 @@ keyboard-layout-language = fr ...@@ -633,6 +634,19 @@ keyboard-layout-language = fr
{% endif -%} {% endif -%}
{% if disk_device_path %}
{% do part_list.append('disk-device-permission') -%}
[disk-device-permission]
recipe = slapos.recipe.template:jinja2
template = inline:
{%- raw %}
[{"disk": "{{disk_device_path}}"}]
{% endraw -%}
rendered = ${buildout:directory}/.slapos-disk-permission
context =
raw disk_device_path {{disk_device_path}}
{% endif -%}
[buildout] [buildout]
parts = parts =
certificate-authority certificate-authority
......
...@@ -90,7 +90,7 @@ command = ...@@ -90,7 +90,7 @@ command =
[template] [template]
recipe = slapos.recipe.template recipe = slapos.recipe.template
url = ${:_profile_base_location_}/instance.cfg.in url = ${:_profile_base_location_}/instance.cfg.in
md5sum = 5a17fc127190bbc19361c5ffb10711b3 md5sum = 5a17fc127190bbc19361c5ffb10711b3
output = ${buildout:directory}/template.cfg output = ${buildout:directory}/template.cfg
mode = 0644 mode = 0644
...@@ -99,7 +99,7 @@ recipe = hexagonit.recipe.download ...@@ -99,7 +99,7 @@ recipe = hexagonit.recipe.download
ignore-existing = true ignore-existing = true
url = ${:_profile_base_location_}/instance-kvm.cfg.jinja2 url = ${:_profile_base_location_}/instance-kvm.cfg.jinja2
mode = 644 mode = 644
md5sum = dbf43756c605144f0a3cd829b588d931 md5sum = 0fd548b8cac9278496d9d83dde26d09c
download-only = true download-only = true
on-update = true on-update = true
...@@ -108,7 +108,7 @@ recipe = hexagonit.recipe.download ...@@ -108,7 +108,7 @@ recipe = hexagonit.recipe.download
ignore-existing = true ignore-existing = true
url = ${:_profile_base_location_}/instance-kvm-cluster.cfg.jinja2.in url = ${:_profile_base_location_}/instance-kvm-cluster.cfg.jinja2.in
mode = 644 mode = 644
md5sum = cccabafc001c6df35da95af6bf2ae28e md5sum = cccabafc001c6df35da95af6bf2ae28e
download-only = true download-only = true
on-update = true on-update = true
...@@ -186,7 +186,7 @@ ignore-existing = true ...@@ -186,7 +186,7 @@ ignore-existing = true
url = ${:_profile_base_location_}/template/template-kvm-run.in url = ${:_profile_base_location_}/template/template-kvm-run.in
mode = 644 mode = 644
filename = template-kvm-run.in filename = template-kvm-run.in
md5sum = 887585f23359d136093de42b1ad1d777 md5sum = 0a076a9338ea0c25fa4e7c9369473d8a
download-only = true download-only = true
on-update = true on-update = true
......
{ {
"name": "KVM", "name": "KVM",
"description": "KVM", "description": "KVM",
"serialisation": "xml", "serialisation": "xml",
"software-type": { "software-type": {
"default": { "default": {
"title": "Default", "title": "Default",
"description": "Standalone KVM", "description": "Standalone KVM",
"request": "instance-kvm-input-schema.json", "request": "instance-kvm-input-schema.json",
"response": "instance-kvm-output-schema.json", "response": "instance-kvm-output-schema.json",
"index": 0 "index": 0
}, },
"kvm-resilient": { "kvm-resilient": {
"title": "Resilient", "title": "Resilient",
"description": "Resilient KVM", "description": "Resilient KVM",
"request": "instance-kvm-resilient-input-schema.json", "request": "instance-kvm-resilient-input-schema.json",
"response": "instance-kvm-output-schema.json", "response": "instance-kvm-output-schema.json",
"index": 1 "index": 1
}, },
"kvm-cluster": { "kvm-cluster": {
"title": "Cluster", "title": "Cluster",
"description": "Cluster KVM", "description": "Cluster KVM",
"serialisation": "json-in-xml", "serialisation": "json-in-xml",
"request": "instance-kvm-cluster-input-schema.json", "request": "instance-kvm-cluster-input-schema.json",
"response": "instance-kvm-output-schema.json", "response": "instance-kvm-output-schema.json",
"index": 2 "index": 2
}
} }
}
} }
...@@ -248,9 +248,21 @@ number = -1 ...@@ -248,9 +248,21 @@ number = -1
if use_nat == 'true': if use_nat == 'true':
number += 1 number += 1
rules = 'user,id=lan%s' % number rules = 'user,id=lan%s' % number
if nat_rules: for rule in nat_rules.split():
rules += ',' + ','.join('hostfwd=tcp:%s:%s-:%s' % (listen_ip, proto = 'tcp'
int(port) + 10000, port) for port in nat_rules.split()) rule = rule.split(':')
if len(rule) == 1:
port = int(rule[0])
elif len(rule) == 2:
proto = rule[0]
port = int(rule[1])
rules += ',hostfwd={proto}:{hostaddr}:{hostport}-:{guestport}'.format(
proto=proto,
hostaddr=listen_ip,
hostport=port + 10000,
guestport=port
)
if httpd_port > 0: if httpd_port > 0:
rules += ',guestfwd=tcp:10.0.2.100:80-cmd:%s %s %s' % (netcat_bin, rules += ',guestfwd=tcp:10.0.2.100:80-cmd:%s %s %s' % (netcat_bin,
......
...@@ -2,7 +2,9 @@ ...@@ -2,7 +2,9 @@
"$schema": "http://json-schema.org/draft-04/schema#", "$schema": "http://json-schema.org/draft-04/schema#",
"description": "Parameters to instantiate a NEO cluster. See https://lab.nexedi.com/nexedi/neoppod/blob/master/neo.conf for more information.", "description": "Parameters to instantiate a NEO cluster. See https://lab.nexedi.com/nexedi/neoppod/blob/master/neo.conf for more information.",
"additionalProperties": false, "additionalProperties": false,
"require": ["cluster"], "require": [
"cluster"
],
"properties": { "properties": {
"cluster": { "cluster": {
"description": "Cluster unique identifier. Your last line of defense against mixing up NEO clusters and corrupting your data. Choose a unique value for each of your cluster.", "description": "Cluster unique identifier. Your last line of defense against mixing up NEO clusters and corrupting your data. Choose a unique value for each of your cluster.",
...@@ -30,7 +32,9 @@ ...@@ -30,7 +32,9 @@
"description": "[NEO SR only] Where to request instances. Each key is a query string for criterions (e.g. \"computer_guid=foo\"), and each value is a list of partition references ('node-0', 'node-1', ...). The prefix 'node-' is mandatory and the number must start from 0. The total number of nodes here must be equal to the length of node-list.", "description": "[NEO SR only] Where to request instances. Each key is a query string for criterions (e.g. \"computer_guid=foo\"), and each value is a list of partition references ('node-0', 'node-1', ...). The prefix 'node-' is mandatory and the number must start from 0. The total number of nodes here must be equal to the length of node-list.",
"additionalProperties": { "additionalProperties": {
"type": "array", "type": "array",
"items": { "type": "string" }, "items": {
"type": "string"
},
"uniqueItems": true "uniqueItems": true
}, },
"type": "object" "type": "object"
...@@ -71,14 +75,14 @@ ...@@ -71,14 +75,14 @@
"type": "integer" "type": "integer"
}, },
"data-deduplication": { "data-deduplication": {
"description": "Set the --dedup option for storage nodes.", "description": "Set the --dedup option for storage nodes.",
"default": false, "default": false,
"type": "boolean" "type": "boolean"
}, },
"disable-drop-partitions": { "disable-drop-partitions": {
"description": "Set the --disable-drop-partitions option for storage nodes.", "description": "Set the --disable-drop-partitions option for storage nodes.",
"default": false, "default": false,
"type": "boolean" "type": "boolean"
}, },
"mysql": { "mysql": {
"description": "Dictionary containing parameters for MySQL.", "description": "Dictionary containing parameters for MySQL.",
......
{ {
"type": "object", "type": "object",
"$schema": "http://json-schema.org/draft-04/schema", "$schema": "http://json-schema.org/draft-04/schema",
"title": "Input Parameters", "title": "Input Parameters",
"properties": { "properties": {
"-dns-type": { "-dns-type": {
"title": "DNS Software type", "title": "DNS Software type",
"description": "Software type of DNS nodes", "description": "Software type of DNS nodes",
"default": "single-default", "default": "single-default",
"type": "string" "type": "string"
}, },
"-dns-software-release-url": { "-dns-software-release-url": {
"title": "DNS Software Release", "title": "DNS Software Release",
"description": "Url of the software release to be used for the nodes", "description": "Url of the software release to be used for the nodes",
"default": "", "default": "",
"type": "string" "type": "string"
}, },
"-dns-quantity": { "-dns-quantity": {
"title": "DNS Quantity", "title": "DNS Quantity",
"description": "DNS Nodes Quantity", "description": "DNS Nodes Quantity",
"default": 1, "default": 1,
"type": "integer" "type": "integer"
}, },
"-dns-i-state": { "-dns-i-state": {
"title": "Requested state of node i", "title": "Requested state of node i",
"description": "Requested State of node i of the replication. i must inferior or equal to '-dns-quantity'", "description": "Requested State of node i of the replication. i must inferior or equal to '-dns-quantity'",
"default": "started", "default": "started",
"type": "string" "type": "string"
}, },
"-sla-i-sla_parameter": { "-sla-i-sla_parameter": {
"title": "sla_parameter used to request node i", "title": "sla_parameter used to request node i",
"description": "Parameter used to provide sla parameter to request dns nodes", "description": "Parameter used to provide sla parameter to request dns nodes",
"default": "", "default": "",
"type": "string" "type": "string"
}, },
"zone": { "zone": {
"title": "Zone", "title": "Zone",
"description": "Zone to be handled by the DNS cluster", "description": "Zone to be handled by the DNS cluster",
...@@ -47,33 +40,30 @@ ...@@ -47,33 +40,30 @@
"default": "domain.com", "default": "domain.com",
"pattern": "^([a-zA-Z0-9]([a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,6}$" "pattern": "^([a-zA-Z0-9]([a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,6}$"
}, },
"server-admin": { "server-admin": {
"title": "Zone Administrator Email", "title": "Zone Administrator Email",
"description": "Email of the zone administrator, it is used to generate SOA value", "description": "Email of the zone administrator, it is used to generate SOA value",
"type": "string", "type": "string",
"default": "admin@domain.com" "default": "admin@domain.com"
}, },
"dns-name-template-string": { "dns-name-template-string": {
"title": "DNS domains template string", "title": "DNS domains template string",
"description": "Template used to generate DNS domain name", "description": "Template used to generate DNS domain name",
"type": "string", "type": "string",
"default": "ns%s. + zone" "default": "ns%s. + zone"
}, },
"monitor-interface-url": { "monitor-interface-url": {
"title": "Monitor Web Interface URL", "title": "Monitor Web Interface URL",
"description": "Give Url of HTML web interface that will be used to render this monitor instance.", "description": "Give Url of HTML web interface that will be used to render this monitor instance.",
"type": "string", "type": "string",
"format": "uri", "format": "uri",
"default": "https://monitor.app.officejs.com" "default": "https://monitor.app.officejs.com"
}, },
"monitor-cors-domains": { "monitor-cors-domains": {
"title": "Monitor CORS domains", "title": "Monitor CORS domains",
"description": "List of cors domains separated with space. Needed for ajax query on this monitor instance from a different domain.", "description": "List of cors domains separated with space. Needed for ajax query on this monitor instance from a different domain.",
"type": "string", "type": "string",
"default": "monitor.app.officejs.com" "default": "monitor.app.officejs.com"
} }
} }
} }
{ {
"type": "object", "type": "object",
"$schema": "http://json-schema.org/draft-04/schema", "$schema": "http://json-schema.org/draft-04/schema",
"title": "Input Parameters", "title": "Input Parameters",
"properties": { "properties": {
"record": { "record": {
"title": "Record", "title": "Record",
"description": "Record for the configuration", "description": "Record for the configuration",
"type": "string" "type": "string"
}, },
"origin": { "origin": {
"title": "Origin", "title": "Origin",
"description": "Used to qualify RR in the configuration. i.e.: if your origin is a.example.com and the RR for Europe is 'eu' the european clients will use eu.a.exmple.com", "description": "Used to qualify RR in the configuration. i.e.: if your origin is a.example.com and the RR for Europe is 'eu' the european clients will use eu.a.exmple.com",
"type": "string" "type": "string"
}, },
"default": { "default": {
"title": "Default RR", "title": "Default RR",
"description": "Defautl record to use when the ip is not regognized", "description": "Defautl record to use when the ip is not regognized",
"type": "string" "type": "string"
}, },
"europe": { "europe": {
"title": "Europe RR", "title": "Europe RR",
"description": "Records to use for Europe", "description": "Records to use for Europe",
"default": "eu", "default": "eu",
"type": "string" "type": "string"
}, },
"africa": { "africa": {
"title": "Africa RR", "title": "Africa RR",
"description": "Records to use for Africa", "description": "Records to use for Africa",
"default": "af", "default": "af",
"type": "string" "type": "string"
}, },
"south-america": { "south-america": {
"title": "South America RR", "title": "South America RR",
"description": "Records to use for South America", "description": "Records to use for South America",
"default": "sa", "default": "sa",
"type": "string" "type": "string"
}, },
"north-america": { "north-america": {
"title": "North America RR", "title": "North America RR",
"description": "Records to use for North America", "description": "Records to use for North America",
"default": "na", "default": "na",
"type": "string" "type": "string"
}, },
"china": { "china": {
"title": "China RR", "title": "China RR",
"description": "Records to use for China", "description": "Records to use for China",
"default": "cn", "default": "cn",
"type": "string" "type": "string"
}, },
"japan": { "japan": {
"title": "Japan RR", "title": "Japan RR",
"description": "Records to use for Japan", "description": "Records to use for Japan",
"default": "jp", "default": "jp",
"type": "string" "type": "string"
}, },
"hong-kong": { "hong-kong": {
"title": "Honk Kong RR", "title": "Honk Kong RR",
"description": "Records to use for Hong Kong", "description": "Records to use for Hong Kong",
"default": "hk", "default": "hk",
"type": "string" "type": "string"
}, },
"east-asia": { "east-asia": {
"title": "East Asia RR", "title": "East Asia RR",
"description": "Records to use for East Asia", "description": "Records to use for East Asia",
"default": "as", "default": "as",
"type": "string" "type": "string"
}, },
"west-asia": { "west-asia": {
"title": "West Asia RR", "title": "West Asia RR",
"description": "Records to use for West Asia", "description": "Records to use for West Asia",
"default": "eu", "default": "eu",
"type": "string" "type": "string"
}, },
"oceania": { "oceania": {
"title": "Oceania RR", "title": "Oceania RR",
"description": "Records to use for Oceania", "description": "Records to use for Oceania",
......
...@@ -30,14 +30,15 @@ import os ...@@ -30,14 +30,15 @@ import os
import socket import socket
from contextlib import closing from contextlib import closing
import logging import logging
import StringIO
import xmlrpclib import xmlrpclib
import supervisor.xmlrpc import supervisor.xmlrpc
from erp5.util.testnode.SlapOSControler import SlapOSControler from erp5.util.testnode.SlapOSControler import SlapOSControler
from erp5.util.testnode.ProcessManager import ProcessManager from erp5.util.testnode.ProcessManager import ProcessManager
import slapos
# Utility functions
def findFreeTCPPort(ip=''): def findFreeTCPPort(ip=''):
"""Find a free TCP port to listen to. """Find a free TCP port to listen to.
""" """
...@@ -47,7 +48,30 @@ def findFreeTCPPort(ip=''): ...@@ -47,7 +48,30 @@ def findFreeTCPPort(ip=''):
return s.getsockname()[1] return s.getsockname()[1]
# TODO:
# - allow requesting multiple instances ?
class SlapOSInstanceTestCase(unittest.TestCase): class SlapOSInstanceTestCase(unittest.TestCase):
"""Install one slapos instance.
This test case install software(s) and request one instance during `setUpClass`
and destroy the instance during `tearDownClass`.
Software Release URL, Instance Software Type and Instance Parameters can be defined
on the class.
All tests from the test class will run with the same instance.
The following class attributes are available:
* `computer_partition`: the computer partition instance, implementing
`slapos.slap.interface.slap.IComputerPartition`.
* `computer_partition_root_path`: the path of the instance root directory.
"""
# Methods to be defined by subclasses.
@classmethod @classmethod
def getSoftwareURLList(cls): def getSoftwareURLList(cls):
"""Return URL of software releases to install. """Return URL of software releases to install.
...@@ -65,20 +89,75 @@ class SlapOSInstanceTestCase(unittest.TestCase): ...@@ -65,20 +89,75 @@ class SlapOSInstanceTestCase(unittest.TestCase):
""" """
return {} return {}
# TODO: allow subclasses to request a specific software type ? @classmethod
def getInstanceSoftwareType(cls):
"""Return software type for instance, default "default"
To be defined by subclasses if they need to request instance with specific
software type.
"""
return "default"
# Utility methods.
def getSupervisorRPCServer(self):
"""Returns a XML-RPC connection to the supervisor used by slapos node
Refer to http://supervisord.org/api.html for details of available methods.
"""
# xmlrpc over unix socket https://stackoverflow.com/a/11746051/7294664
return xmlrpclib.ServerProxy(
'http://slapos-supervisor',
transport=supervisor.xmlrpc.SupervisorTransport(
None,
None,
# XXX hardcoded socket path
serverurl="unix://{working_directory}/inst/supervisord.socket".format(
**self.config)))
# Unittest methods
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
"""Setup the class, build software and request an instance.
If you have to override this method, do not forget to call this method on
parent class.
"""
try: try:
cls._setUpClass() cls.setUpWorkingDirectory()
except: cls.setUpConfig()
cls.setUpSlapOSController()
cls.runSoftwareRelease()
# XXX instead of "runSoftwareRelease", it would be better to be closer to slapos usage:
# cls.supplySoftwares()
# cls.installSoftwares()
cls.runComputerPartition()
# XXX instead of "runComputerPartition", it would be better to be closer to slapos usage:
# cls.requestInstances()
# cls.createInstances()
# cls.requestInstances()
except Exception:
cls.stopSlapOSProcesses() cls.stopSlapOSProcesses()
raise raise
@classmethod @classmethod
def _setUpClass(cls): def tearDownClass(cls):
working_directory = os.environ.get( """Tear down class, stop the processes and destroy instance.
"""
cls.stopSlapOSProcesses()
# Implementation
@classmethod
def stopSlapOSProcesses(cls):
if hasattr(cls, '_process_manager'):
cls._process_manager.killPreviousRun()
@classmethod
def setUpWorkingDirectory(cls):
"""Initialise the directories"""
cls.working_directory = os.environ.get(
'SLAPOS_TEST_WORKING_DIR', 'SLAPOS_TEST_WORKING_DIR',
os.path.join(os.path.dirname(__file__), '.slapos')) os.path.join(os.path.dirname(__file__), '.slapos'))
# To prevent error: Cannot open an HTTP server: socket.error reported # To prevent error: Cannot open an HTTP server: socket.error reported
...@@ -87,76 +166,146 @@ class SlapOSInstanceTestCase(unittest.TestCase): ...@@ -87,76 +166,146 @@ class SlapOSInstanceTestCase(unittest.TestCase):
# https://github.com/torvalds/linux/blob/3848ec5/net/unix/af_unix.c#L234-L238 # https://github.com/torvalds/linux/blob/3848ec5/net/unix/af_unix.c#L234-L238
# Supervisord socket name contains the pid number, which is why we add # Supervisord socket name contains the pid number, which is why we add
# .xxxxxxx in this check. # .xxxxxxx in this check.
if len(working_directory + '/inst/supervisord.socket.xxxxxxx') > 108: if len(cls.working_directory + '/inst/supervisord.socket.xxxxxxx') > 108:
raise RuntimeError('working directory ( {} ) is too deep, try setting ' raise RuntimeError('working directory ( {} ) is too deep, try setting '
'SLAPOS_TEST_WORKING_DIR'.format(working_directory)) 'SLAPOS_TEST_WORKING_DIR'.format(cls.working_directory))
if not os.path.exists(working_directory): if not os.path.exists(cls.working_directory):
os.mkdir(working_directory) os.mkdir(cls.working_directory)
cls.config = config = { @classmethod
"working_directory": working_directory, def setUpConfig(cls):
"slapos_directory": working_directory, """Create slapos configuration"""
"log_directory": working_directory, cls.config = {
"computer_id": 'slapos.test', # XXX "working_directory": cls.working_directory,
'proxy_database': os.path.join(working_directory, 'proxy.db'), "slapos_directory": cls.working_directory,
"log_directory": cls.working_directory,
"computer_id": 'slapos.test', # XXX
'proxy_database': os.path.join(cls.working_directory, 'proxy.db'),
'partition_reference': cls.__name__, 'partition_reference': cls.__name__,
# "proper" slapos command must be in $PATH # "proper" slapos command must be in $PATH
'slapos_binary': 'slapos', 'slapos_binary': 'slapos',
} }
# Some tests are expecting that local IP is not set to 127.0.0.1 # Some tests are expecting that local IP is not set to 127.0.0.1
ipv4_address = os.environ.get('LOCAL_IPV4', '127.0.1.1') ipv4_address = os.environ.get('LOCAL_IPV4', '127.0.1.1')
ipv6_address = os.environ['GLOBAL_IPV6'] ipv6_address = os.environ['GLOBAL_IPV6']
config['proxy_host'] = config['ipv4_address'] = ipv4_address cls.config['proxy_host'] = cls.config['ipv4_address'] = ipv4_address
config['ipv6_address'] = ipv6_address cls.config['ipv6_address'] = ipv6_address
config['proxy_port'] = findFreeTCPPort(ipv4_address) cls.config['proxy_port'] = findFreeTCPPort(ipv4_address)
config['master_url'] = 'http://{proxy_host}:{proxy_port}'.format(**config) cls.config['master_url'] = 'http://{proxy_host}:{proxy_port}'.format(
**cls.config)
cls._process_manager = process_manager = ProcessManager() @classmethod
def setUpSlapOSController(cls):
"""Create the a "slapos controller" and supply softwares from `getSoftwareURLList`.
This is equivalent to:
slapos proxy start
for sr in getSoftwareURLList; do
slapos supply $SR $COMP
done
"""
cls._process_manager = ProcessManager()
# XXX this code is copied from testnode code # XXX this code is copied from testnode code
slapos_controler = SlapOSControler( cls.slapos_controler = SlapOSControler(
working_directory, cls.working_directory,
config cls.config
) )
slapproxy_log = os.path.join(config['log_directory'], 'slapproxy.log') slapproxy_log = os.path.join(cls.config['log_directory'], 'slapproxy.log')
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
logger.debug('Configured slapproxy log to %r', slapproxy_log) logger.debug('Configured slapproxy log to %r', slapproxy_log)
software_url_list = cls.getSoftwareURLList() cls.software_url_list = cls.getSoftwareURLList()
slapos_controler.initializeSlapOSControler( cls.slapos_controler.initializeSlapOSControler(
slapproxy_log=slapproxy_log, slapproxy_log=slapproxy_log,
process_manager=process_manager, process_manager=cls._process_manager,
reset_software=False, reset_software=False,
software_path_list=software_url_list) software_path_list=cls.software_url_list)
# XXX we should check *earlier* if that pidfile exist and if supervisord
# process still running, because if developer started supervisord (or bugs?)
# then another supervisord will start and starting services a second time
# will fail.
cls._process_manager.supervisord_pid_file = os.path.join(
cls.slapos_controler.instance_root, 'var', 'run', 'supervisord.pid')
process_manager.supervisord_pid_file = os.path.join( @classmethod
slapos_controler.instance_root, 'var', 'run', 'supervisord.pid') def runSoftwareRelease(cls):
"""Run all the software releases that were supplied before.
This is the equivalent of `slapos node software`.
The tests will be marked file if software building fail.
"""
logger = logging.getLogger()
logger.level = logging.DEBUG
stream = StringIO.StringIO()
stream_handler = logging.StreamHandler(stream)
logger.addHandler(stream_handler)
try:
cls.software_status_dict = cls.slapos_controler.runSoftwareRelease(
cls.config, environment=os.environ)
stream.seek(0)
stream.flush()
message = ''.join(stream.readlines()[-100:])
assert cls.software_status_dict['status_code'] == 0, message
finally:
logger.removeHandler(stream_handler)
del stream
software_status_dict = slapos_controler.runSoftwareRelease(config, environment=os.environ)
# TODO: log more details in this case @classmethod
assert software_status_dict['status_code'] == 0 def runComputerPartition(cls):
"""Instanciate the software.
This is the equivalent of doing:
slapos request --type=getInstanceSoftwareType --parameters=getInstanceParameterDict
slapos node instance
and return the slapos request instance parameters.
This can be called by tests to simulate re-request with different parameters.
"""
logger = logging.getLogger()
logger.level = logging.DEBUG
stream = StringIO.StringIO()
stream_handler = logging.StreamHandler(stream)
logger.addHandler(stream_handler)
if cls.getInstanceSoftwareType() != 'default':
raise NotImplementedError
instance_parameter_dict = cls.getInstanceParameterDict() instance_parameter_dict = cls.getInstanceParameterDict()
instance_status_dict = slapos_controler.runComputerPartition( try:
config, cls.instance_status_dict = cls.slapos_controler.runComputerPartition(
cls.config,
cluster_configuration=instance_parameter_dict, cluster_configuration=instance_parameter_dict,
environment=os.environ) environment=os.environ)
# TODO: log more details in this case stream.seek(0)
assert instance_status_dict['status_code'] == 0 stream.flush()
message = ''.join(stream.readlines()[-100:])
# FIXME: similar to test node, only one (root) partition is really supported for now. assert cls.instance_status_dict['status_code'] == 0, message
finally:
logger.removeHandler(stream_handler)
del stream
# FIXME: similar to test node, only one (root) partition is really
# supported for now.
computer_partition_list = [] computer_partition_list = []
for i in range(len(software_url_list)): for i in range(len(cls.software_url_list)):
computer_partition_list.append( computer_partition_list.append(
slapos_controler.slap.registerOpenOrder().request( cls.slapos_controler.slap.registerOpenOrder().request(
software_url_list[i], cls.software_url_list[i],
# This is how testnode's SlapOSControler name created partitions # This is how testnode's SlapOSControler name created partitions
partition_reference='testing partition {i}'.format(i=i, **config), partition_reference='testing partition {i}'.format(
partition_parameter_kw=instance_parameter_dict)) i=i, **cls.config),
partition_parameter_kw=instance_parameter_dict))
# expose some class attributes so that tests can use them: # expose some class attributes so that tests can use them:
# the ComputerPartition instances, to getInstanceParameterDict # the ComputerPartition instances, to getInstanceParameterDict
...@@ -164,31 +313,9 @@ class SlapOSInstanceTestCase(unittest.TestCase): ...@@ -164,31 +313,9 @@ class SlapOSInstanceTestCase(unittest.TestCase):
# the path of the instance on the filesystem, for low level inspection # the path of the instance on the filesystem, for low level inspection
cls.computer_partition_root_path = os.path.join( cls.computer_partition_root_path = os.path.join(
config['working_directory'], cls.config['working_directory'],
'inst', 'inst',
cls.computer_partition.getId()) cls.computer_partition.getId())
@classmethod
def stopSlapOSProcesses(cls):
if hasattr(cls, '_process_manager'):
cls._process_manager.killPreviousRun()
@classmethod
def tearDownClass(cls):
cls.stopSlapOSProcesses()
# utility methods
def getSupervisorRPCServer(self):
"""Returns a XML-RPC connection to the supervisor used by slapos node
Refer to http://supervisord.org/api.html for details of available methods.
"""
# xmlrpc over unix socket https://stackoverflow.com/a/11746051/7294664
return xmlrpclib.ServerProxy(
'http://slapos-supervisor',
transport=supervisor.xmlrpc.SupervisorTransport(
None,
None,
# XXX hardcoded socket path
serverurl="unix://{working_directory}/inst/supervisord.socket".format(**self.config)))
{ {
"$schema": "http://json-schema.org/draft-04/schema#", "$schema": "http://json-schema.org/draft-04/schema#",
"properties": { "properties": {
"ipv6-prefix": { "ipv6-prefix": {
"title": "Ipv6 prefix to use to setup the new re6st network", "title": "Ipv6 prefix to use to setup the new re6st network",
"description": "Prefix ipv6 used by re6st to setup network. It is something like 2001:db8:42::/48", "description": "Prefix ipv6 used by re6st to setup network. It is something like 2001:db8:42::/48",
"type": "string" "type": "string"
}, },
"key-size": { "key-size": {
"title": "Number of bit to use for certificate generation", "title": "Number of bit to use for certificate generation",
"description": "Specify the size of certificate generated by re6st. by default, generate 2048-bit key length", "description": "Specify the size of certificate generated by re6st. by default, generate 2048-bit key length",
"type": "integer", "type": "integer",
"minimum": 1024, "minimum": 1024,
"default": 2048 "default": 2048
}, },
"prefix-length": { "prefix-length": {
"title": "Default length of allocated prefixes.", "title": "Default length of allocated prefixes.",
"description": "Default length of allocated prefixes.", "description": "Default length of allocated prefixes.",
"type": "integer", "type": "integer",
"default": 16 "default": 16
}, },
"anonymous-prefix-length": { "anonymous-prefix-length": {
"title": "Length of allocated anonymous prefixes.", "title": "Length of allocated anonymous prefixes.",
"description": "Length of allocated anonymous prefixes. 0 is unset.", "description": "Length of allocated anonymous prefixes. 0 is unset.",
"type": "integer", "type": "integer",
"default": 0 "default": 0
}, },
"mailhost": { "mailhost": {
"title": "SMTP host to send confirmation emails.", "title": "SMTP host to send confirmation emails.",
"description": "SMTP host to send confirmation emails. Not needed if when token is requested from slave instances.", "description": "SMTP host to send confirmation emails. Not needed if when token is requested from slave instances.",
"type": "string", "type": "string",
"default": "127.0.0.1" "default": "127.0.0.1"
}, },
"ipv4-net": { "ipv4-net": {
"title": "Enable ipv4 (ip/NET P_LENGTH).", "title": "Enable ipv4 (ip/NET P_LENGTH).",
"description": "Enable ipv4 (ip/NET P_LENGTH). Each node is assigned a subnet of length PLEN, inside network IP/N. Ex: 10.42.0.0/16 8", "description": "Enable ipv4 (ip/NET P_LENGTH). Each node is assigned a subnet of length PLEN, inside network IP/N. Ex: 10.42.0.0/16 8",
"type": "string", "type": "string",
"default": "" "default": ""
}, },
"client-count": { "client-count": {
"title": "Number of client tunnels to set up.", "title": "Number of client tunnels to set up.",
"description": "Number of client tunnels to set up.", "description": "Number of client tunnels to set up.",
"type": "integer", "type": "integer",
"default": 10 "default": 10
}, },
"tunnel-refresh": { "tunnel-refresh": {
"title": "Interval in seconds between two tunnel refresh.", "title": "Interval in seconds between two tunnel refresh.",
"description": "Interval in seconds between two tunnel refresh: the worst tunnel is closed if the number of client tunnels has reached its maximum number (client-count).", "description": "Interval in seconds between two tunnel refresh: the worst tunnel is closed if the number of client tunnels has reached its maximum number (client-count).",
"type": "integer", "type": "integer",
"default": 300 "default": 300
}, },
"max-clients": { "max-clients": {
"title": "Maximum number of accepted clients per OpenVPN server.", "title": "Maximum number of accepted clients per OpenVPN server.",
"description": "Maximum number of accepted clients per OpenVPN server. (if unset or 0: client-count * 2, which actually represents the average number of tunnels to other peers)", "description": "Maximum number of accepted clients per OpenVPN server. (if unset or 0: client-count * 2, which actually represents the average number of tunnels to other peers)",
"type": "integer", "type": "integer",
"default": 0 "default": 0
}, },
"hello": { "hello": {
"title": "Hello interval in seconds, for both wired and wireless connections.", "title": "Hello interval in seconds, for both wired and wireless connections.",
"description": "Hello interval in seconds, for both wired and wireless connections. OpenVPN ping-exit option is set to 4 times the hello interval. It takes between 3 and 4 times the hello interval for Babel to re-establish connection with a node for which the direct connection has been cut.", "description": "Hello interval in seconds, for both wired and wireless connections. OpenVPN ping-exit option is set to 4 times the hello interval. It takes between 3 and 4 times the hello interval for Babel to re-establish connection with a node for which the direct connection has been cut.",
"type": "integer", "type": "integer",
"default": 15 "default": 15
}, },
"min-protocol": { "min-protocol": {
"title": "Reject nodes that are too old.", "title": "Reject nodes that are too old.",
"description": "Reject nodes that are too old. Default is unset.", "description": "Reject nodes that are too old. Default is unset.",
"type": "integer", "type": "integer",
"default": -1 "default": -1
}, },
"encrypt": { "encrypt": {
"title": "Specify that tunnels should be encrypted.", "title": "Specify that tunnels should be encrypted.",
"description": "Specify that tunnels should be encrypted.", "description": "Specify that tunnels should be encrypted.",
"type": "boolean", "type": "boolean",
"default": false "default": false
}, },
"same-country": { "same-country": {
"title": "Same Country", "title": "Same Country",
"description": "Prevent tunnelling accross borders of listed countries", "description": "Prevent tunnelling accross borders of listed countries",
"type": "string", "type": "string",
"default": "" "default": ""
}
} }
} }
\ No newline at end of file }
...@@ -8,4 +8,4 @@ ...@@ -8,4 +8,4 @@
} }
}, },
"type": "object" "type": "object"
} }
\ No newline at end of file
{ {
"$schema": "http://json-schema.org/draft-04/schema#", "$schema": "http://json-schema.org/draft-04/schema#",
"properties": { "properties": {}
}
} }
{ {
"name": "RE6STNET", "name": "RE6STNET",
"description": "Master instance of re6st (Resilient, Scalable, IPv6 Network application)", "description": "Master instance of re6st (Resilient, Scalable, IPv6 Network application)",
"serialisation": "xml", "serialisation": "xml",
"software-type": { "software-type": {
"default": { "default": {
"title": "Default", "title": "Default",
"description": "Re6st registry", "description": "Re6st registry",
"request": "instance-re6stnet-input-schema.json", "request": "instance-re6stnet-input-schema.json",
"response": "instance-re6stnet-output-schema.json", "response": "instance-re6stnet-output-schema.json",
"index": 0 "index": 0
}, },
"default-slave": { "default-slave": {
"title": "Re6st Token", "title": "Re6st Token",
"description": "Re6st registry", "description": "Re6st registry",
"software-type": "default", "software-type": "default",
"request": "instance-re6stnet-slave-input-schema.json", "request": "instance-re6stnet-slave-input-schema.json",
"response": "instance-re6stnet-output-schema.json", "response": "instance-re6stnet-output-schema.json",
"shared": true, "shared": true,
"index": 1 "index": 1
}
} }
}
} }
...@@ -30,14 +30,15 @@ import os ...@@ -30,14 +30,15 @@ import os
import socket import socket
from contextlib import closing from contextlib import closing
import logging import logging
import StringIO
import xmlrpclib import xmlrpclib
import supervisor.xmlrpc import supervisor.xmlrpc
from erp5.util.testnode.SlapOSControler import SlapOSControler from erp5.util.testnode.SlapOSControler import SlapOSControler
from erp5.util.testnode.ProcessManager import ProcessManager from erp5.util.testnode.ProcessManager import ProcessManager
import slapos
# Utility functions
def findFreeTCPPort(ip=''): def findFreeTCPPort(ip=''):
"""Find a free TCP port to listen to. """Find a free TCP port to listen to.
""" """
...@@ -47,7 +48,30 @@ def findFreeTCPPort(ip=''): ...@@ -47,7 +48,30 @@ def findFreeTCPPort(ip=''):
return s.getsockname()[1] return s.getsockname()[1]
# TODO:
# - allow requesting multiple instances ?
class SlapOSInstanceTestCase(unittest.TestCase): class SlapOSInstanceTestCase(unittest.TestCase):
"""Install one slapos instance.
This test case install software(s) and request one instance during `setUpClass`
and destroy the instance during `tearDownClass`.
Software Release URL, Instance Software Type and Instance Parameters can be defined
on the class.
All tests from the test class will run with the same instance.
The following class attributes are available:
* `computer_partition`: the computer partition instance, implementing
`slapos.slap.interface.slap.IComputerPartition`.
* `computer_partition_root_path`: the path of the instance root directory.
"""
# Methods to be defined by subclasses.
@classmethod @classmethod
def getSoftwareURLList(cls): def getSoftwareURLList(cls):
"""Return URL of software releases to install. """Return URL of software releases to install.
...@@ -65,20 +89,75 @@ class SlapOSInstanceTestCase(unittest.TestCase): ...@@ -65,20 +89,75 @@ class SlapOSInstanceTestCase(unittest.TestCase):
""" """
return {} return {}
# TODO: allow subclasses to request a specific software type ? @classmethod
def getInstanceSoftwareType(cls):
"""Return software type for instance, default "default"
To be defined by subclasses if they need to request instance with specific
software type.
"""
return "default"
# Utility methods.
def getSupervisorRPCServer(self):
"""Returns a XML-RPC connection to the supervisor used by slapos node
Refer to http://supervisord.org/api.html for details of available methods.
"""
# xmlrpc over unix socket https://stackoverflow.com/a/11746051/7294664
return xmlrpclib.ServerProxy(
'http://slapos-supervisor',
transport=supervisor.xmlrpc.SupervisorTransport(
None,
None,
# XXX hardcoded socket path
serverurl="unix://{working_directory}/inst/supervisord.socket".format(
**self.config)))
# Unittest methods
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
"""Setup the class, build software and request an instance.
If you have to override this method, do not forget to call this method on
parent class.
"""
try: try:
cls._setUpClass() cls.setUpWorkingDirectory()
except: cls.setUpConfig()
cls.setUpSlapOSController()
cls.runSoftwareRelease()
# XXX instead of "runSoftwareRelease", it would be better to be closer to slapos usage:
# cls.supplySoftwares()
# cls.installSoftwares()
cls.runComputerPartition()
# XXX instead of "runComputerPartition", it would be better to be closer to slapos usage:
# cls.requestInstances()
# cls.createInstances()
# cls.requestInstances()
except Exception:
cls.stopSlapOSProcesses() cls.stopSlapOSProcesses()
raise raise
@classmethod @classmethod
def _setUpClass(cls): def tearDownClass(cls):
working_directory = os.environ.get( """Tear down class, stop the processes and destroy instance.
"""
cls.stopSlapOSProcesses()
# Implementation
@classmethod
def stopSlapOSProcesses(cls):
if hasattr(cls, '_process_manager'):
cls._process_manager.killPreviousRun()
@classmethod
def setUpWorkingDirectory(cls):
"""Initialise the directories"""
cls.working_directory = os.environ.get(
'SLAPOS_TEST_WORKING_DIR', 'SLAPOS_TEST_WORKING_DIR',
os.path.join(os.path.dirname(__file__), '.slapos')) os.path.join(os.path.dirname(__file__), '.slapos'))
# To prevent error: Cannot open an HTTP server: socket.error reported # To prevent error: Cannot open an HTTP server: socket.error reported
...@@ -87,76 +166,146 @@ class SlapOSInstanceTestCase(unittest.TestCase): ...@@ -87,76 +166,146 @@ class SlapOSInstanceTestCase(unittest.TestCase):
# https://github.com/torvalds/linux/blob/3848ec5/net/unix/af_unix.c#L234-L238 # https://github.com/torvalds/linux/blob/3848ec5/net/unix/af_unix.c#L234-L238
# Supervisord socket name contains the pid number, which is why we add # Supervisord socket name contains the pid number, which is why we add
# .xxxxxxx in this check. # .xxxxxxx in this check.
if len(working_directory + '/inst/supervisord.socket.xxxxxxx') > 108: if len(cls.working_directory + '/inst/supervisord.socket.xxxxxxx') > 108:
raise RuntimeError('working directory ( {} ) is too deep, try setting ' raise RuntimeError('working directory ( {} ) is too deep, try setting '
'SLAPOS_TEST_WORKING_DIR'.format(working_directory)) 'SLAPOS_TEST_WORKING_DIR'.format(cls.working_directory))
if not os.path.exists(working_directory): if not os.path.exists(cls.working_directory):
os.mkdir(working_directory) os.mkdir(cls.working_directory)
cls.config = config = { @classmethod
"working_directory": working_directory, def setUpConfig(cls):
"slapos_directory": working_directory, """Create slapos configuration"""
"log_directory": working_directory, cls.config = {
"computer_id": 'slapos.test', # XXX "working_directory": cls.working_directory,
'proxy_database': os.path.join(working_directory, 'proxy.db'), "slapos_directory": cls.working_directory,
"log_directory": cls.working_directory,
"computer_id": 'slapos.test', # XXX
'proxy_database': os.path.join(cls.working_directory, 'proxy.db'),
'partition_reference': cls.__name__, 'partition_reference': cls.__name__,
# "proper" slapos command must be in $PATH # "proper" slapos command must be in $PATH
'slapos_binary': 'slapos', 'slapos_binary': 'slapos',
} }
# Some tests are expecting that local IP is not set to 127.0.0.1 # Some tests are expecting that local IP is not set to 127.0.0.1
ipv4_address = os.environ.get('LOCAL_IPV4', '127.0.1.1') ipv4_address = os.environ.get('LOCAL_IPV4', '127.0.1.1')
ipv6_address = os.environ['GLOBAL_IPV6'] ipv6_address = os.environ['GLOBAL_IPV6']
config['proxy_host'] = config['ipv4_address'] = ipv4_address cls.config['proxy_host'] = cls.config['ipv4_address'] = ipv4_address
config['ipv6_address'] = ipv6_address cls.config['ipv6_address'] = ipv6_address
config['proxy_port'] = findFreeTCPPort(ipv4_address) cls.config['proxy_port'] = findFreeTCPPort(ipv4_address)
config['master_url'] = 'http://{proxy_host}:{proxy_port}'.format(**config) cls.config['master_url'] = 'http://{proxy_host}:{proxy_port}'.format(
**cls.config)
cls._process_manager = process_manager = ProcessManager() @classmethod
def setUpSlapOSController(cls):
"""Create the a "slapos controller" and supply softwares from `getSoftwareURLList`.
This is equivalent to:
slapos proxy start
for sr in getSoftwareURLList; do
slapos supply $SR $COMP
done
"""
cls._process_manager = ProcessManager()
# XXX this code is copied from testnode code # XXX this code is copied from testnode code
slapos_controler = SlapOSControler( cls.slapos_controler = SlapOSControler(
working_directory, cls.working_directory,
config cls.config
) )
slapproxy_log = os.path.join(config['log_directory'], 'slapproxy.log') slapproxy_log = os.path.join(cls.config['log_directory'], 'slapproxy.log')
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
logger.debug('Configured slapproxy log to %r', slapproxy_log) logger.debug('Configured slapproxy log to %r', slapproxy_log)
software_url_list = cls.getSoftwareURLList() cls.software_url_list = cls.getSoftwareURLList()
slapos_controler.initializeSlapOSControler( cls.slapos_controler.initializeSlapOSControler(
slapproxy_log=slapproxy_log, slapproxy_log=slapproxy_log,
process_manager=process_manager, process_manager=cls._process_manager,
reset_software=False, reset_software=False,
software_path_list=software_url_list) software_path_list=cls.software_url_list)
# XXX we should check *earlier* if that pidfile exist and if supervisord
# process still running, because if developer started supervisord (or bugs?)
# then another supervisord will start and starting services a second time
# will fail.
cls._process_manager.supervisord_pid_file = os.path.join(
cls.slapos_controler.instance_root, 'var', 'run', 'supervisord.pid')
process_manager.supervisord_pid_file = os.path.join( @classmethod
slapos_controler.instance_root, 'var', 'run', 'supervisord.pid') def runSoftwareRelease(cls):
"""Run all the software releases that were supplied before.
This is the equivalent of `slapos node software`.
The tests will be marked file if software building fail.
"""
logger = logging.getLogger()
logger.level = logging.DEBUG
stream = StringIO.StringIO()
stream_handler = logging.StreamHandler(stream)
logger.addHandler(stream_handler)
try:
cls.software_status_dict = cls.slapos_controler.runSoftwareRelease(
cls.config, environment=os.environ)
stream.seek(0)
stream.flush()
message = ''.join(stream.readlines()[-100:])
assert cls.software_status_dict['status_code'] == 0, message
finally:
logger.removeHandler(stream_handler)
del stream
software_status_dict = slapos_controler.runSoftwareRelease(config, environment=os.environ)
# TODO: log more details in this case @classmethod
assert software_status_dict['status_code'] == 0 def runComputerPartition(cls):
"""Instanciate the software.
This is the equivalent of doing:
slapos request --type=getInstanceSoftwareType --parameters=getInstanceParameterDict
slapos node instance
and return the slapos request instance parameters.
This can be called by tests to simulate re-request with different parameters.
"""
logger = logging.getLogger()
logger.level = logging.DEBUG
stream = StringIO.StringIO()
stream_handler = logging.StreamHandler(stream)
logger.addHandler(stream_handler)
if cls.getInstanceSoftwareType() != 'default':
raise NotImplementedError
instance_parameter_dict = cls.getInstanceParameterDict() instance_parameter_dict = cls.getInstanceParameterDict()
instance_status_dict = slapos_controler.runComputerPartition( try:
config, cls.instance_status_dict = cls.slapos_controler.runComputerPartition(
cls.config,
cluster_configuration=instance_parameter_dict, cluster_configuration=instance_parameter_dict,
environment=os.environ) environment=os.environ)
# TODO: log more details in this case stream.seek(0)
assert instance_status_dict['status_code'] == 0 stream.flush()
message = ''.join(stream.readlines()[-100:])
# FIXME: similar to test node, only one (root) partition is really supported for now. assert cls.instance_status_dict['status_code'] == 0, message
finally:
logger.removeHandler(stream_handler)
del stream
# FIXME: similar to test node, only one (root) partition is really
# supported for now.
computer_partition_list = [] computer_partition_list = []
for i in range(len(software_url_list)): for i in range(len(cls.software_url_list)):
computer_partition_list.append( computer_partition_list.append(
slapos_controler.slap.registerOpenOrder().request( cls.slapos_controler.slap.registerOpenOrder().request(
software_url_list[i], cls.software_url_list[i],
# This is how testnode's SlapOSControler name created partitions # This is how testnode's SlapOSControler name created partitions
partition_reference='testing partition {i}'.format(i=i, **config), partition_reference='testing partition {i}'.format(
partition_parameter_kw=instance_parameter_dict)) i=i, **cls.config),
partition_parameter_kw=instance_parameter_dict))
# expose some class attributes so that tests can use them: # expose some class attributes so that tests can use them:
# the ComputerPartition instances, to getInstanceParameterDict # the ComputerPartition instances, to getInstanceParameterDict
...@@ -164,31 +313,9 @@ class SlapOSInstanceTestCase(unittest.TestCase): ...@@ -164,31 +313,9 @@ class SlapOSInstanceTestCase(unittest.TestCase):
# the path of the instance on the filesystem, for low level inspection # the path of the instance on the filesystem, for low level inspection
cls.computer_partition_root_path = os.path.join( cls.computer_partition_root_path = os.path.join(
config['working_directory'], cls.config['working_directory'],
'inst', 'inst',
cls.computer_partition.getId()) cls.computer_partition.getId())
@classmethod
def stopSlapOSProcesses(cls):
if hasattr(cls, '_process_manager'):
cls._process_manager.killPreviousRun()
@classmethod
def tearDownClass(cls):
cls.stopSlapOSProcesses()
# utility methods
def getSupervisorRPCServer(self):
"""Returns a XML-RPC connection to the supervisor used by slapos node
Refer to http://supervisord.org/api.html for details of available methods.
"""
# xmlrpc over unix socket https://stackoverflow.com/a/11746051/7294664
return xmlrpclib.ServerProxy(
'http://slapos-supervisor',
transport=supervisor.xmlrpc.SupervisorTransport(
None,
None,
# XXX hardcoded socket path
serverurl="unix://{working_directory}/inst/supervisord.socket".format(**self.config)))
# THIS IS NOT A BUILDOUT FILE, despite purposedly using a compatible syntax.
# The only allowed lines here are (regexes):
# - "^#" comments, copied verbatim
# - "^[" section beginings, copied verbatim
# - lines containing an "=" sign which must fit in the following categorie.
# - "^\s*filename\s*=\s*path\s*$" where "path" is relative to this file
# Copied verbatim.
# - "^\s*hashtype\s*=.*" where "hashtype" is one of the values supported
# by the re-generation script.
# Re-generated.
# - other lines are copied verbatim
# Substitution (${...:...}), extension ([buildout] extends = ...) and
# section inheritance (< = ...) are NOT supported (but you should really
# not need these here).
[template]
filename = instance.cfg.in
md5sum = c4ac5de141ae6a64848309af03e51d88
[template-selenium]
filename = instance-selenium.cfg.in
md5sum = 9b6648b8f37baa3f7a6bfb68d4426049
...@@ -17,7 +17,7 @@ report-project = $${slap-parameter:report-project} ...@@ -17,7 +17,7 @@ report-project = $${slap-parameter:report-project}
[firefox-instance] [firefox-instance]
recipe = slapos.cookbook:firefox recipe = slapos.cookbook:firefox
runner-path = $${rootdirectory:bin}/firefox-sandboxed runner-path = $${rootdirectory:bin}/firefox-sandboxed
firefox-path = ${firefox:location}/firefox-slapos firefox-path = ${firefox-wrapper:location}
prefsjs-path = $${rootdirectory:etc}/prefs.js prefsjs-path = $${rootdirectory:etc}/prefs.js
shell-path = ${dash:location}/bin/dash shell-path = ${dash:location}/bin/dash
tmp-path = $${xvfb-instance:tmp-path} tmp-path = $${xvfb-instance:tmp-path}
......
...@@ -5,6 +5,7 @@ extends = ...@@ -5,6 +5,7 @@ extends =
../../component/firefox/buildout.cfg ../../component/firefox/buildout.cfg
../../component/dash/buildout.cfg ../../component/dash/buildout.cfg
../../stack/slapos.cfg ../../stack/slapos.cfg
./buildout.hash.cfg
# develop += /opt/slapdev # develop += /opt/slapdev
...@@ -15,6 +16,7 @@ parts = ...@@ -15,6 +16,7 @@ parts =
instance-recipe-egg instance-recipe-egg
xserver xserver
firefox firefox
geckodriver
xwd xwd
[instance-recipe] [instance-recipe]
...@@ -30,20 +32,19 @@ recipe = zc.recipe.egg ...@@ -30,20 +32,19 @@ recipe = zc.recipe.egg
eggs = eggs =
${lxml-python:egg} ${lxml-python:egg}
[template]
# Default template for the instance. [macro-template]
recipe = slapos.recipe.template recipe = slapos.recipe.template
url = ${:_profile_base_location_}/instance.cfg url = ${:_profile_base_location_}/${:filename}
md5sum = c4ac5de141ae6a64848309af03e51d88
output = ${buildout:directory}/template.cfg
mode = 0644 mode = 0644
[template]
<= macro-template
output = ${buildout:directory}/template.cfg
[template-selenium] [template-selenium]
recipe = slapos.recipe.template <= macro-template
url = ${:_profile_base_location_}/instance-selenium.cfg
md5sum = 8be91f4515decef0f8af5910e43e0e52
output = ${buildout:directory}/template-selenium.cfg output = ${buildout:directory}/template-selenium.cfg
mode = 0644
[versions] [versions]
plone.recipe.command = 1.1 plone.recipe.command = 1.1
......
{ {
"$schema": "http://json-schema.org/draft-04/schema#", "$schema": "http://json-schema.org/draft-04/schema#",
"properties": { "properties": {
"user-authorized-key": { "user-authorized-key": {
"title": "User Authorized Key", "title": "User Authorized Key",
"description": "SSH public key in order to connect to the SSH server of this runner instance.", "description": "SSH public key in order to connect to the SSH server of this runner instance.",
"textarea": true, "textarea": true,
"type": "string" "type": "string"
}, },
"instance-amount": { "instance-amount": {
"title": "Partition Amount", "title": "Partition Amount",
"description": "Number of slappart to deploy inside the runner (default is 10). Needs instance to be restarted.", "description": "Number of slappart to deploy inside the runner (default is 10). Needs instance to be restarted.",
"type": "integer", "type": "integer",
"minimum": 1, "minimum": 1,
"maximum": 40 "maximum": 40
}, },
"slapos-software": { "slapos-software": {
"title": "Pre-selected Software Release", "title": "Pre-selected Software Release",
"description": "a relative path from the slapos git repo to a folder containing a software release, which will be automaticaly deployed while the runner instanciation, and only if the parameter auto-deploy is set to 'true'. For example: 'software/helloworld", "description": "a relative path from the slapos git repo to a folder containing a software release, which will be automaticaly deployed while the runner instanciation, and only if the parameter auto-deploy is set to 'true'. For example: 'software/helloworld",
"type": "string" "type": "string"
}, },
"auto-deploy": { "auto-deploy": {
"title": "Automatically Deploy Software", "title": "Automatically Deploy Software",
"description": "Authorizes the software declared with 'slapos-software' to be automatically deployed, or not. Needs instance to be restarted. (default is false)", "description": "Authorizes the software declared with 'slapos-software' to be automatically deployed, or not. Needs instance to be restarted. (default is false)",
"type": "boolean" "type": "boolean"
}, },
"slapos-repository": { "slapos-repository": {
"title": "SlapOS Git Repository URL", "title": "SlapOS Git Repository URL",
"description": "url of the default git repository that will be download by the runner while its instanciation. Will be cloned in a directory named 'slapos' (default is https://lab.nexedi.com/nexedi/slapos.git)", "description": "url of the default git repository that will be download by the runner while its instanciation. Will be cloned in a directory named 'slapos' (default is https://lab.nexedi.com/nexedi/slapos.git)",
"type": "string", "type": "string",
"format": "uri", "format": "uri",
"pattern": "^(http|https|ftp)://" "pattern": "^(http|https|ftp)://"
}, },
"slapos-reference": { "slapos-reference": {
"title": "SlapOS Git Branch Name", "title": "SlapOS Git Branch Name",
"description": "Branch or hash on which the default repository will checkout (default is master)", "description": "Branch or hash on which the default repository will checkout (default is master)",
"type": "string" "type": "string"
}, },
"auto-deploy-instance": { "auto-deploy-instance": {
"title": "Automatically Deploy Instances", "title": "Automatically Deploy Instances",
"description": "Prevent the runner from deploying and starting instances. Needs instance to be restarted. It is set to false for instances of type 'import' in resiliency in any case (default is false)", "description": "Prevent the runner from deploying and starting instances. Needs instance to be restarted. It is set to false for instances of type 'import' in resiliency in any case (default is false)",
"type": "boolean" "type": "boolean"
}, },
"autorun": { "autorun": {
"title": "Automatically Run Sofware/Instance", "title": "Automatically Run Sofware/Instance",
"description": "Let automaticaly build and run a declared software with 'slapos-software'. Only works if 'slapos-software' is set, and 'auto-deploy' is true. Needs instance to be restarted. (default is false)", "description": "Let automaticaly build and run a declared software with 'slapos-software'. Only works if 'slapos-software' is set, and 'auto-deploy' is true. Needs instance to be restarted. (default is false)",
"type": "boolean" "type": "boolean"
}, },
"slapos-software-type": { "slapos-software-type": {
"title": "Deployed Instance Software Type" , "title": "Deployed Instance Software Type",
"description": "Software type of your instance inside the runner", "description": "Software type of your instance inside the runner",
"type": "string" "type": "string"
}, },
"cpu-usage-ratio": { "cpu-usage-ratio": {
"title": "CPU Usage Ratio", "title": "CPU Usage Ratio",
"description": "Ratio of the CPU use for compilation, if value is set to n, compilation will use number-of-cpu/n of cpus (need instance restart)", "description": "Ratio of the CPU use for compilation, if value is set to n, compilation will use number-of-cpu/n of cpus (need instance restart)",
"type": "integer", "type": "integer",
"default" : 4 "default": 4
}, },
"no-ipv4-frontend": { "no-ipv4-frontend": {
"title": "No IPv4 frontend", "title": "No IPv4 frontend",
"description": "Prevent the slaprunner to order an IPv4 frontend for itself", "description": "Prevent the slaprunner to order an IPv4 frontend for itself",
"enum": ["true", "false"], "enum": [
"default": "false" "true",
}, "false"
"custom-frontend-backend-url": { ],
"title": "Custom Frontend Backend URL", "default": "false"
"description": "return an ipv4 frontend of the given ipv6(+optional port)", },
"type": "string", "custom-frontend-backend-url": {
"format": "uri" "title": "Custom Frontend Backend URL",
}, "description": "return an ipv4 frontend of the given ipv6(+optional port)",
"custom-frontend-backend-type": { "type": "string",
"title": "Custom Frontend Backend Type", "format": "uri"
"description": "The type of the frontend slave instance to ask", },
"type": "string", "custom-frontend-backend-type": {
"enum": ["zope"] "title": "Custom Frontend Backend Type",
}, "description": "The type of the frontend slave instance to ask",
"custom-frontend-basic-auth": { "type": "string",
"title": "Custom Frontend Basic Auth", "enum": [
"description": "if the ip given with 'custom-frontend-backend-url' is secure, set it to true for the promise do not fail", "zope"
"type": "boolean" ]
}, },
"custom-frontend-instance-guid": { "custom-frontend-basic-auth": {
"title": "Custom Frontend Instance GUID", "title": "Custom Frontend Basic Auth",
"description": "Instance guid of the frontend you whish to use", "description": "if the ip given with 'custom-frontend-backend-url' is secure, set it to true for the promise do not fail",
"type": "string" "type": "boolean"
}, },
"custom-frontend-software-type": { "custom-frontend-instance-guid": {
"title": "Custom Frontend Software Type", "title": "Custom Frontend Instance GUID",
"description": "SoftwareType of the frontend you request (default is RootSoftwareInstance)", "description": "Instance guid of the frontend you whish to use",
"type": "string", "type": "string"
"enum": ["RootSoftwareInstance", "default"] },
}, "custom-frontend-software-type": {
"custom-frontend-software-url": { "title": "Custom Frontend Software Type",
"title": "Custom Frontend Software URL", "description": "SoftwareType of the frontend you request (default is RootSoftwareInstance)",
"description": "Software Url of the frontend you request (ie.: http://git.erp5.org/gitweb/slapos.git/blob_plain/HEAD:/software/apache-frontend/software.cfg)", "type": "string",
"type": "string", "enum": [
"format": "uri" "RootSoftwareInstance",
}, "default"
"check-custom-frontend-promise": { ]
"title": "Check Custom Frontend Promise", },
"description": "Enable a promise to check that HTTP frontend created from custom-frontend-backend-url is available", "custom-frontend-software-url": {
"type": "string", "title": "Custom Frontend Software URL",
"enum": ["true", "false"], "description": "Software Url of the frontend you request (ie.: http://git.erp5.org/gitweb/slapos.git/blob_plain/HEAD:/software/apache-frontend/software.cfg)",
"default": "false" "type": "string",
}, "format": "uri"
"monitor-port": { },
"title": "Monitor Port", "check-custom-frontend-promise": {
"description": "Allow to manually change the port on wich the apache server running monitoring interface is listening. The default value for the webrunner is different from the default value of the standalone stack-monitor server (default 9684)", "title": "Check Custom Frontend Promise",
"type": "integer", "description": "Enable a promise to check that HTTP frontend created from custom-frontend-backend-url is available",
"minimum": 9683, "type": "string",
"exclusiveMinimum": true "enum": [
}, "true",
"monitor-interface-url": { "false"
"title": "Monitor Web Interface URL", ],
"description": "Give Url of HTML web interface that will be used to render this monitor instance.", "default": "false"
"type": "string", },
"format": "uri", "monitor-port": {
"default": "https://monitor.app.officejs.com" "title": "Monitor Port",
}, "description": "Allow to manually change the port on wich the apache server running monitoring interface is listening. The default value for the webrunner is different from the default value of the standalone stack-monitor server (default 9684)",
"monitor-cors-domains": { "type": "integer",
"title": "Monitor CORS domains", "minimum": 9683,
"description": "List of cors domains separated with space. Needed for ajax query on this monitor instance from a different domain.", "exclusiveMinimum": true
"type": "string", },
"default": "monitor.app.officejs.com" "monitor-interface-url": {
}, "title": "Monitor Web Interface URL",
"instance-name": { "description": "Give Url of HTML web interface that will be used to render this monitor instance.",
"title": "Instance Name", "type": "string",
"description": "Name of the instance, to show in the window title", "format": "uri",
"type": "string" "default": "https://monitor.app.officejs.com"
} },
"monitor-cors-domains": {
"title": "Monitor CORS domains",
"description": "List of cors domains separated with space. Needed for ajax query on this monitor instance from a different domain.",
"type": "string",
"default": "monitor.app.officejs.com"
},
"instance-name": {
"title": "Instance Name",
"description": "Name of the instance, to show in the window title",
"type": "string"
} }
}
} }
...@@ -40,4 +40,4 @@ ...@@ -40,4 +40,4 @@
} }
}, },
"type": "object" "type": "object"
} }
\ No newline at end of file
{ {
"type": "object", "type": "object",
"$schema": "http://json-schema.org/draft-04/schema", "$schema": "http://json-schema.org/draft-04/schema",
"allOf": [ "allOf": [
{ {
"$ref": "instance-runner-input-schema.json#/" "$ref": "instance-runner-input-schema.json#/"
},
{
"properties": {
"resilient-clone-number": {
"title": "Amount of backup(s) to create",
"description": "Amount of backup(s) to create. Each backup consists of a Pull Backup Server and a clone.",
"type": "integer",
"default": 1,
"minimum": 0,
"maximum": 2,
"optional": true
}, },
{ "-sla-runner0-computer_guid": {
"properties": { "title": "Target computer for main instance",
"resilient-clone-number": { "description": "Target computer GUID for main instance.",
"title": "Amount of backup(s) to create", "type": "string",
"description": "Amount of backup(s) to create. Each backup consists of a Pull Backup Server and a clone.", "optional": true
"type": "integer", },
"default": 1, "-sla-runner1-computer_guid": {
"minimum": 0, "title": "Target computer for first clone",
"maximum": 2, "description": "Target computer for first clone instance.",
"optional": true "type": "string",
}, "optional": true
"-sla-runner0-computer_guid": { },
"title": "Target computer for main instance", "-sla-pbs1-computer_guid": {
"description": "Target computer GUID for main instance.", "title": "Target computer for first PBS",
"type": "string", "description": "Target computer for first PBS instance.",
"optional": true "type": "string",
}, "optional": true
"-sla-runner1-computer_guid": { },
"title": "Target computer for first clone", "-sla-runner2-computer_guid": {
"description": "Target computer for first clone instance.", "title": "Target computer for second clone",
"type": "string", "description": "Target computer for second clone instance.",
"optional": true "type": "string",
}, "optional": true
"-sla-pbs1-computer_guid": { },
"title": "Target computer for first PBS", "-sla-pbs2-computer_guid": {
"description": "Target computer for first PBS instance.", "title": "Target computer for second PBS",
"type": "string", "description": "Target computer for second PBS instance.",
"optional": true "type": "string",
}, "optional": true
"-sla-runner2-computer_guid": { },
"title": "Target computer for second clone", "resiliency-backup-periodicity": {
"description": "Target computer for second clone instance.", "title": "Periodicity of backup",
"type": "string", "description": "Periodicity of backup, in cron format.",
"optional": true "type": "string",
}, "optional": true
"-sla-pbs2-computer_guid": { },
"title": "Target computer for second PBS", "remove-backup-older-than": {
"description": "Target computer for second PBS instance.", "title": "Remove backups older than...",
"type": "string", "description": "Remove all the backups in PBS that are older than specified value. It should be rdiff-backup-compatible.",
"optional": true "type": "string",
}, "default": "2W",
"resiliency-backup-periodicity": { "optional": true
"title": "Periodicity of backup", },
"description": "Periodicity of backup, in cron format.", "ignore-known-hosts-file": {
"type": "string", "title": "Ignore known_hosts file",
"optional": true "description": "Set either to fill known_hosts file for ssh or not. Useful if main instance and PBS are using the same IP (slapos proxy, webrunner).",
}, "type": "boolean",
"remove-backup-older-than": { "default": false,
"title": "Remove backups older than...", "optional": true
"description": "Remove all the backups in PBS that are older than specified value. It should be rdiff-backup-compatible.",
"type": "string",
"default": "2W",
"optional": true
},
"ignore-known-hosts-file": {
"title": "Ignore known_hosts file",
"description": "Set either to fill known_hosts file for ssh or not. Useful if main instance and PBS are using the same IP (slapos proxy, webrunner).",
"type": "boolean",
"default": false,
"optional": true
}
}
} }
] }
} }
\ No newline at end of file ]
}
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
"index": 0 "index": 0
}, },
"resilient": { "resilient": {
"title": "Resilient", "title": "Resilient",
"description": "Resilient Runner", "description": "Resilient Runner",
"request": "instance-runner-resilient-input-schema.json", "request": "instance-runner-resilient-input-schema.json",
"response": "instance-runner-output-schema.json", "response": "instance-runner-output-schema.json",
......
...@@ -3,12 +3,15 @@ ...@@ -3,12 +3,15 @@
"extends": "./schema-definitions.json#", "extends": "./schema-definitions.json#",
"properties": { "properties": {
"tcpv4-port": { "tcpv4-port": {
"allOf": [{ "allOf": [
"$ref": "#/definitions/tcpv4port" {
}, { "$ref": "#/definitions/tcpv4port"
"description": "Start allocating ports at this value, going upward", },
"default": 6001 {
}] "description": "Start allocating ports at this value, going upward",
"default": 6001
}
]
}, },
"backend-url": { "backend-url": {
"description": "The backend url that varnish will cache", "description": "The backend url that varnish will cache",
......
...@@ -22,4 +22,4 @@ scikit-learn = ...@@ -22,4 +22,4 @@ scikit-learn =
# install scikit-learn git clone # install scikit-learn git clone
[scikit-learn] [scikit-learn]
<= scikit-learn-develop depends = ${scikit-learn-develop:recipe}
...@@ -125,13 +125,11 @@ mode = 0644 ...@@ -125,13 +125,11 @@ mode = 0644
# Time in minutes to wait for the backup to finish # Time in minutes to wait for the backup to finish
backup_wait_time = 10 backup_wait_time = 10
[rdiff-backup-build] [rdiff-backup]
# use our own version eggs =
find-links = http://www.nexedi.org/static/packages/source/rdiff-backup-1.3.4nxd2.tar.gz ${rdiff-backup-build-1.3.4:egg}
patches =
${:_profile_base_location_}/rdiff-backup-1.3.4-librsync-1.0.0.patch#31fafc8bc4a00f002f52008a9f3b671f
[versions] [versions]
# 1.3.4nxd2 is invalid version string, thus pached version string is not '1.3.4nxd2+SlapOSPatched001' # 1.3.4nxd5 is invalid version string, thus pached version string is not '1.3.4nxd5+SlapOSPatched001'
# but '1.3.4nxd2-SlapOSPatched001'. # but '1.3.4nxd5-SlapOSPatched001'.
rdiff-backup = 1.3.4nxd2-SlapOSPatched001 rdiff-backup = 1.3.4nxd5-SlapOSPatched001
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
"title": "Resiliency Parameters", "title": "Resiliency Parameters",
"description": "List of possible parameters used in the resilient stack", "description": "List of possible parameters used in the resilient stack",
"type": "object", "type": "object",
"properties": { "properties": {
"-sla-0-computer_guid": { "-sla-0-computer_guid": {
"title": "Target computer for main instance", "title": "Target computer for main instance",
......
...@@ -134,7 +134,7 @@ pyparsing = 2.2.0 ...@@ -134,7 +134,7 @@ pyparsing = 2.2.0
pytz = 2016.10 pytz = 2016.10
requests = 2.13.0 requests = 2.13.0
six = 1.10.0 six = 1.10.0
slapos.cookbook = 1.0.66 slapos.cookbook = 1.0.75
slapos.core = 1.4.9 slapos.core = 1.4.9
slapos.extension.strip = 0.4 slapos.extension.strip = 0.4
slapos.extension.shared = 1.0 slapos.extension.shared = 1.0
......
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