Commit 20929ec6 authored by Thomas Gambier's avatar Thomas Gambier 🚴🏼

Update Release Candidate

parents c29807b3 e4b0fcba
...@@ -29,46 +29,37 @@ import string, random ...@@ -29,46 +29,37 @@ import string, random
import os import os
from six.moves import range from six.moves import range
class Recipe(GenericBaseRecipe): from zc.buildout import UserError
from zc.buildout.buildout import bool_option
def __init__(self, buildout, name, options):
base_path = options['base-path'] def issubpathof(subpath, path):
if options.get('use-hash-url', 'True') in ['true', 'True']: subpath = os.path.abspath(subpath)
pool = string.ascii_letters + string.digits path = os.path.abspath(path)
hash_string = ''.join(random.choice(pool) for i in range(64)) relpath = os.path.relpath(subpath, start=path)
path = os.path.join(base_path, hash_string) return not relpath.startswith(os.pardir)
if os.path.exists(base_path):
path_list = os.listdir(base_path)
if len(path_list) == 1:
hash_string = path_list[0]
path = os.path.join(base_path, hash_string)
elif len(path_list) > 1:
raise ValueError("Folder %s should contain 0 or 1 element." % base_path)
options['root-dir'] = path
options['path'] = hash_string
else:
options['root-dir'] = base_path
options['path'] = ''
return GenericBaseRecipe.__init__(self, buildout, name, options)
def install(self): class Recipe(GenericBaseRecipe):
def __init__(self, buildout, name, options):
host, port, socketpath, abstract = (
options.get(k) for k in ('host', 'port', 'socketpath', 'abstract'))
oneof = host, socketpath, abstract
if sum(bool(v) for v in oneof) != 1 or bool(host) != bool(port):
raise UserError("Specify one of (host, port) | socketpath | abstract")
address = (host, int(port)) if host else socketpath or '\0' + abstract
options['address'] = address
return GenericBaseRecipe.__init__(self, buildout, name, options)
if not os.path.exists(self.options['root-dir']): def install(self):
os.mkdir( self.options['root-dir'] )
parameters = { parameters = {
'host': self.options['host'], 'address': self.options['address'],
'port': int(self.options['port']),
'cwd': self.options['base-path'], 'cwd': self.options['base-path'],
'log-file': self.options['log-file'], 'log-file': self.options['log-file'],
'cert-file': self.options.get('cert-file', ''), 'cert-file': self.options.get('cert-file'),
'key-file': self.options.get('key-file', ''), 'key-file': self.options.get('key-file'),
'root-dir': self.options['root-dir'] 'allow-write': bool_option(self.options, 'allow-write', 'false')
} }
return self.createPythonScript( return self.createPythonScript(
self.options['wrapper'].strip(), self.options['wrapper'].strip(),
__name__ + '.simplehttpserver.run', __name__ + '.simplehttpserver.run',
......
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from six.moves.SimpleHTTPServer import SimpleHTTPRequestHandler from six.moves.SimpleHTTPServer import SimpleHTTPRequestHandler
from six.moves.BaseHTTPServer import HTTPServer from six.moves.socketserver import TCPServer
import ssl
import os import cgi
import contextlib
import errno
import logging import logging
from netaddr import valid_ipv4, valid_ipv6 import os
import ssl
import socket import socket
import cgi, errno
from slapos.util import str2bytes from slapos.util import str2bytes
from . import issubpathof
class ServerHandler(SimpleHTTPRequestHandler): class ServerHandler(SimpleHTTPRequestHandler):
base_path = None # set by run
restrict_write = True # set by run
_additional_logs = None
@contextlib.contextmanager
def _log_extra(self, msg):
self._additional_logs = msg
try:
yield
finally:
self._additional_logs = None
def _log(self, level, msg, *args):
if self._additional_logs:
msg += self._additional_logs
logging.log(level, '%s - - ' + msg, self.client_address[0], *args)
def log_message(self, msg, *args):
self._log(logging.INFO, msg, *args)
def log_error(self, msg, *args):
self._log(logging.ERROR, msg, *args)
document_path = '' def log_request(self, *args):
restrict_root_folder = True with self._log_extra('\n' + str(self.headers)):
SimpleHTTPRequestHandler.log_request(self, *args)
def respond(self, code=200, type='text/html'): def respond(self, code=200, type='text/html'):
self.send_response(code) self.send_response(code)
self.send_header("Content-type", type) self.send_header("Content-type", type)
self.end_headers() self.end_headers()
def restrictedRootAccess(self): def restrictedWriteAccess(self):
if self.restrict_root_folder and self.path and self.path == '/': if self.restrict_write and self.command not in ('GET', 'HEAD'):
# no access to root path # no write access
self.respond(403) self.respond(403)
self.wfile.write(b"Forbidden") self.wfile.write(b"Forbidden")
return True return True
return False return False
def do_GET(self):
logging.info('%s - GET: %s \n%s' % (self.client_address[0], self.path, self.headers))
if self.restrictedRootAccess():
return
SimpleHTTPRequestHandler.do_GET(self)
def do_POST(self): def do_POST(self):
"""Write to a file on the server. """Write to a file on the server.
...@@ -45,8 +66,7 @@ class ServerHandler(SimpleHTTPRequestHandler): ...@@ -45,8 +66,7 @@ class ServerHandler(SimpleHTTPRequestHandler):
request can be encoded as application/x-www-form-urlencoded or multipart/form-data request can be encoded as application/x-www-form-urlencoded or multipart/form-data
""" """
logging.info('%s - POST: %s \n%s' % (self.client_address[0], self.path, self.headers)) if self.restrictedWriteAccess():
if self.restrictedRootAccess():
return return
form = cgi.FieldStorage( form = cgi.FieldStorage(
...@@ -67,64 +87,76 @@ class ServerHandler(SimpleHTTPRequestHandler): ...@@ -67,64 +87,76 @@ class ServerHandler(SimpleHTTPRequestHandler):
file_open_mode = 'wb' if ('clear' in form and form['clear'].value in ('1', b'1')) else 'ab' file_open_mode = 'wb' if ('clear' in form and form['clear'].value in ('1', b'1')) else 'ab'
self.writeFile(file_path, file_content, file_open_mode) self.writeFile(file_path, file_content, file_open_mode)
self.respond(200, type=self.headers['Content-Type'])
self.wfile.write(b"Content written to %s" % str2bytes(file_path))
def writeFile(self, filename, content, method='ab'): def writeFile(self, filename, content, method='ab'):
file_path = os.path.abspath(os.path.join(self.document_path, filename)) file_path = os.path.abspath(os.path.join(self.base_path, filename))
if not file_path.startswith(self.document_path): # Check writing there is allowed
if not issubpathof(file_path, self.base_path):
self.respond(403, 'text/plain') self.respond(403, 'text/plain')
self.wfile.write(b"Forbidden") self.wfile.write(b"Forbidden")
return
# Create missing directories if needed
try: try:
os.makedirs(os.path.dirname(file_path)) os.makedirs(os.path.dirname(file_path))
except OSError as exception: except OSError as exception:
if exception.errno != errno.EEXIST: if exception.errno != errno.EEXIST:
logging.error('Failed to create file in %s. The error is \n%s' % ( self.log_error('Failed to create file in %s. The error is \n%s',
file_path, str(exception))) file_path, exception)
# Write content to file
logging.info('Writing recieved content to file %s' % file_path) self.log_message('Writing received content to file %s', file_path)
try: try:
with open(file_path, method) as myfile: with open(file_path, method) as myfile:
myfile.write(content) myfile.write(content)
logging.info('Done.') self.log_message('Done.')
except IOError as e: except IOError as e:
logging.error('Something happened while processing \'writeFile\'. The message is %s' % self.log_error(
str(e)) 'Something happened while processing \'writeFile\'. The message is %s',
e)
class HTTPServerV6(HTTPServer): self.respond(200, type=self.headers['Content-Type'])
address_family = socket.AF_INET6 self.wfile.write(b"Content written to %s" % str2bytes(filename))
def run(args): def run(args):
# minimal web server. serves files relative to the current directory.
# minimal web server. serves files relative to the logging.basicConfig(
# current directory. format="%(asctime)s %(levelname)s - %(message)s",
logging.basicConfig(format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", filename=args['log-file'],
filename=args['log-file'] ,level=logging.INFO) level=logging.INFO)
port = args['port'] address = args['address']
host = args['host'] cwd = args['cwd']
os.chdir(args['cwd'])
os.chdir(cwd)
Handler = ServerHandler Handler = ServerHandler
Handler.document_path = args['root-dir'] Handler.base_path = cwd
Handler.restrict_root_folder = (args['root-dir'] != args['cwd']) Handler.restrict_write = not args['allow-write']
if valid_ipv6(host): try:
server = HTTPServerV6 host, port = address
else: family, _, _, _, _ = socket.getaddrinfo(host, port)[0]
server = HTTPServer except ValueError:
family = socket.AF_UNIX
httpd = server((host, port), Handler)
scheme = 'http' class Server(TCPServer):
if 'cert-file' in args and 'key-file' in args and \ allow_reuse_address = 1 # for tests, HTTPServer in stdlib sets it too
os.path.exists(args['cert-file']) and os.path.exists(args['key-file']): address_family = family
scheme = 'https'
httpd.socket = ssl.wrap_socket (httpd.socket, httpd = Server(address, Handler)
server_side=True,
certfile=args['cert-file'], certfile = args['cert-file']
keyfile=args['key-file']) if certfile: # keyfile == None signifies key is in certfile
PROTOCOL_TLS_SERVER = getattr(ssl, 'PROTOCOL_TLS_SERVER', None)
logging.info("Starting simple http server at %s://%s:%s" % (scheme, host, port)) if PROTOCOL_TLS_SERVER:
sslcontext = ssl.SSLContext(PROTOCOL_TLS_SERVER)
sslcontext.load_cert_chain(certfile, args['key-file'])
httpd.socket = sslcontext.wrap_socket(httpd.socket, server_side=True)
else: # BBB Py2, Py<3.6
httpd.socket = ssl.wrap_socket(
httpd.socket,
server_side=True,
certfile=certfile,
keyfile=args['key-file'])
logging.info("Starting simple http server at %s", address)
httpd.serve_forever() httpd.serve_forever()
This diff is collapsed.
{
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Input Parameters",
"$defs": {
"instance-parameters": {
"type": "object",
"properties": {
"boot-image-url-select": {
"title": "Boot image",
"description": "Selectable list of provided ISO images.",
"type": "string",
"default": "Debian Bookworm 12 netinst x86_64",
"enum": [
"Debian Bookworm 12 netinst x86_64",
"Debian Bullseye 11 netinst x86_64",
"Centos 8.2004 Minimal x86_64",
"Ubuntu Noble 24.04 Live Server x86_64",
"Ubuntu Jammy 22.04 Live Server x86_64",
"Ubuntu Focal 20.04 Live Server x86_64",
"openSUSE Leap 15 NET x86_64",
"Arch Linux 2020.09.01 x86_64",
"Fedora Server 32 netinst x86_64",
"FreeBSD 12.1 RELEASE bootonly x86_64",
"SUSE Linux Enterprise Server 15 SP6 x86_64"
]
},
"boot-image-url-list": {
"title": "[EXPERT] Boot image list",
"description": "The list shall be list of direct URLs to images, followed by hash (#), then by image MD5SUM. Each image shall appear on newline, like: \"https://example.com/image.iso#06226c7fac5bacfa385872a19bb99684<newline>https://example.com/another-image.iso#31b40d58b18e038498ddb46caea1361c\". They will be provided in KVM image list according to the order on the list. Maximum images: 4. Maximum image size: 20GB. Download tries: 4. Maximum ownload time: 4h.",
"type": "string",
"textarea": true
}
}
}
},
"unevaluatedProperties": false,
"allOf": [
{
"$ref": "#/$defs/instance-parameters"
}
]
}
...@@ -43,7 +43,7 @@ md5sum = a02f0694dcb944c18d99f7f79afa2384 ...@@ -43,7 +43,7 @@ md5sum = a02f0694dcb944c18d99f7f79afa2384
[template-kvm-export-script] [template-kvm-export-script]
filename = template/kvm-export.sh.jinja2 filename = template/kvm-export.sh.jinja2
md5sum = a1da7809d547b4c61e7c6337bf9f8b8a md5sum = ba1e0359178925788792a1c6cc29ba59
[template-nginx] [template-nginx]
filename = template/nginx_conf.in filename = template/nginx_conf.in
......
...@@ -453,7 +453,7 @@ ...@@ -453,7 +453,7 @@
}, },
"boot-image-url-list": { "boot-image-url-list": {
"title": "[EXPERT] Boot image list", "title": "[EXPERT] Boot image list",
"description": "The list shall be list of direct URLs to images, followed by hash (#), then by image MD5SUM. Each image shall appear on newline, like: \"https://example.com/image.iso#06226c7fac5bacfa385872a19bb99684<newline>https://example.com/another-image.iso#31b40d58b18e038498ddb46caea1361c\". They will be provided in KVM image list according to the order on the list. Maximum images: 4. Maximum image size: 20GB. Download tires: 4. Maximum download time: 4h.", "description": "The list shall be list of direct URLs to images, followed by hash (#), then by image MD5SUM. Each image shall appear on newline, like: \"https://example.com/image.iso#06226c7fac5bacfa385872a19bb99684<newline>https://example.com/another-image.iso#31b40d58b18e038498ddb46caea1361c\". They will be provided in KVM image list according to the order on the list. Maximum images: 4. Maximum image size: 20GB. Download tries: 4. Maximum download time: 4h.",
"type": "string", "type": "string",
"textarea": true "textarea": true
}, },
......
...@@ -285,31 +285,6 @@ ...@@ -285,31 +285,6 @@
"format": "uri", "format": "uri",
"default": "http://git.erp5.org/gitweb/slapos.git/blob_plain/HEAD:/software/apache-frontend/software.cfg" "default": "http://git.erp5.org/gitweb/slapos.git/blob_plain/HEAD:/software/apache-frontend/software.cfg"
}, },
"boot-image-url-select": {
"title": "Boot image",
"description": "Selectable list of provided ISO images.",
"type": "string",
"default": "Debian Bookworm 12 netinst x86_64",
"enum": [
"Debian Bookworm 12 netinst x86_64",
"Debian Bullseye 11 netinst x86_64",
"Centos 8.2004 Minimal x86_64",
"Ubuntu Noble 24.04 Live Server x86_64",
"Ubuntu Jammy 22.04 Live Server x86_64",
"Ubuntu Focal 20.04 Live Server x86_64",
"openSUSE Leap 15 NET x86_64",
"Arch Linux 2020.09.01 x86_64",
"Fedora Server 32 netinst x86_64",
"FreeBSD 12.1 RELEASE bootonly x86_64",
"SUSE Linux Enterprise Server 15 SP6 x86_64"
]
},
"boot-image-url-list": {
"title": "[EXPERT] Boot image list",
"description": "The list shall be list of direct URLs to images, followed by hash (#), then by image MD5SUM. Each image shall appear on newline, like: \"https://example.com/image.iso#06226c7fac5bacfa385872a19bb99684<newline>https://example.com/another-image.iso#31b40d58b18e038498ddb46caea1361c\". They will be provided in KVM image list according to the order on the list. Maximum images: 4. Maximum image size: 20GB. Download tires: 4. Maximum ownload time: 4h.",
"type": "string",
"textarea": true
},
"whitelist-domains": { "whitelist-domains": {
"title": "Whitelist domains", "title": "Whitelist domains",
"description": "List of whitelisted domain names to be accessed from the VM. They will be resolved to IPs depending on where the VM end up. IPs can be used too.", "description": "List of whitelisted domain names to be accessed from the VM. They will be resolved to IPs depending on where the VM end up. IPs can be used too.",
...@@ -373,6 +348,9 @@ ...@@ -373,6 +348,9 @@
}, },
"unevaluatedProperties": false, "unevaluatedProperties": false,
"allOf": [ "allOf": [
{
"$ref": "./boot-image-input-schema.json#/$defs/instance-parameters"
},
{ {
"$ref": "#/$defs/instance-parameters" "$ref": "#/$defs/instance-parameters"
} }
......
...@@ -36,13 +36,15 @@ parts = ${:common-parts} ...@@ -36,13 +36,15 @@ parts = ${:common-parts}
recipe = zc.recipe.egg recipe = zc.recipe.egg
eggs = eggs =
qemu.qmp qemu.qmp
colorlog
qmpbackup qmpbackup
find-links += find-links +=
https://github.com/abbbi/qmpbackup/releases/download/v0.37/qmpbackup-0.37.tar.gz https://github.com/abbbi/qmpbackup/releases/download/v0.43/qmpbackup-0.43.tar.gz
[versions] [versions]
qemu.qmp = 0.0.3:whl qemu.qmp = 0.0.3:whl
qmpbackup = 0.37 colorlog = 6.9.0:whl
qmpbackup = 0.43
[python-with-eggs] [python-with-eggs]
recipe = zc.recipe.egg recipe = zc.recipe.egg
......
...@@ -6,6 +6,9 @@ set -e ...@@ -6,6 +6,9 @@ set -e
LC_ALL=C LC_ALL=C
export LC_ALL export LC_ALL
BACKUP_DIR={{ directory['backup'] }} BACKUP_DIR={{ directory['backup'] }}
# decolorize colorlog in qmpbackup
NO_COLOR=true
export NO_COLOR
log=$(mktemp --tmpdir={{ directory['tmp'] }}) log=$(mktemp --tmpdir={{ directory['tmp'] }})
trap "rm -f $log" EXIT TERM INT trap "rm -f $log" EXIT TERM INT
...@@ -25,6 +28,9 @@ if [ $RESULT -ne 0 ] ; then ...@@ -25,6 +28,9 @@ if [ $RESULT -ne 0 ] ; then
find $BACKUP_DIR/{{ disk['device'] }} -name '*.qcow2' -delete find $BACKUP_DIR/{{ disk['device'] }} -name '*.qcow2' -delete
$qmpbackup --level full || exit $? $qmpbackup --level full || exit $?
echo "Post take-over cleanup" echo "Post take-over cleanup"
elif egrep -q 'No full backup found for device.*{{ disk['device']}}.*in.*{{ disk['device']}}.*: Execute full backup first.' $log ; then
$qmpbackup --level full || exit $?
echo "Recovered from empty backup"
else else
exit $RESULT exit $RESULT
fi fi
......
...@@ -941,7 +941,11 @@ class TestInstanceResilientBackupImporter( ...@@ -941,7 +941,11 @@ class TestInstanceResilientBackupImporter(
# the real assertions comes from re-stabilizing the instance tree # the real assertions comes from re-stabilizing the instance tree
self.slap.waitForInstance(max_retry=10) self.slap.waitForInstance(max_retry=10)
# check that all stabilizes after backup after takeover # check that all stabilizes after backup after takeover
self.call_exporter() status_text = self.call_exporter()
self.assertIn(
'Post take-over cleanup',
status_text
)
self.slap.waitForInstance(max_retry=10) self.slap.waitForInstance(max_retry=10)
...@@ -951,10 +955,9 @@ class TestInstanceResilientBackupImporterIde( ...@@ -951,10 +955,9 @@ class TestInstanceResilientBackupImporterIde(
disk_type = 'ide' disk_type = 'ide'
@skipUnlessKvm class TestInstanceResilientBackupExporterMixin(
class TestInstanceResilientBackupExporter( TestInstanceResilientBackupMixin):
TestInstanceResilientBackupMixin, KVMTestCase): def initialBackup(self):
def test(self):
status_text = self.call_exporter() status_text = self.call_exporter()
self.assertEqual( self.assertEqual(
len(glob.glob(self.getBackupPartitionPath('FULL-*.qcow2'))), len(glob.glob(self.getBackupPartitionPath('FULL-*.qcow2'))),
...@@ -966,6 +969,44 @@ class TestInstanceResilientBackupExporter( ...@@ -966,6 +969,44 @@ class TestInstanceResilientBackupExporter(
'Recovered from partial backup by removing partial', 'Recovered from partial backup by removing partial',
status_text status_text
) )
self.assertNotIn(
'Recovered from empty backup',
status_text
)
self.assertNotIn(
'Post take-over cleanup',
status_text
)
@skipUnlessKvm
class TestInstanceResilientBackupExporter(
TestInstanceResilientBackupExporterMixin, KVMTestCase):
def test(self):
self.initialBackup()
@skipUnlessKvm
class TestInstanceResilientBackupExporterMigrateOld(
TestInstanceResilientBackupExporterMixin, KVMTestCase):
def test(self):
backup_partition = self.getPartitionPath(
'kvm-export', 'srv', 'backup', 'kvm')
backup_file_list = ['virtual.qcow2', 'virtual.qcow2.gz']
for backup_file in backup_file_list:
with open(os.path.join(backup_partition, backup_file), 'w') as fh:
fh.write('')
self.initialBackup()
post_backup_file_list = os.listdir(backup_partition)
for backup_file in backup_file_list:
self.assertNotIn(backup_file, post_backup_file_list)
@skipUnlessKvm
class TestInstanceResilientBackupExporterPartialRecovery(
TestInstanceResilientBackupExporterMixin, KVMTestCase):
def test(self):
self.initialBackup()
# cover .partial file in the backup directory with fallback to full # cover .partial file in the backup directory with fallback to full
current_backup = glob.glob(self.getBackupPartitionPath('FULL-*'))[0] current_backup = glob.glob(self.getBackupPartitionPath('FULL-*'))[0]
with open(current_backup + '.partial', 'w') as fh: with open(current_backup + '.partial', 'w') as fh:
...@@ -986,12 +1027,56 @@ class TestInstanceResilientBackupExporter( ...@@ -986,12 +1027,56 @@ class TestInstanceResilientBackupExporter(
'kvm-export', 'etc', 'plugin', 'check-backup-directory.py')))) 'kvm-export', 'etc', 'plugin', 'check-backup-directory.py'))))
@skipUnlessKvm
class TestInstanceResilientBackupExporterEmptyRecovery(
TestInstanceResilientBackupExporterMixin, KVMTestCase):
def test(self):
self.initialBackup()
# cover empty backup recovery
current_backup_list = glob.glob(self.getBackupPartitionPath('*.qcow2'))
self.assertEqual(
1,
len(current_backup_list)
)
for file in current_backup_list:
os.unlink(file)
status_text = self.call_exporter()
self.assertEqual(
len(glob.glob(self.getBackupPartitionPath('FULL-*.qcow2'))),
1)
self.assertEqual(
len(glob.glob(self.getBackupPartitionPath('INC-*.qcow2'))),
0)
self.assertIn(
'Recovered from empty backup',
status_text
)
@skipUnlessKvm @skipUnlessKvm
class TestInstanceResilientBackupExporterIde( class TestInstanceResilientBackupExporterIde(
TestInstanceResilientBackupExporter): TestInstanceResilientBackupExporter):
disk_type = 'ide' disk_type = 'ide'
@skipUnlessKvm
class TestInstanceResilientBackupExporterMigrateOldIde(
TestInstanceResilientBackupExporterMigrateOld):
disk_type = 'ide'
@skipUnlessKvm
class TestInstanceResilientBackupExporterPartialRecoveryIde(
TestInstanceResilientBackupExporterPartialRecovery):
disk_type = 'ide'
@skipUnlessKvm
class TestInstanceResilientBackupExporterEmptyRecoveryIde(
TestInstanceResilientBackupExporterEmptyRecovery):
disk_type = 'ide'
@skipUnlessKvm @skipUnlessKvm
class TestInstanceResilient(KVMTestCase, KvmMixin): class TestInstanceResilient(KVMTestCase, KvmMixin):
__partition_reference__ = 'ir' __partition_reference__ = 'ir'
......
...@@ -67,7 +67,7 @@ ...@@ -67,7 +67,7 @@
"description": "Only track references.", "description": "Only track references.",
"default": false, "default": false,
"type": "boolean" "type": "boolean"
}, }
}, },
"type": "object" "type": "object"
}, },
......
# 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 = 2a578c1dfea2b7ebe83bbacb052127c0
[software.json]
filename = software.cfg.json
md5sum = d40a0e467955be469645c517a3ca4881
[instance.json]
filename = ../kvm/boot-image-input-schema.json
md5sum = 83f45b6fd98dc988c548ab5f14dcdbe6
[buildout]
parts =
switch_softwaretype
eggs-directory = ${buildout:eggs-directory}
develop-eggs-directory = ${buildout:develop-eggs-directory}
[switch_softwaretype]
recipe = slapos.cookbook:switch-softwaretype
default = dynamic-template-kvm:output
[slap-configuration]
# we usejsonschema recipe in order to force some values for VPS (see all the const in the JSON schema)
<= slap-connection
recipe = slapos.cookbook:slapconfiguration.jsonschema
jsonschema = ${software.json:target}
set-default = main
validate-parameters = main
[slap-configuration-vps]
# this section will force all constant values for VPS
recipe = slapos.recipe.build
depends = $${slap-configuration:configuration}
init =
conf = self.buildout['slap-configuration']['configuration']
# we know for sure that there is only the boot-image parameters in conf
# so only set what is custom compared to default values
conf['ram-size'] = 245760
conf['ram-max-size'] = 246272
conf['auto-ballooning'] = False
conf['cpu-count'] = 40
conf['cpu-max-count'] = 41
conf['wipe-disk-ondestroy'] = True
conf['use-tap'] = True
conf['frontend-software-type'] = "default"
conf['frontend-software-url'] = "http://git.erp5.org/gitweb/slapos.git/blob_plain/HEAD:/software/apache-frontend/software.cfg"
conf['frontend-additional-software-type'] = "default"
conf['frontend-additional-software-url'] = "chinary-frontend-sr"
conf['disk-device-path'] = "/dev/sdb"
options['configuration'] = conf
# XXX we should make sure this configuration matches KVM json schema...
[jinja2-template-base]
recipe = slapos.recipe.template:jinja2
output = $${buildout:directory}/$${:filename}
extensions = jinja2.ext.do
extra-context =
context =
key develop_eggs_directory buildout:develop-eggs-directory
key eggs_directory buildout:eggs-directory
key ipv4 slap-configuration:ipv4
key ipv6 slap-configuration:ipv6
key global_ipv4_prefix network-information:global-ipv4-network
key storage_dict slap-configuration:storage-dict
key slapparameter_dict slap-configuration-vps:configuration
key computer_id slap-configuration:computer-id
raw openssl_executable_location ${openssl:location}/bin/openssl
$${:extra-context}
[dynamic-template-kvm]
<= jinja2-template-base
url = ${template-kvm:location}/instance-kvm.cfg.jinja2
filename = template-kvm.cfg
extra-context =
section slap_configuration slap-configuration
raw ansible_promise_tpl ${template-ansible-promise:target}
raw curl_executable_location ${curl:location}/bin/curl
raw dash_executable_location ${dash:location}/bin/dash
raw dnsresolver_executable ${buildout:bin-directory}/dnsresolver
raw dcron_executable_location ${dcron:location}/sbin/crond
raw boot_image_select_source_config ${boot-image-select-source-config:target}
raw whitelist_domains_default ${whitelist-domains-default:target}
raw whitelist_firewall_download_controller ${whitelist-firewall-download-controller:output}
raw image_download_controller ${image-download-controller:output}
raw image_download_config_creator ${image-download-config-creator:output}
raw logrotate_cfg ${template-logrotate-base:output}
raw novnc_location ${noVNC:location}
raw netcat_bin ${netcat:location}/bin/netcat
raw nginx_executable ${nginx-output:nginx}
raw nginx_mime ${nginx-output:mime}
raw python_executable ${buildout:executable}
raw python_eggs_executable ${buildout:bin-directory}/${python-with-eggs:interpreter}
raw qemu_executable_location ${qemu:location}/bin/qemu-system-x86_64
raw qemu_img_executable_location ${qemu:location}/bin/qemu-img
raw qemu_start_promise_tpl ${template-qemu-ready:target}
raw sixtunnel_executable_location ${6tunnel:location}/bin/6tunnel
raw template_httpd_cfg ${template-httpd:output}
raw template_content ${template-content:target}
raw template_kvm_controller_run ${template-kvm-controller:target}
raw template_kvm_run ${template-kvm-run:target}
raw template_monitor ${monitor2-template:output}
raw template_nginx ${template-nginx:target}
raw websockify_executable_location ${buildout:directory}/bin/websockify
raw wipe_disk_wrapper ${buildout:directory}/bin/securedelete
template-parts-destination = ${template-parts:target}
template-replicated-destination = ${template-replicated:target}
import-list = file parts :template-parts-destination
file replicated :template-replicated-destination
[buildout]
extends =
../kvm/software.cfg
buildout.hash.cfg
parts += instance.json
[download-vps-base]
# we cannot use "download-base" section because:
# 1. we need _profile_base_location to point to current directory for our own files
# 2. we need json to be in specific directory
recipe = slapos.recipe.build:download
url = ${:_profile_base_location_}/${:filename}
[directory]
recipe = slapos.recipe.build:mkdirectory
json-vps = ${buildout:parts-directory}/json-schema/vps
json-kvm = ${buildout:parts-directory}/json-schema/kvm
[software.json]
<= download-vps-base
destination = ${directory:json-vps}/${:filename}
[instance.json]
<= download-vps-base
destination = ${directory:json-kvm}/${:filename}
[template]
<= template-base
# we need to overwrite _profile_base_location to current directory
url = ${:_profile_base_location_}/${:filename}
{
"name": "VPS",
"description": "VPS",
"serialisation": "json-in-xml",
"software-type": {
"default": {
"title": "Default",
"description": "Default VPS",
"request": "../kvm/boot-image-input-schema.json",
"response": "../kvm/instance-kvm-output-schema.json",
"index": 0
}
}
}
...@@ -360,12 +360,12 @@ sgmllib3k = 1.0.0 ...@@ -360,12 +360,12 @@ sgmllib3k = 1.0.0
simplegeneric = 0.8.1 simplegeneric = 0.8.1
singledispatch = 3.4.0.3 singledispatch = 3.4.0.3
six = 1.16.0 six = 1.16.0
slapos.cookbook = 1.0.373 slapos.cookbook = 1.0.386
slapos.core = 1.14.3 slapos.core = 1.14.3
slapos.extension.shared = 1.0 slapos.extension.shared = 1.0
slapos.libnetworkcache = 0.25 slapos.libnetworkcache = 0.25
slapos.rebootstrap = 4.7 slapos.rebootstrap = 4.7
slapos.recipe.build = 0.57 slapos.recipe.build = 0.58
slapos.recipe.cmmi = 0.22 slapos.recipe.cmmi = 0.22
slapos.recipe.template = 5.1 slapos.recipe.template = 5.1
slapos.toolbox = 0.146 slapos.toolbox = 0.146
......
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