Skip to content

Commit 7edaa77

Browse files
update how callback plugin gets copied and added to job container (#1093) (#1098)
when in containerized environment - always copy callback plugin to private_data_dir/artifacts/{job_id}/callback - appending to `ANSIBLE_CALLBACK_PLUGINS` with the runner callback plugin location (from private_data/artifacts) - unused method `utils.callback_mount` - update unit tests Co-authored-by: Alan Rominger <[email protected]> (cherry picked from commit 3b74385) Signed-off-by: Hao Liu <[email protected]> Co-authored-by: Alan Rominger <[email protected]>
1 parent 8dff126 commit 7edaa77

File tree

8 files changed

+30
-40
lines changed

8 files changed

+30
-40
lines changed

ansible_runner/config/_base.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import re
2424
import stat
2525
import tempfile
26+
import shutil
2627

2728
from base64 import b64encode
2829
from uuid import uuid4
@@ -39,7 +40,6 @@
3940
from ansible_runner.defaults import registry_auth_prefix
4041
from ansible_runner.loader import ArtifactLoader
4142
from ansible_runner.utils import (
42-
callback_mount,
4343
get_callback_dir,
4444
open_fifo_write,
4545
args2cmdline,
@@ -224,6 +224,7 @@ def _prepare_env(self, runner_mode='pexpect'):
224224
self.env['AWX_ISOLATED_DATA_DIR'] = artifact_dir
225225
if self.fact_cache_type == 'jsonfile':
226226
self.env['ANSIBLE_CACHE_PLUGIN_CONNECTION'] = os.path.join(artifact_dir, 'fact_cache')
227+
227228
else:
228229
# seed env with existing shell env
229230
self.env = os.environ.copy()
@@ -262,7 +263,18 @@ def _prepare_env(self, runner_mode='pexpect'):
262263
self.fact_cache = os.path.join(self.artifact_dir, self.settings['fact_cache'])
263264

264265
# Use local callback directory
265-
if not self.containerized:
266+
if self.containerized:
267+
# when containerized, copy the callback dir to $private_data_dir/artifacts/<job_id>/callback
268+
# then append to env['ANSIBLE_CALLBACK_PLUGINS'] with the copied location.
269+
callback_dir = os.path.join(self.artifact_dir, 'callback')
270+
# if callback dir already exists (on repeat execution with the same ident), remove it first.
271+
if os.path.exists(callback_dir):
272+
shutil.rmtree(callback_dir)
273+
shutil.copytree(get_callback_dir(), callback_dir)
274+
275+
container_callback_dir = os.path.join("/runner/artifacts", "{}".format(self.ident), "callback")
276+
self.env['ANSIBLE_CALLBACK_PLUGINS'] = ':'.join(filter(None, (self.env.get('ANSIBLE_CALLBACK_PLUGINS'), container_callback_dir)))
277+
else:
266278
callback_dir = self.env.get('AWX_LIB_DIRECTORY', os.getenv('AWX_LIB_DIRECTORY'))
267279
if callback_dir is None:
268280
callback_dir = get_callback_dir()
@@ -504,10 +516,6 @@ def wrap_args_for_containerization(self, args, execution_mode, cmdline_args):
504516
# custom show paths inside private_data_dir do not make sense
505517
self._update_volume_mount_paths(new_args, "{}".format(self.private_data_dir), dst_mount_path="/runner", labels=":Z")
506518

507-
# Mount the stdout callback plugin from the ansible-runner code base
508-
mount_paths = callback_mount(copy_if_needed=True)
509-
self._update_volume_mount_paths(new_args, mount_paths[0], dst_mount_path=mount_paths[1], labels=":Z")
510-
511519
if self.container_auth_data:
512520
# Pull in the necessary registry auth info, if there is a container cred
513521
self.registry_auth_path, registry_auth_conf_file = self._generate_container_auth_dir(self.container_auth_data)

ansible_runner/utils/__init__.py

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -61,27 +61,6 @@ def is_dir_owner(directory):
6161
return bool(current_user == callback_owner)
6262

6363

64-
def callback_mount(copy_if_needed=False):
65-
'''
66-
Return a tuple that gives mount points for the standard out callback
67-
in the form of (<host location>, <location in container>)
68-
if copy_if_needed is set, and the install is owned by another user,
69-
it will copy the plugin to a tmpdir for the mount in anticipation of SELinux problems
70-
'''
71-
container_dot_ansible = '/home/runner/.ansible'
72-
rel_path = ('callback', '',)
73-
host_path = os.path.join(get_plugin_dir(), *rel_path)
74-
if copy_if_needed:
75-
callback_dir = get_callback_dir()
76-
if not is_dir_owner(callback_dir):
77-
tmp_path = tempfile.mkdtemp(prefix='ansible_runner_plugins_')
78-
register_for_cleanup(tmp_path)
79-
host_path = os.path.join(tmp_path, 'callback')
80-
shutil.copytree(callback_dir, host_path)
81-
container_path = os.path.join(container_dot_ansible, 'plugins', *rel_path)
82-
return (host_path, container_path)
83-
84-
8564
class Bunch(object):
8665

8766
'''

test/unit/config/test__base.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
from ansible_runner.config._base import BaseConfig, BaseExecutionMode
1414
from ansible_runner.loader import ArtifactLoader
1515
from ansible_runner.exceptions import ConfigurationError
16-
from ansible_runner.utils import callback_mount
1716

1817
try:
1918
Pattern = re._pattern_type
@@ -331,7 +330,6 @@ def test_containerization_settings(tmp_path, runtime, mocker):
331330
expected_command_start.extend([
332331
'-v', '{}/artifacts/:/runner/artifacts/:Z'.format(rc.private_data_dir),
333332
'-v', '{}/:/runner/:Z'.format(rc.private_data_dir),
334-
'-v', '{0}:{1}:Z'.format(*callback_mount()),
335333
'--env-file', '{}/env.list'.format(rc.artifact_dir),
336334
])
337335

test/unit/config/test_ansible_cfg.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from ansible_runner.config.ansible_cfg import AnsibleCfgConfig
77
from ansible_runner.config._base import BaseExecutionMode
88
from ansible_runner.exceptions import ConfigurationError
9-
from ansible_runner.utils import get_executable_path, callback_mount
9+
from ansible_runner.utils import get_executable_path
1010

1111

1212
def test_ansible_cfg_init_defaults(tmp_path, patch_private_data_dir):
@@ -91,7 +91,6 @@ def test_prepare_config_command_with_containerization(tmp_path, runtime, mocker)
9191
expected_command_start.extend([
9292
'-v', '{}/artifacts/:/runner/artifacts/:Z'.format(rc.private_data_dir),
9393
'-v', '{}/:/runner/:Z'.format(rc.private_data_dir),
94-
'-v', '{0}:{1}:Z'.format(*callback_mount()),
9594
'--env-file', '{}/env.list'.format(rc.artifact_dir),
9695
])
9796

test/unit/config/test_command.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
from ansible_runner.config.command import CommandConfig
77
from ansible_runner.config._base import BaseExecutionMode
88
from ansible_runner.exceptions import ConfigurationError
9-
from ansible_runner.utils import callback_mount
109

1110

1211
def test_ansible_config_defaults(tmp_path, patch_private_data_dir):
@@ -106,7 +105,6 @@ def test_prepare_run_command_with_containerization(tmp_path, runtime, mocker):
106105
expected_command_start.extend([
107106
'-v', '{}/artifacts/:/runner/artifacts/:Z'.format(rc.private_data_dir),
108107
'-v', '{}/:/runner/:Z'.format(rc.private_data_dir),
109-
'-v', '{0}:{1}:Z'.format(*callback_mount()),
110108
'--env-file', '{}/env.list'.format(rc.artifact_dir),
111109
])
112110

test/unit/config/test_doc.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from ansible_runner.config.doc import DocConfig
77
from ansible_runner.config._base import BaseExecutionMode
88
from ansible_runner.exceptions import ConfigurationError
9-
from ansible_runner.utils import get_executable_path, callback_mount
9+
from ansible_runner.utils import get_executable_path
1010

1111

1212
def test_ansible_doc_defaults(tmp_path, patch_private_data_dir):
@@ -101,7 +101,6 @@ def test_prepare_plugin_docs_command_with_containerization(tmp_path, runtime, mo
101101
expected_command_start.extend([
102102
'-v', '{}/artifacts/:/runner/artifacts/:Z'.format(rc.private_data_dir),
103103
'-v', '{}/:/runner/:Z'.format(rc.private_data_dir),
104-
'-v', '{0}:{1}:Z'.format(*callback_mount()),
105104
'--env-file', '{}/env.list'.format(rc.artifact_dir),
106105
])
107106

@@ -170,7 +169,6 @@ def test_prepare_plugin_list_command_with_containerization(tmp_path, runtime, mo
170169
expected_command_start.extend([
171170
'-v', '{}/artifacts/:/runner/artifacts/:Z'.format(rc.private_data_dir),
172171
'-v', '{}/:/runner/:Z'.format(rc.private_data_dir),
173-
'-v', '{0}:{1}:Z'.format(*callback_mount()),
174172
'--env-file', '{}/env.list'.format(rc.artifact_dir),
175173
])
176174

test/unit/config/test_inventory.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from ansible_runner.config.inventory import InventoryConfig
77
from ansible_runner.config._base import BaseExecutionMode
88
from ansible_runner.exceptions import ConfigurationError
9-
from ansible_runner.utils import get_executable_path, callback_mount
9+
from ansible_runner.utils import get_executable_path
1010

1111

1212
def test_ansible_inventory_init_defaults(tmp_path, patch_private_data_dir):
@@ -126,7 +126,6 @@ def test_prepare_inventory_command_with_containerization(tmp_path, runtime, mock
126126
expected_command_start.extend([
127127
'-v', '{}/artifacts/:/runner/artifacts/:Z'.format(rc.private_data_dir),
128128
'-v', '{}/:/runner/:Z'.format(rc.private_data_dir),
129-
'-v', '{0}:{1}:Z'.format(*callback_mount()),
130129
'--env-file', '{}/env.list'.format(rc.artifact_dir),
131130
])
132131

test/unit/config/test_runner.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
from ansible_runner.interface import init_runner
1515
from ansible_runner.loader import ArtifactLoader
1616
from ansible_runner.exceptions import ConfigurationError
17-
from ansible_runner.utils import callback_mount
1817

1918
try:
2019
Pattern = re._pattern_type
@@ -715,6 +714,11 @@ def test_containerization_settings(tmp_path, runtime, mocker):
715714
mock_containerized = mocker.patch('ansible_runner.runner_config.RunnerConfig.containerized', new_callable=mocker.PropertyMock)
716715
mock_containerized.return_value = True
717716

717+
# In this test get_callback_dir() will not return a callback plugin dir that exists
718+
# mock shutil.copytree and shutil.rmtree to just return True instead of trying to copy
719+
mocker.patch('shutil.copytree', return_value=True)
720+
mocker.patch('shutil.rmtree', return_value=True)
721+
718722
rc = RunnerConfig(tmp_path)
719723
rc.ident = 'foo'
720724
rc.playbook = 'main.yaml'
@@ -725,6 +729,14 @@ def test_containerization_settings(tmp_path, runtime, mocker):
725729
rc.container_volume_mounts = ['/host1:/container1', '/host2:/container2']
726730
rc.prepare()
727731

732+
# validate ANSIBLE_CALLBACK_PLUGINS env var is set
733+
assert rc.env.get('ANSIBLE_CALLBACK_PLUGINS', None) is not None
734+
735+
# validate ANSIBLE_CALLBACK_PLUGINS contains callback plugin dir
736+
callback_plugins = rc.env['ANSIBLE_CALLBACK_PLUGINS'].split(':')
737+
callback_dir = os.path.join("/runner/artifacts", "{}".format(rc.ident), "callback")
738+
assert callback_dir in callback_plugins
739+
728740
extra_container_args = []
729741
if runtime == 'podman':
730742
extra_container_args = ['--quiet']
@@ -733,7 +745,6 @@ def test_containerization_settings(tmp_path, runtime, mocker):
733745

734746
expected_command_start = [runtime, 'run', '--rm', '--tty', '--interactive', '--workdir', '/runner/project'] + \
735747
['-v', '{}/:/runner/:Z'.format(rc.private_data_dir)] + \
736-
['-v', '{0}:{1}:Z'.format(*callback_mount())] + \
737748
['-v', '/host1/:/container1/', '-v', '/host2/:/container2/'] + \
738749
['--env-file', '{}/env.list'.format(rc.artifact_dir)] + \
739750
extra_container_args + \

0 commit comments

Comments
 (0)