Commit 2a90733c authored by Jérome Perrin's avatar Jérome Perrin Committed by Jérome Perrin

runpromises: support software releases older than slapos 1.0.118

Before slapos commit a184cca8b (Try to reuse existing file to avoid
excessive IO on update + other minor optimisations, 2019-06-17), which
started to be used in profiles in 65acdca0d (Release slapos.cookbook
(1.0.118), 2019-08-13), the promise plugins did not contain

    import sys
    sys.path[0:0] = (..., )

but there was an extra import statement:

    import sys
    import json
    sys.path[0:0] = (..., )

slapos.core >= 1.7 was not able to process such promises, because the
code introspecting these promises assumed that the second node of the
AST was the assignment, which is incorrect in the old promises because
it was another import.

To accomodate both cases, use the value from the first assignment.

We also change to use ast.literal_eval for safety.
parent b01cc6cf
Pipeline #19783 passed with stage
...@@ -36,8 +36,13 @@ promise_file = next( ...@@ -36,8 +36,13 @@ promise_file = next(
with open(os.path.join(promise_folder, promise_file)) as f: with open(os.path.join(promise_folder, promise_file)) as f:
promise_content = f.read() promise_content = f.read()
tree = ast.parse(promise_content, mode='exec') tree = ast.parse(promise_content, mode='exec')
assign_node = next(e for e in tree.body if isinstance(e, ast.Assign))
sys.path[0:0] = eval(compile(ast.Expression(tree.body[1].value), '', 'eval')) if sys.version_info >= (3, 9):
assert ast.unparse(assign_node.targets[0]) == 'sys.path[0:0]'
else:
assert [ast.dump(n) for n in assign_node.targets] \
== [ast.dump(n) for n in ast.parse("sys.path[0:0] = []").body[0].targets]
sys.path[0:0] = ast.literal_eval(assign_node.value)
from slapos.grid.promise import PromiseLauncher, PromiseError from slapos.grid.promise import PromiseLauncher, PromiseError
from slapos.cli.entry import SlapOSApp from slapos.cli.entry import SlapOSApp
......
...@@ -4215,6 +4215,46 @@ class TestSlapgridPluginPromiseWithInstancePython(TestSlapgridPromiseWithMaster) ...@@ -4215,6 +4215,46 @@ class TestSlapgridPluginPromiseWithInstancePython(TestSlapgridPromiseWithMaster)
" 0[(not ready)]: Promise 'failing_promise_plugin.py' failed with output: héhé fake promise plugin error") " 0[(not ready)]: Promise 'failing_promise_plugin.py' failed with output: héhé fake promise plugin error")
class TestSlapgridPluginPromiseWithInstancePythonOldSlapOSCompatibility(
TestSlapgridPluginPromiseWithInstancePython):
"""Process instance plugins with a different python, but simulate the case
where plugin scripts structure had one extra import
"""
def getTestComputerClass(self):
# use a test computer that will use a custom python (because we reuse
# TestSlapgridPluginPromiseWithInstancePython) and some promise plugins
# scripts that look like the one slapos.cookbook was creating before 1.0.118
class TestComputer(
super(TestSlapgridPluginPromiseWithInstancePythonOldSlapOSCompatibility,
self).getTestComputerClass()):
def getTestInstanceClass(self):
class TestInstance(super(TestComputer, self).getTestInstanceClass()):
def setPluginPromise(self, *args, **kwargs):
plugin_promise = super(TestInstance,
self).setPluginPromise(*args, **kwargs)
with open(plugin_promise) as f:
plugin_code = f.read()
legacy_plugin_code = plugin_code.replace(
textwrap.dedent('''\
# coding: utf-8
import sys
'''),
textwrap.dedent('''\
# coding: utf-8
import json
import sys
'''))
assert legacy_plugin_code != plugin_code # make sure our replace matched
with open(plugin_promise, 'w') as f:
f.write(legacy_plugin_code)
return plugin_promise
return TestInstance
return TestComputer
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