Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(Backport 51871) cmdmod: add 'binds' parameter in run_chroot #54996

Merged
merged 2 commits into from
Dec 4, 2019
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
46 changes: 32 additions & 14 deletions salt/modules/cmdmod.py
Original file line number Diff line number Diff line change
Expand Up @@ -2904,6 +2904,7 @@ def run_chroot(root,
group=None,
shell=DEFAULT_SHELL,
python_shell=True,
binds=None,
env=None,
clean_env=False,
template=None,
Expand All @@ -2929,19 +2930,17 @@ def run_chroot(root,

:param str root: Path to the root of the jail to use.

stdin
A string of standard input can be specified for the command to be run using
the ``stdin`` parameter. This can be useful in cases where sensitive
information must be read from standard input.:
:param str stdin: A string of standard input can be specified for
the command to be run using the ``stdin`` parameter. This can
be useful in cases where sensitive information must be read
from standard input.:

runas
User to run script as.
:param str runas: User to run script as.

group
Group to run script as.
:param str group: Group to run script as.

shell
Shell to execute under. Defaults to the system default shell.
:param str shell: Shell to execute under. Defaults to the system
default shell.

:param str cmd: The command to run. ex: ``ls -lart /home``

Expand All @@ -2965,6 +2964,11 @@ def run_chroot(root,
arguments. Set to True to use shell features, such as pipes or
redirection.

:param list binds: List of directories that will be exported inside
aplanas marked this conversation as resolved.
Show resolved Hide resolved
the chroot with the bind option.

.. versionadded:: Sodium

:param dict env: Environment variables to be set prior to execution.

.. note::
Expand All @@ -2983,11 +2987,11 @@ def run_chroot(root,
engine will be used to render the downloaded file. Currently jinja,
mako, and wempy are supported.

:param bool rstrip:
Strip all whitespace off the end of output before it is returned.
:param bool rstrip: Strip all whitespace off the end of output
before it is returned.

:param str umask:
The umask (in octal) to use when running the command.
:param str umask: The umask (in octal) to use when running the
command.

:param str output_encoding: Control the encoding used to decode the
command's output.
Expand Down Expand Up @@ -3061,6 +3065,15 @@ def run_chroot(root,
'sysfs',
fstype='sysfs')

binds = binds if binds else []
for bind_exported in binds:
bind_exported_to = os.path.relpath(bind_exported, os.path.sep)
bind_exported_to = os.path.join(root, bind_exported_to)
__salt__['mount.mount'](
bind_exported_to,
bind_exported,
opts='default,bind')

# Execute chroot routine
sh_ = '/bin/sh'
if os.path.isfile(os.path.join(root, 'bin/bash')):
Expand Down Expand Up @@ -3111,6 +3124,11 @@ def run_chroot(root,
log.error('Processes running in chroot could not be killed, '
'filesystem will remain mounted')

for bind_exported in binds:
bind_exported_to = os.path.relpath(bind_exported, os.path.sep)
bind_exported_to = os.path.join(root, bind_exported_to)
__salt__['mount.umount'](bind_exported_to)

__salt__['mount.umount'](os.path.join(root, 'sys'))
__salt__['mount.umount'](os.path.join(root, 'proc'))
__salt__['mount.umount'](os.path.join(root, 'dev'))
Expand Down
30 changes: 30 additions & 0 deletions tests/unit/modules/test_cmdmod.py
Original file line number Diff line number Diff line change
Expand Up @@ -433,3 +433,33 @@ def test_run_all_output_encoding(self):
ret = cmdmod.run_all('some command', output_encoding='latin1')

self.assertEqual(ret['stdout'], stdout)

def test_run_chroot_mount(self):
'''
Test cmdmod.run_chroot mount / umount balance
'''
mock_mount = MagicMock()
mock_umount = MagicMock()
mock_run_all = MagicMock()
with patch.dict(cmdmod.__salt__, {
'mount.mount': mock_mount,
'mount.umount': mock_umount}):
with patch('salt.modules.cmdmod.run_all', mock_run_all):
cmdmod.run_chroot('/mnt', 'cmd')
self.assertEqual(mock_mount.call_count, 3)
self.assertEqual(mock_umount.call_count, 3)

def test_run_chroot_mount_bind(self):
'''
Test cmdmod.run_chroot mount / umount balance with bind mount
'''
mock_mount = MagicMock()
mock_umount = MagicMock()
mock_run_all = MagicMock()
with patch.dict(cmdmod.__salt__, {
'mount.mount': mock_mount,
'mount.umount': mock_umount}):
with patch('salt.modules.cmdmod.run_all', mock_run_all):
cmdmod.run_chroot('/mnt', 'cmd', binds=['/var'])
self.assertEqual(mock_mount.call_count, 4)
self.assertEqual(mock_umount.call_count, 4)