From 94333d005e22acdf35706f289981af8da711a943 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A0=20Sala?= <22398818+adrisala@users.noreply.github.com> Date: Wed, 9 Sep 2026 16:48:00 +0200 Subject: [PATCH] fix: awxkit controller_dir support for containerized installs (#16647) The controller_dir property hardcoded /tmp/awx_{id} as the expected volume mount prefix. On containerized installs the job execution directory is at /home/ansible/aap/controller/data/job_execution/awx_{id}, causing a RuntimeError when the prefix didn't match. Changed to exact path component matching on the awx_{id} segment, which works for both traditional and containerized path layouts while preventing false matches (e.g. awx_1 matching awx_10). Co-authored-by: Claude Opus 4.6 (1M context) --- awxkit/awxkit/api/pages/unified_jobs.py | 9 ++-- awxkit/test/test_unified_jobs.py | 71 +++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 3 deletions(-) create mode 100644 awxkit/test/test_unified_jobs.py diff --git a/awxkit/awxkit/api/pages/unified_jobs.py b/awxkit/awxkit/api/pages/unified_jobs.py index 8954eec30b..987391364d 100644 --- a/awxkit/awxkit/api/pages/unified_jobs.py +++ b/awxkit/awxkit/api/pages/unified_jobs.py @@ -139,15 +139,18 @@ class UnifiedJob(HasStatus, base.Base): """ self.get() job_args = self.job_args - expected_prefix = '/tmp/awx_{}'.format(self.id) + expected_segment = 'awx_{}'.format(self.id) for arg1, arg2 in zip(job_args[:-1], job_args[1:]): if arg1 == '-v': if ':' in arg2: host_loc = arg2.split(':')[0] - if host_loc.startswith(expected_prefix): + parts = host_loc.rstrip('/').split('/') + if any(p == expected_segment or p.startswith(expected_segment + '_') for p in parts): return host_loc raise RuntimeError( - 'Could not find a controller private_data_dir for this job. Searched for volume mount to {} inside of args {}'.format(expected_prefix, job_args) + 'Could not find a controller private_data_dir for this job. Searched for volume mount matching {} inside of args {}'.format( + expected_segment, job_args + ) ) diff --git a/awxkit/test/test_unified_jobs.py b/awxkit/test/test_unified_jobs.py new file mode 100644 index 0000000000..4f959d6c3b --- /dev/null +++ b/awxkit/test/test_unified_jobs.py @@ -0,0 +1,71 @@ +from unittest import mock + +import pytest + +from awxkit.api.pages.unified_jobs import UnifiedJob + + +def _make_job(job_id, job_args): + """Create a minimal UnifiedJob mock with the given id and job_args.""" + job = mock.MagicMock(spec=UnifiedJob) + job.id = job_id + job.get = mock.MagicMock() + type(job).job_args = mock.PropertyMock(return_value=job_args) + type(job).controller_dir = UnifiedJob.controller_dir + return job + + +class TestControllerDir: + def test_traditional_path(self): + job = _make_job(4387, ['podman', 'run', '-v', '/tmp/awx_4387_qv4aqn_8/:/runner/:Z', '--name', 'test']) + assert job.controller_dir == '/tmp/awx_4387_qv4aqn_8/' + + def test_containerized_path(self): + job = _make_job( + 4387, + [ + 'podman', + 'run', + '-v', + '/home/ansible/aap/controller/data/job_execution/awx_4387_qv4aqn_8/:/runner/:Z', + '--name', + 'test', + ], + ) + assert job.controller_dir == '/home/ansible/aap/controller/data/job_execution/awx_4387_qv4aqn_8/' + + def test_no_false_match_on_similar_id(self): + job = _make_job(1, ['podman', 'run', '-v', '/tmp/awx_10_abc/:/runner/:Z', '--name', 'test']) + with pytest.raises(RuntimeError, match='Could not find a controller private_data_dir'): + _ = job.controller_dir + + def test_exact_segment_match(self): + job = _make_job(1, ['podman', 'run', '-v', '/tmp/awx_1/:/runner/:Z', '--name', 'test']) + assert job.controller_dir == '/tmp/awx_1/' + + def test_segment_with_suffix(self): + job = _make_job(1, ['podman', 'run', '-v', '/tmp/awx_1_abc/:/runner/:Z', '--name', 'test']) + assert job.controller_dir == '/tmp/awx_1_abc/' + + def test_no_volume_mounts_raises(self): + job = _make_job(99, ['podman', 'run', '--name', 'test']) + with pytest.raises(RuntimeError, match='Could not find a controller private_data_dir'): + _ = job.controller_dir + + def test_multiple_volumes_picks_correct(self): + job = _make_job( + 42, + [ + 'podman', + 'run', + '-v', + '/etc/pki:/etc/pki:O', + '-v', + '/home/ansible/aap/controller/data/job_execution/awx_42_xyz/:/runner/:Z', + '-v', + '/usr/share/pki:/usr/share/pki:O', + '--name', + 'test', + ], + ) + assert job.controller_dir == '/home/ansible/aap/controller/data/job_execution/awx_42_xyz/'