Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Fixed
correctly.

In such scenario, package / module was incorrectly loaded from Python 2 site-packages instead of
Python 3 standard library which broke such packs. (bug fix) #4658
Python 3 standard library which broke such packs. (bug fix) #4658 #4674

3.0.0 - April 18, 2019
----------------------
Expand Down
12 changes: 7 additions & 5 deletions conf/st2.conf.sample
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,18 @@ actions_pool_size = 60
python_runner_log_level = DEBUG
# Internal pool size for dispatcher used by workflow actions.
workflows_pool_size = 40
# Prefix for Python 3 installation (e.g. /opt/python3.6). If not specified, it tries to find Python 3 libraries in /usr/lib and /usr/local/lib.
python3_prefix = None
# Virtualenv binary which should be used to create pack virtualenvs.
virtualenv_binary = /usr/bin/virtualenv
# Python 3 binary which will be used by Python actions for packs which use Python 3 virtual environment
# Python 3 binary which will be used by Python actions for packs which use Python 3 virtual environment.
python3_binary = /usr/bin/python3
# location of the logging.conf file
logging = /etc/st2/logging.actionrunner.conf
# True to store and stream action output (stdout and stderr) in real-time.
stream_output = True
# List of virtualenv options to be passsed to "virtualenv" command that creates pack virtualenv.
virtualenv_opts = --system-site-packages # comma separated list allowed here.
# True to store and stream action output (stdout and stderr) in real-time.
stream_output = True
# location of the logging.conf file
logging = /etc/st2/logging.actionrunner.conf
# Python binary which will be used by Python actions.
python_binary = /usr/bin/python

Expand Down
6 changes: 5 additions & 1 deletion st2common/st2common/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,11 @@ def register_opts(ignore_errors=False):
cfg.StrOpt(
'python3_binary', default=default_python3_bin_path,
help='Python 3 binary which will be used by Python actions for packs which '
'use Python 3 virtual environment'),
'use Python 3 virtual environment.'),
cfg.StrOpt(
'python3_prefix', default=None,
help='Prefix for Python 3 installation (e.g. /opt/python3.6). If not specified, it '
'tries to find Python 3 libraries in /usr/lib and /usr/local/lib.'),
cfg.StrOpt(
'virtualenv_binary', default=default_virtualenv_bin_path,
help='Virtualenv binary which should be used to create pack virtualenvs.'),
Expand Down
30 changes: 21 additions & 9 deletions st2common/st2common/util/sandboxing.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,20 +162,32 @@ def get_sandbox_python_path_for_python_action(pack, inherit_from_parent=True,
'site-packages')

# Work around to make sure we also add system lib dir to PYTHONPATH and not just virtualenv
# one
# NOTE: abc.py is always available in base lib directory which is symlinked to virtualenv
# lib directory
abc_module_path = os.path.join(python3_lib_directory, 'abc.py')
link_path = os.path.realpath(abc_module_path)
python3_system_lib_directory = os.path.dirname(link_path)

if not os.path.exists(python3_system_lib_directory):
# one (e.g. /usr/lib/python3.6)
# NOTE: We can't simply use sys.prefix dir since it will be set to /opt/stackstorm/st2

system_prefix_dirs = []
# Take custom prefix into account (if specified)
if cfg.CONF.actionrunner.python3_prefix:
system_prefix_dirs.append(cfg.CONF.actionrunner.python3_prefix)

# By default, Python libs are installed either in /usr/lib/python3.x or
# /usr/local/lib/python3.x
system_prefix_dirs.extend(['/usr/lib', '/usr/local/lib'])

for system_prefix_dir in system_prefix_dirs:
python3_system_lib_directory = os.path.join(system_prefix_dir,
virtualenv_directories[0])

if os.path.exists(python3_system_lib_directory):
break

if not python3_system_lib_directory or not os.path.exists(python3_system_lib_directory):
python3_system_lib_directory = None

full_sandbox_python_path = []

# NOTE: Order here is very important for imports to function correctly
if python3_lib_directory:
if python3_system_lib_directory:
full_sandbox_python_path.append(python3_system_lib_directory)

full_sandbox_python_path.append(python3_lib_directory)
Expand Down
27 changes: 26 additions & 1 deletion st2common/tests/unit/test_util_sandboxing.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,6 @@ def test_get_sandbox_python_path_for_python_action_python2_used_for_venv(self,
@mock.patch('os.path.exists', mock.Mock(return_value=True))
@mock.patch('os.path.isdir', mock.Mock(return_value=True))
@mock.patch('os.listdir', mock.Mock(return_value=['python3.6']))
@mock.patch('os.path.realpath', mock.Mock(return_value='/usr/lib/python3.6/abc.py'))
@mock.patch('st2common.util.sandboxing.get_python_lib')
@mock.patch('st2common.util.sandboxing.get_pack_base_path',
mock.Mock(return_value='/tmp/packs/dummy_pack'))
Expand All @@ -165,6 +164,8 @@ def test_get_sandbox_python_path_for_python_action_python3_used_for_venv(self,
self.assertEqual(len(split), 4)

# First entry should be system lib/python3 dir
self.assertTrue('/usr/lib/python3.6' in split[0])

# Second entry should be lib/python3 dir from venv
self.assertTrue('virtualenvs/dummy_pack/lib/python3.6' in split[1])

Expand Down Expand Up @@ -207,3 +208,27 @@ def test_get_sandbox_python_path_for_python_action_python3_used_for_venv(self,
'/tmp/packs/dummy_pack/actions/lib/::/data/test1:/data/test2:'
'%s/virtualenvtest' % (sys.prefix))
self.assertEqual(python_path, expected)

# Custom prefix specified in the config
cfg.CONF.set_override(name='python3_prefix', override='/opt/lib',
group='actionrunner')

# No inheritance
python_path = get_sandbox_python_path_for_python_action(pack='dummy_pack',
inherit_from_parent=False,
inherit_parent_virtualenv=False)

split = python_path.strip(':').split(':')
self.assertEqual(len(split), 4)

# First entry should be system lib/python3 dir
self.assertTrue('/opt/lib/python3.6' in split[0])

# Second entry should be lib/python3 dir from venv
self.assertTrue('virtualenvs/dummy_pack/lib/python3.6' in split[1])

# Third entry should be python3 site-packages dir from venv
self.assertTrue('virtualenvs/dummy_pack/lib/python3.6/site-packages' in split[2])

# Fourth entry should be actions/lib dir from pack root directory
self.assertTrue('packs/dummy_pack/actions/lib/' in split[3])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.