Commit 3fba7c6e authored by Thomas Gambier's avatar Thomas Gambier 🚴🏼

Update Release Candidate

parents cbf7bd47 70b7c017
...@@ -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.326' version = '1.0.329'
name = 'slapos.cookbook' name = 'slapos.cookbook'
long_description = open("README.rst").read() long_description = open("README.rst").read()
......
...@@ -58,6 +58,7 @@ class Recipe(GenericBaseRecipe): ...@@ -58,6 +58,7 @@ class Recipe(GenericBaseRecipe):
"\npath_list = %s" % ",".join(software_path_list) "\npath_list = %s" % ",".join(software_path_list)
CONFIG['computer_id'] = self.buildout['slap-connection']['computer-id'] CONFIG['computer_id'] = self.buildout['slap-connection']['computer-id']
CONFIG['server_url'] = self.buildout['slap-connection']['server-url'] CONFIG['server_url'] = self.buildout['slap-connection']['server-url']
CONFIG['shared_part_list'] = CONFIG['shared_part_list'].replace('\n', '\n ')
configuration_file = self.createFile( configuration_file = self.createFile(
self.options['configuration-file'], self.options['configuration-file'],
self.substituteTemplate( self.substituteTemplate(
......
...@@ -2,7 +2,8 @@ ...@@ -2,7 +2,8 @@
slapos_directory = %(slapos_directory)s slapos_directory = %(slapos_directory)s
working_directory = %(working_directory)s working_directory = %(working_directory)s
test_suite_directory = %(test_suite_directory)s test_suite_directory = %(test_suite_directory)s
shared_part_list = %(shared_part_list)s shared_part_list =
%(shared_part_list)s
software_directory = %(software_directory)s software_directory = %(software_directory)s
log_directory = %(log_directory)s log_directory = %(log_directory)s
run_directory = %(run_directory)s run_directory = %(run_directory)s
......
...@@ -15,4 +15,4 @@ ...@@ -15,4 +15,4 @@
[template] [template]
filename = instance.cfg filename = instance.cfg
md5sum = 06379c0ed1fe0df409c7b8f61fc218eb md5sum = ed0f91f39d5eda903938aa527625f40d
...@@ -28,13 +28,20 @@ test-working-dir = ${buildout:directory}/tmp ...@@ -28,13 +28,20 @@ test-working-dir = ${buildout:directory}/tmp
nxdtest-working-dir = ${:var}/nxdtest nxdtest-working-dir = ${:var}/nxdtest
[slapos-test-runner-nxdtest-environment.sh] [slapos-test-runner-nxdtest-environment.sh]
recipe = slapos.recipe.template recipe = slapos.recipe.template:jinja2
output = ${directory:etc}/${:_buildout_section_name_} output = ${directory:etc}/${:_buildout_section_name_}
PATH={{ buildout['bin-directory'] }}:{{ curl_location }}/bin:{{ faketime_location }}/bin:{{ openssl_location }}/bin:/usr/bin:/bin
context =
section slap slap-configuration
key ipv6_random slap-configuration:ipv6-random
{%- raw %}
inline = inline =
export PATH={{ buildout['bin-directory'] }}:{{ curl_location }}/bin:{{ faketime_location }}/bin:{{ openssl_location }}/bin:/usr/bin:/bin export PATH=${:PATH}
export SLAPOS_TEST_IPV4=${slap-configuration:ipv4-random} export SLAPOS_TEST_IPV4=${slap-configuration:ipv4-random}
export SLAPOS_TEST_IPV6=${slap-configuration:ipv6-random} export SLAPOS_TEST_IPV6={{ slap.get('ipv6-range-network') or ipv6_random }}
export SLAPOS_TEST_WORKING_DIR=${directory:test-working-dir} export SLAPOS_TEST_WORKING_DIR=${directory:test-working-dir}
{%- endraw %}
[slapos-test-runner-dot-nxdtest] [slapos-test-runner-dot-nxdtest]
recipe = slapos.recipe.template:jinja2 recipe = slapos.recipe.template:jinja2
......
...@@ -15,19 +15,19 @@ ...@@ -15,19 +15,19 @@
[instance-theia] [instance-theia]
_update_hash_filename_ = instance-theia.cfg.jinja.in _update_hash_filename_ = instance-theia.cfg.jinja.in
md5sum = a9d4ace568acdd5002d587816ab91737 md5sum = b406265f591f54a0d5a6aa3ff8522764
[instance] [instance]
_update_hash_filename_ = instance.cfg.in _update_hash_filename_ = instance.cfg.in
md5sum = 08b8aa2b7f59ac0e4e5d4ca180054937 md5sum = f322033a7670b9be29b1bf1bf9024b87
[instance-import] [instance-import]
_update_hash_filename_ = instance-import.cfg.jinja.in _update_hash_filename_ = instance-import.cfg.jinja.in
md5sum = a343818079d4fc106594e5850cc1853a md5sum = 6520d2aa0c1c6094cbf276080594ec1a
[instance-export] [instance-export]
_update_hash_filename_ = instance-export.cfg.jinja.in _update_hash_filename_ = instance-export.cfg.jinja.in
md5sum = 84ceb4c9ee0f07fce8518ef7517ce1d4 md5sum = bb6d26c56b4bb9cf553c130fdd51000d
[instance-resilient] [instance-resilient]
_update_hash_filename_ = instance-resilient.cfg.jinja _update_hash_filename_ = instance-resilient.cfg.jinja
...@@ -35,7 +35,7 @@ md5sum = ad9499e7355ded4975ad313442cecb7a ...@@ -35,7 +35,7 @@ md5sum = ad9499e7355ded4975ad313442cecb7a
[slapos-standalone-script] [slapos-standalone-script]
_update_hash_filename_ = slapos_standalone_script.py.jinja _update_hash_filename_ = slapos_standalone_script.py.jinja
md5sum = 6792d29057db35ea69b01e72a5c913e3 md5sum = 3572b3fa458505ae25ebcea9b1ed3267
[theia-common] [theia-common]
_update_hash_filename_ = theia_common.py _update_hash_filename_ = theia_common.py
......
...@@ -42,6 +42,7 @@ context = ...@@ -42,6 +42,7 @@ context =
raw slapos_cfg $${directory:runner}/etc/slapos.cfg raw slapos_cfg $${directory:runner}/etc/slapos.cfg
raw project_path $${directory:project} raw project_path $${directory:project}
raw public_path $${directory:frontend-static-public} raw public_path $${directory:frontend-static-public}
raw statefiles_path $${directory:statefiles}
key exitfile :exitcode-file key exitfile :exitcode-file
key errorfile :error-file key errorfile :error-file
{%- raw %} {%- raw %}
...@@ -55,6 +56,7 @@ inline = ...@@ -55,6 +56,7 @@ inline =
--cfg {{ slapos_cfg }} \ --cfg {{ slapos_cfg }} \
--dirs {{ project_path }} \ --dirs {{ project_path }} \
--dirs {{ public_path }} \ --dirs {{ public_path }} \
--dirs {{ statefiles_path }} \
--exitfile {{ exitfile }} \ --exitfile {{ exitfile }} \
--errorfile {{ errorfile }} --errorfile {{ errorfile }}
{%- endraw %} {%- endraw %}
......
...@@ -102,6 +102,7 @@ context = ...@@ -102,6 +102,7 @@ context =
raw slapos_cfg $${directory:runner}/etc/slapos.cfg raw slapos_cfg $${directory:runner}/etc/slapos.cfg
raw project_path $${directory:project} raw project_path $${directory:project}
raw public_path $${directory:frontend-static-public} raw public_path $${directory:frontend-static-public}
raw statefiles_path $${directory:statefiles}
key exitfile :exitcode-file key exitfile :exitcode-file
key errorfile :error-file key errorfile :error-file
{%- raw %} {%- raw %}
...@@ -122,6 +123,7 @@ inline = ...@@ -122,6 +123,7 @@ inline =
--cfg {{ slapos_cfg }} \ --cfg {{ slapos_cfg }} \
--dirs {{ project_path }} \ --dirs {{ project_path }} \
--dirs {{ public_path }} \ --dirs {{ public_path }} \
--dirs {{ statefiles_path }} \
--exitfile {{ exitfile }} \ --exitfile {{ exitfile }} \
--errorfile {{ errorfile }} --errorfile {{ errorfile }}
{%- endraw %} {%- endraw %}
......
...@@ -38,7 +38,7 @@ additional-url = $${remote-additional-frontend:connection-secure_access} ...@@ -38,7 +38,7 @@ additional-url = $${remote-additional-frontend:connection-secure_access}
username = $${frontend-instance-password:username} username = $${frontend-instance-password:username}
password = $${frontend-instance-password:passwd} password = $${frontend-instance-password:passwd}
backend-url = $${frontend-instance:url} backend-url = $${frontend-instance:url}
ipv6 = {{ ipv6_random }} ipv6 = {{ ipv6_theia }}
[directory] [directory]
recipe = slapos.cookbook:mkdirectory recipe = slapos.cookbook:mkdirectory
...@@ -50,6 +50,7 @@ bin = $${:home}/bin ...@@ -50,6 +50,7 @@ bin = $${:home}/bin
tmp = $${:home}/tmp tmp = $${:home}/tmp
dot-theia = $${:home}/.theia/ dot-theia = $${:home}/.theia/
pidfiles = $${:var}/run pidfiles = $${:var}/run
statefiles = $${:var}/state
services = $${:etc}/service services = $${:etc}/service
runner = $${:srv}/runner runner = $${:srv}/runner
...@@ -227,7 +228,7 @@ storage-path = $${buildout:parts-directory}/.$${:_buildout_section_name_} ...@@ -227,7 +228,7 @@ storage-path = $${buildout:parts-directory}/.$${:_buildout_section_name_}
recipe = slapos.cookbook:free_port recipe = slapos.cookbook:free_port
minimum = 3000 minimum = 3000
maximum = 3100 maximum = 3100
ip = {{ ipv6_random }} ip = {{ ipv6_theia }}
[frontend-instance-certificate] [frontend-instance-certificate]
recipe = plone.recipe.command recipe = plone.recipe.command
...@@ -421,7 +422,7 @@ inline = ...@@ -421,7 +422,7 @@ inline =
#!/bin/sh #!/bin/sh
export HOME=$${directory:home} export HOME=$${directory:home}
export PATH=${cli-utilities:PATH}:$HOME/.cargo/bin:$HOME/.local/bin:$PATH export PATH=${cli-utilities:PATH}:$HOME/.cargo/bin:$HOME/.local/bin:$PATH
export IPV6_SLAPRUNNER={{ ipv6_random }} export IPV6_SLAPRUNNER={{ ipv6_theia }}
# Theia Backend # Theia Backend
# ------------- # -------------
...@@ -566,7 +567,7 @@ ip = {{ ipv4_random }} ...@@ -566,7 +567,7 @@ ip = {{ ipv4_random }}
[slapos-standalone-config] [slapos-standalone-config]
ipv4 = {{ ipv4_random }} ipv4 = {{ ipv4_random }}
ipv6 = {{ ipv6_random }} ipv6 = {{ slap_resource.get('ipv6-range-network') or ipv6_theia }}
port = $${slapos-standalone-port:port} port = $${slapos-standalone-port:port}
base-directory = $${directory:runner} base-directory = $${directory:runner}
software-root = $${directory:runner}/software software-root = $${directory:runner}/software
...@@ -589,7 +590,8 @@ inline = ...@@ -589,7 +590,8 @@ inline =
[slapos-standalone-script] [slapos-standalone-script]
recipe = slapos.recipe.template:jinja2 recipe = slapos.recipe.template:jinja2
output = $${directory:bin}/$${:_buildout_section_name_} output = $${directory:bin}/$${:_buildout_section_name_}
embedded-request-exitcode-file = $${directory:etc}/embedded-request-exitcode embedded-request-exitcode-file = $${directory:statefiles}/embedded-request.exitcode
standalone-ran-before-flag = $${directory:statefiles}/standalone-ran-before.flag
shared-part-list = shared-part-list =
{{ """${buildout:shared-part-list}""" | indent(2) }} {{ """${buildout:shared-part-list}""" | indent(2) }}
context = context =
...@@ -599,11 +601,12 @@ context = ...@@ -599,11 +601,12 @@ context =
key request_script_template request-script-example:inline key request_script_template request-script-example:inline
key shared_part_list :shared-part-list key shared_part_list :shared-part-list
key embedded_request_exitcode_file :embedded-request-exitcode-file key embedded_request_exitcode_file :embedded-request-exitcode-file
key standalone_ran_before_flag :standalone-ran-before-flag
key embedded_instance_config embedded-instance-config:output key embedded_instance_config embedded-instance-config:output
key home_path directory:home key home_path directory:home
key forward_frontend_requests :forward-frontend-requests key forward_frontend_requests :forward-frontend-requests
section slap_connection slap-connection section slap_connection slap-connection
section slapos_standalone_config slapos-standalone-config section config slapos-standalone-config
forward-frontend-requests = {{ parameter_dict['forward-slapos-frontend-requests'] }} forward-frontend-requests = {{ parameter_dict['forward-slapos-frontend-requests'] }}
url = ${slapos-standalone-script:output} url = ${slapos-standalone-script:output}
......
...@@ -37,8 +37,9 @@ context = ...@@ -37,8 +37,9 @@ context =
key parameter_dict slap-configuration:configuration key parameter_dict slap-configuration:configuration
key root_title slap-configuration:root-instance-title key root_title slap-configuration:root-instance-title
key partition_root_path buildout:directory key partition_root_path buildout:directory
key ipv6_random slap-configuration:ipv6-random key ipv6_theia slap-configuration:ipv6-random
key ipv4_random slap-configuration:ipv4-random key ipv4_random slap-configuration:ipv4-random
section slap_resource slap-configuration
import os os import os os
import json json import json json
default-parameters = default-parameters =
......
...@@ -70,23 +70,23 @@ def setupStandalone(): ...@@ -70,23 +70,23 @@ def setupStandalone():
shared_parts = {{ repr(shared_part_list) }} shared_parts = {{ repr(shared_part_list) }}
shared_part_list = [x.strip() for x in shared_parts.splitlines() if x.strip()] shared_part_list = [x.strip() for x in shared_parts.splitlines() if x.strip()]
standalone = slapos.slap.standalone.StandaloneSlapOS( standalone = slapos.slap.standalone.StandaloneSlapOS(
{{ repr(slapos_standalone_config['base-directory']) }}, {{ repr(config['base-directory']) }},
{{ repr(slapos_standalone_config['ipv4']) }}, {{ repr(config['ipv4']) }},
{{ slapos_standalone_config['port'] }}, {{ config['port'] }},
computer_id={{ repr(slapos_standalone_config['computer-id']) }}, computer_id={{ repr(config['computer-id']) }},
shared_part_list=shared_part_list, shared_part_list=shared_part_list,
software_root={{ repr(slapos_standalone_config['software-root']) }}, software_root={{ repr(config['software-root']) }},
instance_root={{ repr(slapos_standalone_config['instance-root']) }}, instance_root={{ repr(config['instance-root']) }},
partition_forward_configuration=partition_forward_configuration, partition_forward_configuration=partition_forward_configuration,
slapos_bin={{ repr(slapos_standalone_config['slapos-bin']) }}, slapos_bin={{ repr(config['slapos-bin']) }},
local_software_release_root={{ repr(slapos_standalone_config['local-software-release-root']) }}, local_software_release_root={{ repr(config['local-software-release-root']) }},
) )
standalone.start() standalone.start()
try: try:
partition_count = 20 partition_count = 20
logging.info("Standalone SlapOS: Formatting %d partitions", partition_count) logging.info("Standalone SlapOS: Formatting %d partitions", partition_count)
standalone.format(partition_count, {{ repr(slapos_standalone_config['ipv4']) }}, {{ repr(slapos_standalone_config['ipv6']) }}) standalone.format(partition_count, {{ repr(config['ipv4']) }}, {{ repr(config['ipv6']) }})
logging.info("Standalone SlapOS for computer `%s` started", {{ repr(slapos_standalone_config['computer-id']) }}) logging.info("Standalone SlapOS for computer `%s` started", {{ repr(config['computer-id']) }})
# Run instance at least once, to start the supervisor managing instances. # Run instance at least once, to start the supervisor managing instances.
try: try:
standalone.waitForInstance(max_retry=0) standalone.waitForInstance(max_retry=0)
...@@ -153,10 +153,28 @@ def main(): ...@@ -153,10 +153,28 @@ def main():
with setupStandalone() as standalone: with setupStandalone() as standalone:
config_json_file = {{ repr(embedded_instance_config) }} config_json_file = {{ repr(embedded_instance_config) }}
done_file = config_json_file + '.done'
if not os.path.exists(done_file): # backwards compatibility
with open(done_file, 'w'): pass old_flag_file = config_json_file + '.done'
old_exitcode_file = os.path.join(
{{ repr(home_path) }}, 'etc', 'embedded-request-exitcode')
# new state filesstandalone_ran_before_flag
standalone_ran_before_flag = {{ repr(standalone_ran_before_flag) }}
exitcode_file = {{ repr(embedded_request_exitcode_file) }}
# backwards compatibility
if os.path.exists(old_flag_file):
logging.info("Moving old %s to %s", old_flag_file, standalone_ran_before_flag)
os.rename(old_flag_file, standalone_ran_before_flag)
if os.path.exists(old_exitcode_file):
logging.info("Moving old %s to %s", old_exitcode_file, exitcode_file)
os.rename(old_exitcode_file, exitcode_file)
elif not os.path.exists(standalone_ran_before_flag):
logging.info("First run!")
logging.info("Creating flag file %s", standalone_ran_before_flag)
with open(standalone_ran_before_flag, 'x'): pass
try: try:
config = parseEmbeddedInstanceConfig(config_json_file) config = parseEmbeddedInstanceConfig(config_json_file)
except Exception: except Exception:
...@@ -172,14 +190,14 @@ def main(): ...@@ -172,14 +190,14 @@ def main():
'SLAPOS_CONFIGURATION': standalone._slapos_config, 'SLAPOS_CONFIGURATION': standalone._slapos_config,
'SLAPOS_CLIENT_CONFIGURATION': standalone._slapos_config, 'SLAPOS_CLIENT_CONFIGURATION': standalone._slapos_config,
}) })
with open({{ repr(embedded_request_exitcode_file) }}, 'w') as f: with open(exitcode_file, 'w') as f:
f.write(str(exitcode)) f.write(str(exitcode))
except Exception: except Exception:
logging.info("Failed to request embedded instance", exc_info=True) logging.info("Failed to request embedded instance", exc_info=True)
s = socket.socket(socket.AF_UNIX) s = socket.socket(socket.AF_UNIX)
s.bind({{ repr('\0' + slapos_standalone_config['abstract-socket-path']) }}) s.bind({{ repr('\0' + config['abstract-socket-path']) }})
s.listen(5) s.listen(5)
logging.info("Standalone SlapOS ready") logging.info("Standalone SlapOS ready")
......
...@@ -34,6 +34,7 @@ import subprocess ...@@ -34,6 +34,7 @@ import subprocess
import sqlite3 import sqlite3
import time import time
import netaddr
import pexpect import pexpect
import psutil import psutil
import requests import requests
...@@ -241,6 +242,19 @@ class TestTheia(TheiaTestCase): ...@@ -241,6 +242,19 @@ class TestTheia(TheiaTestCase):
self.assertIn(b'slaprunner', self.captureSlapos('proxy', 'show')) self.assertIn(b'slaprunner', self.captureSlapos('proxy', 'show'))
self.assertIn(b'slaprunner', self.captureSlapos('computer', 'list')) self.assertIn(b'slaprunner', self.captureSlapos('computer', 'list'))
def test_ipv6_range(self):
proxy_path = self.getPath('srv', 'runner', 'var', 'proxy.db')
query = "SELECT partition_reference, address FROM partition_network%s" % DB_VERSION
with sqlite3.connect(proxy_path) as db:
rows = db.execute(query).fetchall()
partitions = set(p for p, _ in rows)
ipv6 = set(addr for _, addr in rows if netaddr.valid_ipv6(addr))
# Check that each partition has a different IPv6
self.assertEqual(len(partitions), len(ipv6))
# Check that no partition has the same IPv6 as theia
self.assertNotIn(self.connection_parameters['ipv6'], ipv6)
class TestTheiaWithNonAsciiInstanceName(TestTheia): class TestTheiaWithNonAsciiInstanceName(TestTheia):
default_partition_reference = '💥' default_partition_reference = '💥'
...@@ -524,6 +538,10 @@ class ResilientTheiaMixin(object): ...@@ -524,6 +538,10 @@ class ResilientTheiaMixin(object):
def getPartitionPath(cls, instance_type='export', *paths): def getPartitionPath(cls, instance_type='export', *paths):
return os.path.join(cls.slap._instance_root, cls.getPartitionId(instance_type), *paths) return os.path.join(cls.slap._instance_root, cls.getPartitionId(instance_type), *paths)
@classmethod
def getPath(cls, *components): # patch getPath
return cls.getPartitionPath('export', *components)
@classmethod @classmethod
def _getSlapos(cls, instance_type='export'): def _getSlapos(cls, instance_type='export'):
return cls.getPartitionPath(instance_type, 'srv', 'runner', 'bin', 'slapos') return cls.getPartitionPath(instance_type, 'srv', 'runner', 'bin', 'slapos')
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import errno import errno
import json
import os import os
import re import re
import shutil import shutil
...@@ -38,11 +39,15 @@ import requests ...@@ -38,11 +39,15 @@ import requests
from slapos.proxy.db_version import DB_VERSION from slapos.proxy.db_version import DB_VERSION
from slapos.slap.slap import DEFAULT_SOFTWARE_TYPE
from slapos.testing.testcase import SlapOSNodeCommandError, installSoftwareUrlList from slapos.testing.testcase import SlapOSNodeCommandError, installSoftwareUrlList
import test
from test import TheiaTestCase, ResilientTheiaMixin, theia_software_release_url from test import TheiaTestCase, ResilientTheiaMixin, theia_software_release_url
dummy_software_url = os.path.abspath( dummy_software_url = os.path.abspath(
os.path.join('resilience_dummy', 'software.cfg')) os.path.join('resilience_dummy', 'software.cfg'))
...@@ -82,8 +87,7 @@ class ResilientTheiaTestCase(ResilientTheiaMixin, TheiaTestCase): ...@@ -82,8 +87,7 @@ class ResilientTheiaTestCase(ResilientTheiaMixin, TheiaTestCase):
cls.checkSlapos('node', 'instance', instance_type=instance_type) cls.checkSlapos('node', 'instance', instance_type=instance_type)
@classmethod @classmethod
def _deployEmbeddedSoftware(cls, software_url, instance_name, retries=0, instance_type='export'): def _processEmbeddedSoftware(cls, retries=0, instance_type='export'):
cls.callSlapos('supply', software_url, 'slaprunner', instance_type=instance_type)
for _ in range(retries): for _ in range(retries):
try: try:
output = cls.captureSlapos('node', 'software', instance_type=instance_type, stderr=subprocess.STDOUT) output = cls.captureSlapos('node', 'software', instance_type=instance_type, stderr=subprocess.STDOUT)
...@@ -96,6 +100,11 @@ class ResilientTheiaTestCase(ResilientTheiaMixin, TheiaTestCase): ...@@ -96,6 +100,11 @@ class ResilientTheiaTestCase(ResilientTheiaMixin, TheiaTestCase):
print("Wait before running slapos node software one last time") print("Wait before running slapos node software one last time")
time.sleep(120) time.sleep(120)
cls.checkSlapos('node', 'software', instance_type=instance_type) cls.checkSlapos('node', 'software', instance_type=instance_type)
@classmethod
def _deployEmbeddedSoftware(cls, software_url, instance_name, retries=0, instance_type='export'):
cls.callSlapos('supply', software_url, 'slaprunner', instance_type=instance_type)
cls._processEmbeddedSoftware(retries, instance_type)
cls.callSlapos('request', instance_name, software_url, instance_type=instance_type) cls.callSlapos('request', instance_name, software_url, instance_type=instance_type)
cls._processEmbeddedInstance(retries, instance_type) cls._processEmbeddedInstance(retries, instance_type)
...@@ -435,7 +444,8 @@ class TestTheiaExportAndImport(ResilienceMixin, ExportAndImportMixin, ResilientT ...@@ -435,7 +444,8 @@ class TestTheiaExportAndImport(ResilienceMixin, ExportAndImportMixin, ResilientT
class TakeoverMixin(ExportAndImportMixin): class TakeoverMixin(ExportAndImportMixin):
def _getTakeoverUrlAndPassword(self, scope="theia-1"): def _getTakeoverUrlAndPassword(self, scope="theia-1"):
parameter_dict = self.computer_partition.getConnectionParameterDict() partition = self.requestDefaultInstance() # re-request for up-to-date info
parameter_dict = partition.getConnectionParameterDict()
takeover_url = parameter_dict["takeover-%s-url" % scope] takeover_url = parameter_dict["takeover-%s-url" % scope]
takeover_password = parameter_dict["takeover-%s-password" % scope] takeover_password = parameter_dict["takeover-%s-password" % scope]
return takeover_url, takeover_password return takeover_url, takeover_password
...@@ -488,8 +498,18 @@ class TakeoverMixin(ExportAndImportMixin): ...@@ -488,8 +498,18 @@ class TakeoverMixin(ExportAndImportMixin):
self.assertIn("Success", resp.text, "An Error occured: %s" % resp.text) self.assertIn("Success", resp.text, "An Error occured: %s" % resp.text)
return resp.text return resp.text
def _doTakeover(self):
# Takeover
takeover_url, takeover_password = self._getTakeoverUrlAndPassword()
self._requestTakeover(takeover_url, takeover_password)
# Wait for import instance to become export instance and new import to be allocated
# This also checks that all promises of theia instances succeed
self.slap.waitForInstance(self.instance_max_retry)
self.computer_partition = self.requestDefaultInstance()
class TheiaSyncMixin(ResilienceMixin, TakeoverMixin):
class TheiaSyncMixin(TakeoverMixin, ResilienceMixin):
def _doSync(self, max_tries=None, wait_interval=None): def _doSync(self, max_tries=None, wait_interval=None):
max_tries = max_tries or self.backup_max_tries max_tries = max_tries or self.backup_max_tries
wait_interval = wait_interval or self.backup_wait_interval wait_interval = wait_interval or self.backup_wait_interval
...@@ -537,17 +557,10 @@ class TestTheiaResilience(TheiaSyncMixin, ResilientTheiaTestCase): ...@@ -537,17 +557,10 @@ class TestTheiaResilience(TheiaSyncMixin, ResilientTheiaTestCase):
def _checkSync(self): def _checkSync(self):
# Check that ~/etc still contains everything it did before # Check that ~/etc still contains everything it did before
etc_listdir = os.listdir(self.getPartitionPath('import', 'etc')) etc_listdir = os.listdir(self.getPartitionPath('import', 'etc'))
self.assertTrue(set(self.etc_listdir).issubset(etc_listdir)) try:
self.assertTrue(set(self.etc_listdir).issubset(etc_listdir))
def _doTakeover(self): except AssertionError:
# Takeover breakpoint()
takeover_url, takeover_password = self._getTakeoverUrlAndPassword()
self._requestTakeover(takeover_url, takeover_password)
# Wait for import instance to become export instance and new import to be allocated
# This also checks that all promises of theia instances succeed
self.slap.waitForInstance(self.instance_max_retry)
self.computer_partition = self.requestDefaultInstance()
def _checkTakeover(self): def _checkTakeover(self):
# Check that there is an export, import and frozen instance and get their new partition IDs # Check that there is an export, import and frozen instance and get their new partition IDs
...@@ -601,3 +614,43 @@ class TestTheiaFrontendForwarding(TheiaSyncMixin, ResilientTheiaTestCase): ...@@ -601,3 +614,43 @@ class TestTheiaFrontendForwarding(TheiaSyncMixin, ResilientTheiaTestCase):
def _doTakeover(self): def _doTakeover(self):
# do nothing # do nothing
pass pass
class TestTheiaResilienceWithInitialInstance(TestTheiaResilience, test.TestTheiaWithEmbeddedInstance):
backup_max_tries = 70
backup_wait_interval = 10
sr_url = dummy_software_url
sr_type = DEFAULT_SOFTWARE_TYPE
sr_config = {}
@classmethod
def getInstanceParameterDict(cls, sr_url=None, sr_type=None, sr_config=None):
d = test.TestTheiaWithEmbeddedInstance.getInstanceParameterDict.__func__(
cls, sr_url, sr_type, sr_config)
d.update(autorun='stopped')
return d
def _prepareExport(self):
# Check that there is an export and import instance and get their partition IDs
self.export_id = self.getPartitionId('export')
self.import_id = self.getPartitionId('import')
# Remember content of ~/etc in the import theia
self.etc_listdir = os.listdir(self.getPartitionPath('import', 'etc'))
# Check initial embedded instance
test.TestTheiaWithEmbeddedInstance.test(self)
self._processEmbeddedSoftware()
self._processEmbeddedInstance()
def _checkTakeover(self):
# Check takeover
TestTheiaResilience._checkTakeover(self)
# Check that embedded instance still exists
test.TestTheiaWithEmbeddedInstance.test(self)
self._processEmbeddedSoftware()
self._processEmbeddedInstance()
import json
import os
from slapos.testing.testcase import (
installSoftwareUrlList,
makeModuleSetUpAndTestCaseClass,
SlapOSNodeCommandError,
)
import test
import test_resiliency
stable_software_url = "https://lab.nexedi.com/nexedi/slapos/raw/1.0.324/software/theia/software.cfg"
dev_software_url = os.path.abspath(
os.path.join(os.path.dirname(__file__), '..', 'software.cfg'))
software_url_list = [stable_software_url, dev_software_url]
_, SlapOSInstanceTestCase = makeModuleSetUpAndTestCaseClass(stable_software_url)
class UpgradeTestCase(SlapOSInstanceTestCase):
_current_software_url = stable_software_url
@classmethod
def getSoftwareURL(cls):
return cls._current_software_url
@classmethod
def upgrade(cls):
# request instance on dev software
cls._current_software_url = dev_software_url
cls.logger.debug('Requesting instance on dev software')
cls.requestDefaultInstance()
# wait for slapos node instance
snapshot_name = "{}.{}.dev.setUpClass".format(cls.__module__, cls.__name__)
with cls._snapshotManager(snapshot_name):
try:
for _ in range(2): # propagation
cls.waitForInstance()
cls.logger.debug("Instance on dev software done")
except BaseException:
cls.logger.exception("Error during instance on dev software")
raise
cls.computer_partition = cls.requestDefaultInstance()
@classmethod
def beforeUpgrade(cls):
pass
@classmethod
def setUpClass(cls):
# request and instantiate with old software url
super().setUpClass()
# before upgrade hook
cls.beforeUpgrade()
# upgrade
cls.upgrade()
def setUpModule():
installSoftwareUrlList(
SlapOSInstanceTestCase,
software_url_list,
debug=SlapOSInstanceTestCase._debug,
)
class TestTheia(UpgradeTestCase, test.TestTheia):
pass
class TestTheiaWithEmbeddedInstance(
UpgradeTestCase,
test.TestTheiaWithEmbeddedInstance):
pass
class TestTheiaResilientInterface(
UpgradeTestCase,
test.TestTheiaResilientInterface):
pass
class TestTheiaResilientWithEmbeddedInstance(
UpgradeTestCase,
test.TestTheiaResilientWithEmbeddedInstance):
pass
class TestTheiaResilienceWithInitialInstance(
UpgradeTestCase,
test_resiliency.TestTheiaResilienceWithInitialInstance):
@classmethod
def beforeUpgrade(cls):
# Check initial embedded instance
test.TestTheiaWithEmbeddedInstance.test(cls())
class TestResilientTheiaUpgradeWithInitialInstance(
UpgradeTestCase,
test_resiliency.ResilientTheiaTestCase,
test_resiliency.TheiaSyncMixin):
backup_max_tries = 70
backup_wait_interval = 10
old_flag_file = os.path.join('etc', 'embedded-instance-config.json.done')
old_exitcode_file = os.path.join('etc', 'embedded-request-exitcode')
flag_file = os.path.join('var', 'state', 'standalone-ran-before.flag')
exitcode_file = os.path.join('var', 'state', 'embedded-request.exitcode')
@classmethod
def getInstanceParameterDict(cls):
return {
'initial-embedded-instance': json.dumps({
'software-url': test_resiliency.dummy_software_url
}),
}
def assertExists(self, path):
self.assertTrue(os.path.exists(path))
def assertNotFound(self, path):
self.assertFalse(os.path.exists(path))
@classmethod
def beforeUpgrade(cls):
self = cls()
self.assertExists(cls.getPartitionPath('export', self.old_flag_file))
self.assertExists(cls.getPartitionPath('export', self.old_exitcode_file))
self.assertExists(self.getPartitionPath('import', self.old_flag_file))
self.assertNotFound(self.getPartitionPath('import', self.old_exitcode_file))
def _prepareExport(self): # after upgrade
self.assertNotFound(self.getPartitionPath('export', self.old_flag_file))
self.assertNotFound(self.getPartitionPath('export', self.old_exitcode_file))
self.assertNotFound(self.getPartitionPath('import', self.old_flag_file))
self.assertNotFound(self.getPartitionPath('import', self.old_exitcode_file))
self.assertExists(self.getPartitionPath('export', self.flag_file))
self.assertExists(self.getPartitionPath('export', self.exitcode_file))
self.assertExists(self.getPartitionPath('import', self.flag_file))
self.assertNotFound(self.getPartitionPath('import', self.exitcode_file))
def _checkSync(self):
self.assertExists(self.getPartitionPath('export', self.flag_file))
self.assertExists(self.getPartitionPath('export', self.exitcode_file))
self.assertExists(self.getPartitionPath('import', self.flag_file))
self.assertExists(self.getPartitionPath('import', self.exitcode_file))
def _checkTakeover(self):
self.assertNotFound(self.getPartitionPath('export', self.old_flag_file))
self.assertNotFound(self.getPartitionPath('export', self.old_exitcode_file))
self.assertNotFound(self.getPartitionPath('import', self.old_flag_file))
self.assertNotFound(self.getPartitionPath('import', self.old_exitcode_file))
self.assertExists(self.getPartitionPath('export', self.flag_file))
self.assertExists(self.getPartitionPath('export', self.exitcode_file))
self.assertExists(self.getPartitionPath('import', self.flag_file))
self.assertNotFound(self.getPartitionPath('import', self.exitcode_file))
class TestResilientTheiaUpgradeWithInitialInstanceAndSync(
TestResilientTheiaUpgradeWithInitialInstance):
@classmethod
def beforeUpgrade(cls):
cls()._doSync()
def _prepareExport(self): # after upgrade
self.assertNotFound(self.getPartitionPath('export', self.old_flag_file))
self.assertNotFound(self.getPartitionPath('export', self.old_exitcode_file))
self.assertNotFound(self.getPartitionPath('import', self.old_flag_file))
self.assertNotFound(self.getPartitionPath('import', self.old_exitcode_file))
self.assertExists(self.getPartitionPath('export', self.flag_file))
self.assertExists(self.getPartitionPath('export', self.exitcode_file))
self.assertExists(self.getPartitionPath('import', self.flag_file))
self.assertExists(self.getPartitionPath('import', self.exitcode_file))
...@@ -297,7 +297,7 @@ simplegeneric = 0.8.1 ...@@ -297,7 +297,7 @@ 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.326 slapos.cookbook = 1.0.326
slapos.core = 1.10.0 slapos.core = 1.10.1
slapos.extension.shared = 1.0 slapos.extension.shared = 1.0
slapos.libnetworkcache = 0.25 slapos.libnetworkcache = 0.25
slapos.rebootstrap = 4.5 slapos.rebootstrap = 4.5
......
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