Skip to content

Commit 9af86ce

Browse files
authored
Merge pull request #25 from fosterseth/pass_incontainer_path
Allow passing in container_root for extra_vars file
2 parents 15e8a8f + 8a3c74c commit 9af86ce

5 files changed

+125
-3
lines changed

.flake8

+1
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ per-file-ignores =
110110
# additionally test docstrings don't need param lists (DAR, DCO020):
111111
tests/**.py: DAR, DCO020, S101, S105, S108, S404, S603, WPS202, WPS210, WPS430, WPS436, WPS441, WPS442, WPS450
112112

113+
tests/_temporary_private_container_api_test.py: DAR, DCO020, S101, S105, S108, S404, S603, WPS202, WPS210, WPS226, WPS430, WPS436, WPS441, WPS442, WPS450
113114
tests/_temporary_private_inject_api_test.py: DAR, DCO020, S101, S105, S108, S404, S603, WPS202, WPS210, WPS226, WPS430, WPS436, WPS441, WPS442, WPS450, WPS201
114115

115116
src/awx_plugins/interfaces/_temporary_private_inject_api.py: ANN001,ANN201,B950,C901,CCR001,D103,E800,LN001,LN002,Q003,WPS110,WPS111,WPS118,WPS125,WPS204,WPS210,WPS211,WPS213,WPS221,WPS226,WPS231,WPS232,WPS319,WPS323,WPS336,WPS337,WPS361,WPS421,WPS429,WPS430,WPS431,WPS436,WPS442,WPS503,WPS507,WPS516,WPS226

src/awx_plugins/interfaces/_temporary_private_container_api.py

+12-2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
def get_incontainer_path(
1919
path: os.PathLike[str] | str,
2020
private_data_dir: os.PathLike[str] | str,
21+
*,
22+
container_root: os.PathLike[str] | str | None = None,
2123
) -> str:
2224
"""Produce an in-container path string.
2325
@@ -30,6 +32,8 @@ def get_incontainer_path(
3032
:param path: Host-side path view.
3133
:param private_data_dir: Host-side directory mounted to ``/runner``
3234
in container.
35+
:param container_root: Container-side root directory to mount the private
36+
data directory to.
3337
3438
:raises RuntimeError: If the private data directory is not absolute or does
3539
not contain the path.
@@ -39,15 +43,21 @@ def get_incontainer_path(
3943
if not os.path.isabs(private_data_dir):
4044
raise RuntimeError('The private_data_dir path must be absolute')
4145

42-
container_root = pathlib.Path(CONTAINER_ROOT)
46+
container_root_path = pathlib.Path(
47+
CONTAINER_ROOT if container_root is None
48+
else container_root,
49+
)
4350

4451
# NOTE: Due to how `tempfile.mkstemp()` works, we are probably passed
4552
# NOTE: a resolved `path`, but unresolved `private_data_dir``.
4653
resolved_path = pathlib.Path(path).resolve()
4754
resolved_pdd = pathlib.Path(private_data_dir).resolve()
4855

4956
try:
50-
return str(container_root / resolved_path.relative_to(resolved_pdd))
57+
return str(
58+
container_root_path /
59+
resolved_path.relative_to(resolved_pdd),
60+
)
5161
except ValueError as val_err:
5262
raise RuntimeError(
5363
f'Cannot convert path {resolved_path !s} '

src/awx_plugins/interfaces/_temporary_private_inject_api.py

+7-1
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,8 @@ def inject_credential(
159159
safe_env: EnvVarsType,
160160
args: ArgsType,
161161
private_data_dir: str,
162+
*,
163+
container_root: os.PathLike[str] | str | None = None,
162164
) -> None:
163165
# pylint: disable=unidiomatic-typecheck
164166
"""Inject credential data.
@@ -181,6 +183,8 @@ def inject_credential(
181183
:param private_data_dir: a temporary directory to store files
182184
generated by file injectors (like configuration files or key
183185
files)
186+
:param container_root: root directory inside the container to mount
187+
the private data directory to.
184188
:returns: None
185189
"""
186190
if not cred_type.injectors:
@@ -287,7 +291,9 @@ def inject_credential(
287291
)
288292
if extra_vars:
289293
path = _build_extra_vars_file(extra_vars, private_data_dir)
290-
container_path = get_incontainer_path(path, private_data_dir)
294+
container_path = get_incontainer_path(
295+
path, private_data_dir, container_root=container_root,
296+
)
291297
args.extend(
292298
# pylint: disable-next=consider-using-f-string
293299
['-e', '@%s' % container_path],

tests/_temporary_private_container_api_test.py

+55
Original file line numberDiff line numberDiff line change
@@ -87,3 +87,58 @@ def test_paths_outside_private_path_conversion(
8787
get_incontainer_path(typed_host_path, typed_host_runner_path)
8888

8989
assert isinstance(raised_exc_info.value.__cause__, ValueError)
90+
91+
92+
@pytest.mark.parametrize(
93+
(
94+
'host_path',
95+
'host_runner_path',
96+
'container_root',
97+
'expected_incontainer_path',
98+
),
99+
(
100+
('/root', '/', '/tmp', '/tmp/root'),
101+
(
102+
'/tmp/private/subdir',
103+
'/tmp/private',
104+
'/tmp/private',
105+
'/tmp/private/subdir',
106+
),
107+
(
108+
'/tmp/private/subdir',
109+
'/tmp/private',
110+
None,
111+
f'{CONTAINER_ROOT}/subdir',
112+
),
113+
),
114+
ids=('differing-paths', 'same-paths', 'default-container-root'),
115+
)
116+
@pytest.mark.parametrize(
117+
'convert_path_to_type',
118+
(pathlib.Path, str),
119+
ids=('host-path-pathlib', 'host-path-str'),
120+
)
121+
@pytest.mark.parametrize(
122+
'convert_runner_path_to_type',
123+
(pathlib.Path, str),
124+
ids=('host-path-pathlib', 'host-path-str'),
125+
)
126+
# pylint: disable-next=too-many-arguments,too-many-positional-arguments
127+
def test_provide_custom_container_root( # noqa: WPS211
128+
host_path: os.PathLike[str] | str,
129+
host_runner_path: os.PathLike[str] | str,
130+
container_root: os.PathLike[str] | str | None,
131+
expected_incontainer_path: str,
132+
convert_path_to_type: PathToTypeCallableType,
133+
convert_runner_path_to_type: PathToTypeCallableType,
134+
) -> None:
135+
"""Ensure custom container root is respected."""
136+
typed_host_path = convert_path_to_type(host_path)
137+
typed_host_runner_path = convert_runner_path_to_type(host_runner_path)
138+
139+
incontainer_path = get_incontainer_path(
140+
typed_host_path,
141+
typed_host_runner_path,
142+
container_root=container_root,
143+
)
144+
assert expected_incontainer_path == incontainer_path

tests/_temporary_private_inject_api_test.py

+50
Original file line numberDiff line numberDiff line change
@@ -599,3 +599,53 @@ def custom_injectors(_cr: Credential, env: EnvVarsType, _pd: str) -> None:
599599
)
600600

601601
assert safe_env.items() == expected_safe_env.items()
602+
603+
604+
@pytest.mark.parametrize(
605+
(
606+
'container_root',
607+
'expected_arg_prefix',
608+
),
609+
(
610+
pytest.param(
611+
None,
612+
f'@{CONTAINER_ROOT}/',
613+
id='default-root',
614+
),
615+
pytest.param(
616+
'/custom_root',
617+
'@/custom_root/',
618+
id='custom-root',
619+
),
620+
),
621+
)
622+
def test_custom_container_root_with_extra_vars(
623+
private_data_dir: str,
624+
container_root: str | None,
625+
expected_arg_prefix: str,
626+
) -> None:
627+
"""Check custom container root with extra vars."""
628+
cred_type = ManagedCredentialType(
629+
kind='cloudh',
630+
name='SomeCloudi',
631+
namespace='foo',
632+
managed=True,
633+
inputs={},
634+
injectors={'extra_vars': {'api_secret': '{{api_secret}}'}},
635+
)
636+
credential = Credential(inputs={})
637+
638+
env: EnvVarsType = {}
639+
cmdline_args: list[str] = []
640+
inject_credential(
641+
cred_type,
642+
credential,
643+
env,
644+
{},
645+
cmdline_args,
646+
private_data_dir,
647+
container_root=container_root,
648+
)
649+
650+
assert cmdline_args[0] == '-e'
651+
assert cmdline_args[1].startswith(expected_arg_prefix)

0 commit comments

Comments
 (0)