Commit 2e5c7422 authored by Jérome Perrin's avatar Jérome Perrin

Fix Gitlab resiliency tests

See merge request nexedi/slapos!1677
parents 78333ab1 4bb65573
...@@ -54,7 +54,7 @@ md5sum = d769ea27820e932c596c35bbbf3f2902 ...@@ -54,7 +54,7 @@ md5sum = d769ea27820e932c596c35bbbf3f2902
[instance-gitlab.cfg.in] [instance-gitlab.cfg.in]
_update_hash_filename_ = instance-gitlab.cfg.in _update_hash_filename_ = instance-gitlab.cfg.in
md5sum = e17bfe96bb9a0f4666d90c877a663e88 md5sum = 35bb9f1d8f4fd6675bd768d8a7e1253c
[instance-gitlab-export.cfg.in] [instance-gitlab-export.cfg.in]
_update_hash_filename_ = instance-gitlab-export.cfg.in _update_hash_filename_ = instance-gitlab-export.cfg.in
......
...@@ -916,8 +916,6 @@ rake = ${gitlab-rake:wrapper-path} ...@@ -916,8 +916,6 @@ rake = ${gitlab-rake:wrapper-path}
# run command on every reinstantiation # run command on every reinstantiation
update-command = ${:command} update-command = ${:command}
# https://gitlab.com/gitlab-org/gitlab-foss/issues/38457
# we need to manually install ajv@^4.0.0 with yarn to fix the bug 'yarn check failed!'
command = command =
${:rake} gitlab:assets:clean && ${:rake} gitlab:assets:clean &&
${:rake} gettext:compile RAILS_ENV=production && ${:rake} gettext:compile RAILS_ENV=production &&
......
...@@ -15,11 +15,11 @@ ...@@ -15,11 +15,11 @@
[instance-theia] [instance-theia]
_update_hash_filename_ = instance-theia.cfg.jinja.in _update_hash_filename_ = instance-theia.cfg.jinja.in
md5sum = 23b498618bce83a6eb8df0470417f59e md5sum = b4e87cff99a8521e6d0b911e3ef35b30
[instance] [instance]
_update_hash_filename_ = instance.cfg.in _update_hash_filename_ = instance.cfg.in
md5sum = 5aab12790cdb1981cb0caf00d389a227 md5sum = 837eb2786f185ddb5a28d29e271652f7
[instance-import] [instance-import]
_update_hash_filename_ = instance-import.cfg.jinja.in _update_hash_filename_ = instance-import.cfg.jinja.in
......
...@@ -53,7 +53,11 @@ pidfiles = $${:var}/run ...@@ -53,7 +53,11 @@ pidfiles = $${:var}/run
statefiles = $${:var}/state statefiles = $${:var}/state
services = $${:etc}/service services = $${:etc}/service
{% if parameter_dict['testing-short-embedded-instance-path'] %}
runner = $${:home}/r
{% else %}
runner = $${:srv}/runner runner = $${:srv}/runner
{% endif %}
backup = $${:srv}/backup/theia backup = $${:srv}/backup/theia
project = $${:srv}/project project = $${:srv}/project
...@@ -567,8 +571,13 @@ ipv4 = {{ ipv4_random }} ...@@ -567,8 +571,13 @@ ipv4 = {{ ipv4_random }}
ipv6 = {{ slap_resource.get('ipv6-range-network') or ipv6_theia }} 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}
{% if parameter_dict['testing-short-embedded-instance-path'] %}
software-root = $${directory:runner}/s
instance-root = $${directory:runner}/i
{% else %}
software-root = $${directory:runner}/software software-root = $${directory:runner}/software
instance-root = $${directory:runner}/instance instance-root = $${directory:runner}/instance
{% endif %}
local-software-release-root = $${directory:home} local-software-release-root = $${directory:home}
slapos-bin = ${buildout:bin-directory}/slapos slapos-bin = ${buildout:bin-directory}/slapos
slapos-configuration = $${directory:runner}/etc/slapos.cfg slapos-configuration = $${directory:runner}/etc/slapos.cfg
......
...@@ -55,7 +55,8 @@ default-parameters = ...@@ -55,7 +55,8 @@ default-parameters =
"additional-frontend-sr": "$${:frontend-sr}", "additional-frontend-sr": "$${:frontend-sr}",
"additional-frontend-sr-type": "default", "additional-frontend-sr-type": "default",
"additional-frontend-guid": null, "additional-frontend-guid": null,
"monitor-httpd-port": 8386 "monitor-httpd-port": 8386,
"testing-short-embedded-instance-path": null
} }
frontend-sr = http://git.erp5.org/gitweb/slapos.git/blob_plain/HEAD:/software/apache-frontend/software.cfg frontend-sr = http://git.erp5.org/gitweb/slapos.git/blob_plain/HEAD:/software/apache-frontend/software.cfg
......
...@@ -24,7 +24,6 @@ ...@@ -24,7 +24,6 @@
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# #
############################################################################## ##############################################################################
from __future__ import unicode_literals
import gzip import gzip
import json import json
...@@ -32,13 +31,12 @@ import os ...@@ -32,13 +31,12 @@ import os
import re import re
import subprocess import subprocess
import time import time
import unittest
import shutil import shutil
import requests import requests
import tempfile import tempfile
from datetime import datetime, timedelta from datetime import datetime, timedelta
from six.moves.urllib.parse import urljoin from urllib.parse import urljoin
from mimetypes import guess_type from mimetypes import guess_type
from json.decoder import JSONDecodeError from json.decoder import JSONDecodeError
...@@ -67,6 +65,21 @@ def setUpModule(): ...@@ -67,6 +65,21 @@ def setUpModule():
) )
class TestTheiaResilienceWithShortPaths(test_resiliency.TestTheiaResilience):
"""TestTheiaResilience, but with shorter paths for embedded slapos, to
overcome OS limit with the length of unix sockets or #! "shebang" lines.
"""
@classmethod
def getInstanceParameterDict(cls):
return dict(
super().getInstanceParameterDict(),
**{'testing-short-embedded-instance-path': 'true'})
@classmethod
def _getSlapos(cls, instance_type='export'):
return cls.getPartitionPath(instance_type, 'r', 'bin', 'slapos')
class ERP5Mixin(object): class ERP5Mixin(object):
_test_software_url = erp5_software_release_url _test_software_url = erp5_software_release_url
_connexion_parameters_regex = re.compile(r"{.*}", re.DOTALL) _connexion_parameters_regex = re.compile(r"{.*}", re.DOTALL)
...@@ -125,7 +138,7 @@ class ERP5Mixin(object): ...@@ -125,7 +138,7 @@ class ERP5Mixin(object):
instance_type, 'srv', 'runner', 'instance', partition, *paths) instance_type, 'srv', 'runner', 'instance', partition, *paths)
class TestTheiaResilienceERP5(ERP5Mixin, test_resiliency.TestTheiaResilience): class TestTheiaResilienceERP5(ERP5Mixin, TestTheiaResilienceWithShortPaths):
test_instance_max_retries = 12 test_instance_max_retries = 12
backup_max_tries = 480 backup_max_tries = 480
backup_wait_interval = 60 backup_wait_interval = 60
...@@ -242,7 +255,8 @@ class TestTheiaResilienceERP5(ERP5Mixin, test_resiliency.TestTheiaResilience): ...@@ -242,7 +255,8 @@ class TestTheiaResilienceERP5(ERP5Mixin, test_resiliency.TestTheiaResilience):
out = subprocess.check_output((mysql_bin, 'erp5', '-e', query), universal_newlines=True) out = subprocess.check_output((mysql_bin, 'erp5', '-e', query), universal_newlines=True)
self.assertIn(self._erp5_new_title, out, 'Mariadb catalog is not properly restored') self.assertIn(self._erp5_new_title, out, 'Mariadb catalog is not properly restored')
class TestTheiaResiliencePeertube(test_resiliency.TestTheiaResilience):
class TestTheiaResiliencePeertube(TestTheiaResilienceWithShortPaths):
test_instance_max_retries = 12 test_instance_max_retries = 12
backup_max_tries = 480 backup_max_tries = 480
backup_wait_interval = 60 backup_wait_interval = 60
...@@ -446,9 +460,10 @@ class TestTheiaResiliencePeertube(test_resiliency.TestTheiaResilience): ...@@ -446,9 +460,10 @@ class TestTheiaResiliencePeertube(test_resiliency.TestTheiaResilience):
def _getPeertubePartitionPath(self, instance_type, servicename, *paths): def _getPeertubePartitionPath(self, instance_type, servicename, *paths):
partition = self._getPeertubePartition(servicename) partition = self._getPeertubePartition(servicename)
return self.getPartitionPath( return self.getPartitionPath(
instance_type, 'srv', 'runner', 'instance', partition, *paths) instance_type, 'r', 'i', partition, *paths)
class TestTheiaResilienceGitlab(test_resiliency.TestTheiaResilience): class TestTheiaResilienceGitlab(TestTheiaResilienceWithShortPaths):
test_instance_max_retries = 50 # puma takes time to be ready test_instance_max_retries = 50 # puma takes time to be ready
backup_max_tries = 480 backup_max_tries = 480
backup_wait_interval = 60 backup_wait_interval = 60
...@@ -467,7 +482,7 @@ class TestTheiaResilienceGitlab(test_resiliency.TestTheiaResilience): ...@@ -467,7 +482,7 @@ class TestTheiaResilienceGitlab(test_resiliency.TestTheiaResilience):
stderr=subprocess.STDOUT, stderr=subprocess.STDOUT,
text=True, text=True,
) )
print(out) self.logger.info("_getGitlabConnectionParameters output: %s", out)
return json.loads(self._connection_parameters_regex.search(out).group(0).replace("'", '"')) return json.loads(self._connection_parameters_regex.search(out).group(0).replace("'", '"'))
def test_twice(self): def test_twice(self):
...@@ -499,7 +514,7 @@ class TestTheiaResilienceGitlab(test_resiliency.TestTheiaResilience): ...@@ -499,7 +514,7 @@ class TestTheiaResilienceGitlab(test_resiliency.TestTheiaResilience):
# Create a new project # Create a new project
print("Gitlab create a project") print("Gitlab create a project")
path = '/api/v3/projects' path = '/api/v4/projects'
parameter_dict = {'name': 'sample-test', 'namespace': 'open'} parameter_dict = {'name': 'sample-test', 'namespace': 'open'}
# Token can be set manually # Token can be set manually
headers = {"PRIVATE-TOKEN" : 'SLurtnxPscPsU-SDm4oN'} headers = {"PRIVATE-TOKEN" : 'SLurtnxPscPsU-SDm4oN'}
...@@ -508,14 +523,14 @@ class TestTheiaResilienceGitlab(test_resiliency.TestTheiaResilience): ...@@ -508,14 +523,14 @@ class TestTheiaResilienceGitlab(test_resiliency.TestTheiaResilience):
# Check the project is exist # Check the project is exist
print("Gitlab check project is exist") print("Gitlab check project is exist")
path = '/api/v3/projects' path = '/api/v4/projects'
response = requests.get(backend_url + path, headers=headers, verify=False) response = requests.get(backend_url + path, params={'search': 'sample-test'}, headers=headers, verify=False)
try: try:
projects = response.json() projects = response.json()
except JSONDecodeError: except JSONDecodeError:
self.fail("No json file returned! Maybe your Gitlab URL is incorrect.") self.fail("No json file returned! Maybe your Gitlab URL is incorrect.")
# Only one project exist # Only one project matches the search
self.assertEqual(len(projects), 1) self.assertEqual(len(projects), 1)
# The project name is sample-test, which we created above. # The project name is sample-test, which we created above.
self.assertIn("sample-test", projects[0]['name_with_namespace']) self.assertIn("sample-test", projects[0]['name_with_namespace'])
...@@ -543,12 +558,14 @@ class TestTheiaResilienceGitlab(test_resiliency.TestTheiaResilience): ...@@ -543,12 +558,14 @@ class TestTheiaResilienceGitlab(test_resiliency.TestTheiaResilience):
output = subprocess.check_output(('git', 'push', 'origin'), cwd=repo_path, universal_newlines=True) output = subprocess.check_output(('git', 'push', 'origin'), cwd=repo_path, universal_newlines=True)
# Do a fake periodically update # Do a fake periodically update
# Compute backup date in the near future # Compute backup date in the future
soon = (datetime.now() + timedelta(minutes=4)) # During slapos node instance, the static assets are recompiled, which takes a lot
# of time, so we give it at least 20 minutes.
soon = (datetime.now() + timedelta(minutes=20))
frequency = "%d * * * *" % soon.minute frequency = "%d * * * *" % soon.minute
params = 'backup_frequency=%s' % frequency params = 'backup_frequency=%s' % frequency
# Update Peertube parameters # Update Gitlab parameters
print('Requesting Gitlab with parameters %s' % params) print('Requesting Gitlab with parameters %s' % params)
self.checkSlapos('request', 'test_instance', self._test_software_url, '--parameters', params) self.checkSlapos('request', 'test_instance', self._test_software_url, '--parameters', params)
...@@ -557,8 +574,8 @@ class TestTheiaResilienceGitlab(test_resiliency.TestTheiaResilience): ...@@ -557,8 +574,8 @@ class TestTheiaResilienceGitlab(test_resiliency.TestTheiaResilience):
self.callSlapos('node', 'restart', 'all') self.callSlapos('node', 'restart', 'all')
# Wait until after the programmed backup date, and a bit more # Wait until after the programmed backup date, and a bit more
t = (soon - datetime.now()).total_seconds() t = ((soon - datetime.now()) + timedelta(minutes=10)).total_seconds()
time.sleep(t + 240) time.sleep(t)
self.callSlapos('node', 'status') self.callSlapos('node', 'status')
os.chdir(self.temp_clone_dir) os.chdir(self.temp_clone_dir)
...@@ -583,9 +600,9 @@ class TestTheiaResilienceGitlab(test_resiliency.TestTheiaResilience): ...@@ -583,9 +600,9 @@ class TestTheiaResilienceGitlab(test_resiliency.TestTheiaResilience):
# Check the project is exist # Check the project is exist
print("Gitlab check project is exist") print("Gitlab check project is exist")
path = '/api/v3/projects' path = '/api/v4/projects'
headers = {"PRIVATE-TOKEN" : 'SLurtnxPscPsU-SDm4oN'} headers = {"PRIVATE-TOKEN" : 'SLurtnxPscPsU-SDm4oN'}
response = requests.get(backend_url + path, headers=headers, verify=False) response = requests.get(backend_url + path, params={'search': 'sample-test'}, headers=headers, verify=False)
try: try:
projects = response.json() projects = response.json()
except JSONDecodeError: except JSONDecodeError:
...@@ -623,4 +640,4 @@ class TestTheiaResilienceGitlab(test_resiliency.TestTheiaResilience): ...@@ -623,4 +640,4 @@ class TestTheiaResilienceGitlab(test_resiliency.TestTheiaResilience):
def _getGitlabPartitionPath(self, instance_type, servicename, *paths): def _getGitlabPartitionPath(self, instance_type, servicename, *paths):
partition = self._getGitlabPartition(servicename) partition = self._getGitlabPartition(servicename)
return self.getPartitionPath( return self.getPartitionPath(
instance_type, 'srv', 'runner', 'instance', partition, *paths) instance_type, 'r', 'i', partition, *paths)
...@@ -72,34 +72,42 @@ def setUpModule(): ...@@ -72,34 +72,42 @@ def setUpModule():
class ResilientTheiaTestCase(ResilientTheiaMixin, TheiaTestCase): class ResilientTheiaTestCase(ResilientTheiaMixin, TheiaTestCase):
@classmethod @classmethod
def _processEmbeddedInstance(cls, retries=0, instance_type='export'): def _processEmbeddedInstance(cls, retries=0, instance_type='export'):
for _ in range(retries): for retry in range(retries):
try: try:
output = cls.captureSlapos('node', 'instance', instance_type=instance_type, stderr=subprocess.STDOUT) output = cls.captureSlapos('node', 'instance', instance_type=instance_type, stderr=subprocess.STDOUT, text=True)
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
continue continue
print(output) cls.logger.info("_processEmbeddedInstance retry=%s output=%s", retry, output)
break break
else: else:
if retries: if retries:
# Sleep a bit as an attempt to workaround monitoring boostrap not being ready # Sleep a bit as an attempt to workaround monitoring boostrap not being ready
print("Wait before running slapos node instance one last time") print("Wait before running slapos node instance one last time")
time.sleep(120) time.sleep(120)
cls.checkSlapos('node', 'instance', instance_type=instance_type) try:
cls.checkSlapos('node', 'instance', instance_type=instance_type, text=True)
except subprocess.CalledProcessError as e:
cls.logger.error(e.output, exc_info=True)
raise
@classmethod @classmethod
def _processEmbeddedSoftware(cls, retries=0, instance_type='export'): def _processEmbeddedSoftware(cls, retries=0, instance_type='export'):
for _ in range(retries): for retry 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, text=True)
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
continue continue
print(output) cls.logger.info("_processEmbeddedSoftware retry=%s output=%s", retry, output)
break break
else: else:
if retries: if retries:
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) try:
cls.checkSlapos('node', 'software', instance_type=instance_type, text=True)
except subprocess.CalledProcessError as e:
cls.logger.error(e.output, exc_info=True)
raise
@classmethod @classmethod
def _deployEmbeddedSoftware(cls, software_url, instance_name, retries=0, instance_type='export'): def _deployEmbeddedSoftware(cls, software_url, instance_name, retries=0, instance_type='export'):
......
...@@ -30,7 +30,7 @@ md5sum = 1b8645835f04081861266436505fd28f ...@@ -30,7 +30,7 @@ md5sum = 1b8645835f04081861266436505fd28f
[template-replicated] [template-replicated]
filename = template-replicated.cfg.in filename = template-replicated.cfg.in
md5sum = 67c863b15dbfa937babdbd620f95c1ff md5sum = 743012b9e8d318712187621867613bd4
[template-parts] [template-parts]
filename = template-parts.cfg.in filename = template-parts.cfg.in
......
...@@ -87,7 +87,7 @@ return = ssh-public-key resilient-ssh-url notification-url ip takeover-url takeo ...@@ -87,7 +87,7 @@ return = ssh-public-key resilient-ssh-url notification-url ip takeover-url takeo
pbs-notification-id = ${slap-connection:computer-id}-${slap-connection:partition-id}-{{namebase}}-{{id}}-push pbs-notification-id = ${slap-connection:computer-id}-${slap-connection:partition-id}-{{namebase}}-{{id}}-push
{% for extra_parameter_for_pseudo_replicating_instance in ["software-root", "buildout-shared-folder"] %} {% for extra_parameter_for_pseudo_replicating_instance in ["software-root", "buildout-shared-folder", "testing-short-embedded-instance-path"] %}
{% if slapparameter_dict.get(extra_parameter_for_pseudo_replicating_instance) %} {% if slapparameter_dict.get(extra_parameter_for_pseudo_replicating_instance) %}
config-{{ extra_parameter_for_pseudo_replicating_instance }} = {{ slapparameter_dict.get(extra_parameter_for_pseudo_replicating_instance) }} config-{{ extra_parameter_for_pseudo_replicating_instance }} = {{ slapparameter_dict.get(extra_parameter_for_pseudo_replicating_instance) }}
{% endif %} {% endif %}
......
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