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