Commit 1db0017f authored by Xavier Thompson's avatar Xavier Thompson

sotware/theia: Add resiliency test

parent d3676015
Pipeline #14213 failed with stage
in 0 seconds
# Dummy
A very simple SR that is entirely self contained.
It doesn't depend on any files other than those it this directory.
In particular it doesn't extent stack/slapos.cfg.
It takes very little time to compile and deploy.
[buildout]
parts =
log-writer
eggs-directory = ${buildout:eggs-directory}
develop-eggs-directory = ${buildout:develop-eggs-directory}
offline = true
[directory]
recipe = plone.recipe.command
home = $${buildout:directory}
etc = $${:home}/etc
run = $${:etc}/run
command = mkdir -p $${:run}
[log-writer]
recipe = slapos.recipe.template:jinja2
template = inline:#!/bin/sh
echo "Hello : $(date)" >> $${directory:home}/log.log
rendered = $${directory:run}/log-writer
mode = 700
[buildout]
find-links +=
http://www.nexedi.org/static/packages/source/
http://www.nexedi.org/static/packages/source/slapos.buildout/
parts =
instance-template
plone-recipe-command
versions = versions
[plone-recipe-command]
recipe = zc.recipe.egg
eggs = plone.recipe.command
[instance-template]
recipe = slapos.recipe.template
url = ${:_profile_base_location_}/instance.cfg.in
output = ${buildout:directory}/instance.cfg
mode = 0644
[versions]
setuptools = 44.0.0
zc.buildout = 2.7.1+slapos010
zc.recipe.egg = 2.0.3+slapos003
...@@ -33,6 +33,7 @@ import subprocess ...@@ -33,6 +33,7 @@ import subprocess
import tempfile import tempfile
import time import time
import re import re
import shutil
from six.moves.urllib.parse import urlparse, urljoin from six.moves.urllib.parse import urlparse, urljoin
import pexpect import pexpect
...@@ -74,6 +75,63 @@ class TheiaTestCase(SlapOSInstanceTestCase): ...@@ -74,6 +75,63 @@ class TheiaTestCase(SlapOSInstanceTestCase):
return None return None
class TheiaResiliencyTestCase(TheiaTestCase):
@classmethod
def _getLocalPath(cls, relative_path):
partition_root = cls.getPartitionPathWhere(cls.getSoftwareURL(), 'export')
absolute_path = os.path.join(partition_root, relative_path)
return absolute_path
@classmethod
def _doSlaposCommand(cls, command):
partition_root = cls.getPartitionPathWhere(cls.getSoftwareURL(), 'export')
slapos_bin = os.path.join(partition_root, 'srv', 'runner', 'bin', 'slapos')
output = subprocess.check_output((slapos_bin, ) + command)
return output
def _supplySoftwareRelease(self, software_url):
self._doSlaposCommand(('supply', software_url, 'slaprunner'))
def _waitForSoftwareBuild(self):
self._doSlaposCommand(('node', 'software'))
def _requestInstance(self, instance_name, software_url):
self._doSlaposCommand(('request', instance_name, software_url))
def _waitForInstanceDeploy(self):
self._doSlaposCommand(('node', 'instance'))
def _getTakeoverUrlAndPassword(self, scope="theia-1"):
parameter_dict = self.computer_partition.getConnectionParameterDict()
takeover_url = parameter_dict["takeover-%s-url" % scope]
takeover_password = parameter_dict["takeover-%s-password" % scope]
return takeover_url, takeover_password
def _getTakeoverState(self, takeover_url):
def getTakeoverPageContent():
resp = requests.get(takeover_url, verify=True)
self.assertEqual(requests.codes.ok, resp.status_code)
return resp.text
takeover_page_content = getTakeoverPageContent()
if "<b>Last valid backup:</b> No backup downloaded yet, takeover should not happen now." in takeover_page_content:
return "nothing"
elif "<b>Importer script(s) of backup in progress:</b> True" in takeover_page_content:
return "ongoing"
return "ready"
def _doTakeover(self, takeover_url, takeover_password):
resp = requests.get(
"%s?password=%s" % (takeover_url, takeover_password),
verify=True
)
self.assertEqual(requests.codes.ok, resp.status_code)
self.assertNotIn("Error", resp.text, "An Error occured: %s" % resp.text)
self.assertIn("Success", resp.text, "'Success' not in '%s'" % resp.text)
return resp.text
# Utils # Utils
# ----- # -----
...@@ -296,3 +354,89 @@ class TestTheiaResilientWithSR(TestTheiaWithSR): ...@@ -296,3 +354,89 @@ class TestTheiaResilientWithSR(TestTheiaWithSR):
# Patch the computer root path to that of the export theia instance # Patch the computer root path to that of the export theia instance
path = cls.getPartitionPathWhere(cls.getSoftwareURL(), 'export') path = cls.getPartitionPathWhere(cls.getSoftwareURL(), 'export')
cls.computer_partition_root_path = path cls.computer_partition_root_path = path
class TestTheiaBasicResilience(TheiaResiliencyTestCase):
instance_max_retry = 30
@classmethod
def getInstanceSoftwareType(cls):
return 'resilient'
def test_basic_dummy_resilience(self):
export_partition_id = self.getPartitionIdWhere(self.getSoftwareURL(), 'export')
import_partition_id = self.getPartitionIdWhere(self.getSoftwareURL(), 'import')
# Copy ./dummy SR in export theia ~/srv/project/dummy
dummy_target_path = self._getLocalPath('srv/project/dummy')
shutil.copytree('dummy', dummy_target_path)
dummy_software_url = os.path.join(dummy_target_path, 'software.cfg')
# Deploy dummy instance
self._supplySoftwareRelease(dummy_software_url)
self._waitForSoftwareBuild()
self._requestInstance("dummy_instance", dummy_software_url)
self._waitForInstanceDeploy()
# Check that dummy instance was properly deployed
relative_dummy_log_path = 'srv/runner/instance/slappart0/log.log'
with open(self._getLocalPath(relative_dummy_log_path), 'r') as f:
content = f.read()
self.assertTrue(content.startswith("Hello"), content)
# Call exporter script instead of waiting for cron job
# XXX Accelerate cron frequency instead ?
exporter_script = self._getLocalPath('bin/exporter')
transaction_id = str(int(time.time()))
subprocess.check_output((exporter_script, '--transaction-id', transaction_id))
# Get equeue.log file in import instance
import_partition_root = self.getPartitionPathWhere(self.getSoftwareURL(), 'import')
importer_log = os.path.join(import_partition_root, 'var', 'log', 'equeue.log')
def getFileContent(file_path):
with open(file_path) as f:
return f.read()
# Wait for importer to start
time.sleep(60)
takeover_url, takeover_password = self._getTakeoverUrlAndPassword()
for _ in range(100):
takeover_state = self._getTakeoverState(takeover_url)
if takeover_state == "ready":
break
elif takeover_state == "nothing":
importer_log_content = getFileContent(importer_log)
self.fail("Backup is not even started: %s" % importer_log_content)
else:
self.logger.info("Backup is ongoing, waiting some more")
time.sleep(20)
# Takeover
self._doTakeover(takeover_url, takeover_password)
# Wait for import instance to become export instance and new import to be allocated
self.slap.waitForInstance(1)
previous_computer_partition = self.computer_partition
self.computer_partition = self.requestDefaultInstance()
# Check that the import instance became the export instance
new_export_partition_id = self.getPartitionIdWhere(self.getSoftwareURL(), 'export')
self.assertNotEqual(export_partition_id, import_partition_id)
self.assertEqual(import_partition_id, new_export_partition_id)
# Check that there is a new import instance
new_import_partition_id = self.getPartitionIdWhere(self.getSoftwareURL(), 'import')
self.assertNotEqual(export_partition_id, new_import_partition_id)
self.assertNotEqual(new_export_partition_id, new_import_partition_id)
# Check that the data was transfered over
with open(self._getLocalPath(relative_dummy_log_path), 'r') as f:
content_after = f.read()
self.assertTrue(content.startswith("Hello"), content)
self.assertTrue(content_after.startswith("Hello"), content_after)
self.assertIn(content, content_after, "%s not in %s" % (content, content_after))
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