Commit e2cebc0c authored by Jérome Perrin's avatar Jérome Perrin

Fix promise output when falling back to SR python

On python3 slapos.core for python2 software release, the output was bytes:

```
2021-11-05 17:28:39 slapos[12654] INFO Error with promises for the following partitions:
2021-11-05 17:28:39 slapos[12654] INFO   slappart7[balancer]: b'Promise \'check-apachedex-result.py\' failed with output: ERROR \'"/srv/slapgrid/slappart3/srv/runner/software/cc0326f0dcb093f56c01291c300c8481/bin/check-apachedex-result" --apachedex_path "/srv/slapgrid/slappart3/srv/runner/instance/slappart7/srv/monitor/private/apachedex" --status_file /srv/slapgrid/slappart3/srv/runner/instance/slappart7/srv/monitor/private/apachedex.report.json --threshold "70"\' run with failure, output: \'Score too low: 0% - Threshold: 70.0%\\n\''
```

See merge request nexedi/slapos.core!344
parents 06f72fdf 54c7061f
......@@ -176,7 +176,10 @@ class ColoredStreamHandler(logging.StreamHandler):
message = record.msg
try:
if not isinstance(message, basestring):
message = unicode(message)
try:
message = unicode(message)
except UnicodeDecodeError:
message = unicode(str(message), 'utf-8', 'replace')
except NameError:
if not isinstance(message, str):
message = str(message)
......
......@@ -64,5 +64,9 @@ os.dup2(2, 1)
try:
promise_checker.run()
except Exception as e:
os.write(out, str(e))
if sys.version_info < (3,):
error_str = unicode(str(e), 'utf-8', 'repr')
else:
error_str = str(e)
os.write(out, error_str.encode('utf-8', 'repr'))
sys.exit(2 if isinstance(e, PromiseError) else 1)
......@@ -730,6 +730,7 @@ stderr_logfile_backups=1
command,
preexec_fn=lambda: dropPrivileges(uid, gid, logger=self.logger),
cwd=instance_path,
universal_newlines=True,
stdout=subprocess.PIPE)
promises = plugins + len(listifdir(legacy_promise_dir))
# Add a timeout margin to let the process kill the promises and cleanup
......
##############################################################################
#
# coding: utf-8
# Copyright (c) 2010 Vifib SARL and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
......@@ -69,7 +69,7 @@ from slapos.util import dumps
from slapos import __path__ as slapos_path
from zope import __path__ as zope_path
PROMISE_PATHS = sorted(set(map(os.path.dirname, slapos_path + zope_path)))
PROMISE_PATHS = sorted(set(map(os.path.dirname, list(slapos_path) + list(zope_path))))
import httmock
......@@ -119,6 +119,7 @@ touch worked
"""
PROMISE_CONTENT_TEMPLATE = """
# coding: utf-8
import sys
sys.path[0:0] = %(paths)r
......@@ -1757,41 +1758,51 @@ echo %s; echo %s; exit 42""" % (line1, line2))
def test_processing_summary(self):
"""At the end of instance processing, a summary of partition with errors is displayed.
"""
computer = ComputerForTest(self.software_root, self.instance_root, 3, 3)
_, instance1, instance2 = computer.instance_list
computer = ComputerForTest(self.software_root, self.instance_root, 4, 4)
_, instance1, instance2, instance3 = computer.instance_list
# instance0 has no problem, it is not in summary
# instance 1 fails software
instance1 = computer.instance_list[1]
instance1.software = computer.software_list[1]
instance1.software.setBuildout("""#!/bin/sh
echo fake buildout error
exit 1""")
# instance 2 fails promises
instance2 = computer.instance_list[2]
# instance 2 fails old style promises
instance2.requested_state = 'started'
instance2.setPromise("failing_promise", """#!/bin/sh
echo fake promise error
echo héhé fake promise error
exit 1""")
# instance 3 fails promise plugin
instance3.requested_state = 'started'
instance3.setPluginPromise(
"failing_promise_plugin.py",
promise_content="""if 1:
return self.logger.error("héhé fake promise plugin error")
""",
)
with httmock.HTTMock(computer.request_handler), \
patch.object(self.grid.logger, 'info',) as dummyLogger:
self.launchSlapgrid()
# reconstruct the string like logger does
self.assertEqual(
dummyLogger.mock_calls[-4][1][0] % dummyLogger.mock_calls[-4][1][1:],
dummyLogger.mock_calls[-5][1][0] % dummyLogger.mock_calls[-5][1][1:],
'Error while processing the following partitions:')
self.assertRegexpMatches(
dummyLogger.mock_calls[-3][1][0] % dummyLogger.mock_calls[-3][1][1:],
dummyLogger.mock_calls[-4][1][0] % dummyLogger.mock_calls[-4][1][1:],
r" 1\[\(not ready\)\]: Failed to run buildout profile in directory '.*/instance/1':\nfake buildout error\n\n")
self.assertEqual(
dummyLogger.mock_calls[-2][1][0] % dummyLogger.mock_calls[-2][1][1:],
dummyLogger.mock_calls[-3][1][0] % dummyLogger.mock_calls[-3][1][1:],
'Error with promises for the following partitions:')
self.assertEqual(
dummyLogger.mock_calls[-2][1][0] % dummyLogger.mock_calls[-2][1][1:],
" 2[(not ready)]: Promise 'failing_promise' failed with output: héhé fake promise error")
self.assertEqual(
dummyLogger.mock_calls[-1][1][0] % dummyLogger.mock_calls[-1][1][1:],
" 2[(not ready)]: Promise 'failing_promise' failed with output: fake promise error")
" 3[(not ready)]: Promise 'failing_promise_plugin.py' failed with output: héhé fake promise plugin error")
def test_partition_force_stop(self):
"""
......@@ -4162,6 +4173,26 @@ class TestSlapgridPluginPromiseWithInstancePython(TestSlapgridPromiseWithMaster)
super(TestSlapgridPluginPromiseWithInstancePython, self).tearDown()
self.assertEqual(self.expect_plugin, called)
def test_failed_promise_output(self):
computer = ComputerForTest(self.software_root, self.instance_root, 1, 1)
instance, = computer.instance_list
instance.requested_state = 'started'
instance.setPluginPromise(
"failing_promise_plugin.py",
promise_content="""if 1:
return self.logger.error("héhé fake promise plugin error")
""",
)
with httmock.HTTMock(computer.request_handler), \
patch.object(self.grid.logger, 'info',) as dummyLogger:
self.launchSlapgrid()
self.assertEqual(
dummyLogger.mock_calls[-1][1][0] % dummyLogger.mock_calls[-1][1][1:],
" 0[(not ready)]: Promise 'failing_promise_plugin.py' failed with output: héhé fake promise plugin error")
class TestSVCBackend(unittest.TestCase):
"""Tests for supervisor backend.
......
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