From 6362401432b56cf6051dc0abfdc0ce9e098337a4 Mon Sep 17 00:00:00 2001 From: Sviatoslav Sydorenko Date: Sun, 29 Sep 2024 00:54:27 +0200 Subject: [PATCH] Use `awx_plugins.interfaces` to map container path The original function `to_container_path` has been renamed into `get_incontainer_path()` to represent what it does better and make the imports more obvious. --- awx/main/models/credential.py | 8 ++++--- awx/main/tasks/jobs.py | 8 ++++--- .../test_inventory_source_injectors.py | 7 +++--- awx/main/tests/unit/test_tasks.py | 3 ++- .../unit/utils/test_execution_environments.py | 8 +++---- awx/main/utils/execution_environments.py | 23 ------------------- 6 files changed, 20 insertions(+), 37 deletions(-) diff --git a/awx/main/models/credential.py b/awx/main/models/credential.py index 53d817e3464f..052f5f9b6c4c 100644 --- a/awx/main/models/credential.py +++ b/awx/main/models/credential.py @@ -26,6 +26,9 @@ from django.utils.timezone import now from django.contrib.auth.models import User +# Shared code for the AWX platform +from awx_plugins.interfaces._temporary_private_container_api import get_incontainer_path + # DRF from awx.main.utils.pglock import advisory_lock from rest_framework.serializers import ValidationError as DRFValidationError @@ -41,7 +44,6 @@ ) from awx.main.utils import decrypt_field, classproperty, set_environ from awx.main.utils.safe_yaml import safe_dump -from awx.main.utils.execution_environments import to_container_path from awx.main.validators import validate_ssh_private_key from awx.main.models.base import CommonModelNameNotUnique, PasswordFieldsModel, PrimordialModel from awx.main.models.mixins import ResourceMixin @@ -623,7 +625,7 @@ class TowerNamespace: with open(path, 'w') as f: f.write(data) os.chmod(path, stat.S_IRUSR | stat.S_IWUSR) - container_path = to_container_path(path, private_data_dir) + container_path = get_incontainer_path(path, private_data_dir) # determine if filename indicates single file or many if file_label.find('.') == -1: @@ -665,7 +667,7 @@ def build_extra_vars_file(vars, private_dir): extra_vars = build_extra_vars(self.injectors.get('extra_vars', {})) if extra_vars: path = build_extra_vars_file(extra_vars, private_data_dir) - container_path = to_container_path(path, private_data_dir) + container_path = get_incontainer_path(path, private_data_dir) args.extend(['-e', '@%s' % container_path]) diff --git a/awx/main/tasks/jobs.py b/awx/main/tasks/jobs.py index c6cfc6a18061..80b639e2a74a 100644 --- a/awx/main/tasks/jobs.py +++ b/awx/main/tasks/jobs.py @@ -18,6 +18,9 @@ # Django from django.conf import settings +# Shared code for the AWX platform +from awx_plugins.interfaces._temporary_private_container_api import CONTAINER_ROOT, get_incontainer_path + # Runner import ansible_runner @@ -67,7 +70,6 @@ from awx.main.tasks.facts import start_fact_cache, finish_fact_cache from awx.main.exceptions import AwxTaskError, PostRunError, ReceptorNodeNotFound from awx.main.utils.ansible import read_ansible_config -from awx.main.utils.execution_environments import CONTAINER_ROOT, to_container_path from awx.main.utils.safe_yaml import safe_dump, sanitize_jinja from awx.main.utils.common import ( update_scm_url, @@ -909,7 +911,7 @@ def build_env(self, job, private_data_dir, private_data_files=None): cred_files = private_data_files.get('credentials', {}) for cloud_cred in job.cloud_credentials: if cloud_cred and cloud_cred.credential_type.namespace == 'openstack' and cred_files.get(cloud_cred, ''): - env['OS_CLIENT_CONFIG_FILE'] = to_container_path(cred_files.get(cloud_cred, ''), private_data_dir) + env['OS_CLIENT_CONFIG_FILE'] = get_incontainer_path(cred_files.get(cloud_cred, ''), private_data_dir) for network_cred in job.network_credentials: env['ANSIBLE_NET_USERNAME'] = network_cred.get_input('username', default='') @@ -1552,7 +1554,7 @@ def build_args(self, inventory_update, private_data_dir, passwords): args.append('-i') script_params = dict(hostvars=True, towervars=True) source_inv_path = self.write_inventory_file(input_inventory, private_data_dir, f'hosts_{input_inventory.id}', script_params) - args.append(to_container_path(source_inv_path, private_data_dir)) + args.append(get_incontainer_path(source_inv_path, private_data_dir)) # Include any facts from input inventories so they can be used in filters start_fact_cache( input_inventory.hosts.only(*HOST_FACTS_FIELDS), diff --git a/awx/main/tests/functional/test_inventory_source_injectors.py b/awx/main/tests/functional/test_inventory_source_injectors.py index 0df9a132260d..6c93717b76b5 100644 --- a/awx/main/tests/functional/test_inventory_source_injectors.py +++ b/awx/main/tests/functional/test_inventory_source_injectors.py @@ -5,11 +5,12 @@ import re from collections import namedtuple +from awx_plugins.interfaces._temporary_private_container_api import get_incontainer_path + from awx.main.tasks.jobs import RunInventoryUpdate from awx.main.models import InventorySource, Credential, CredentialType, UnifiedJob, ExecutionEnvironment from awx.main.constants import CLOUD_PROVIDERS, STANDARD_INVENTORY_UPDATE_ENV from awx.main.tests import data -from awx.main.utils.execution_environments import to_container_path from django.conf import settings @@ -115,7 +116,7 @@ def read_content(private_data_dir, raw_env, inventory_update): continue # Ansible runner abs_file_path = os.path.join(private_data_dir, filename) file_aliases[abs_file_path] = filename - runner_path = to_container_path(abs_file_path, private_data_dir) + runner_path = get_incontainer_path(abs_file_path, private_data_dir) if runner_path in inverse_env: referenced_paths.add(abs_file_path) alias = 'file_reference' @@ -163,7 +164,7 @@ def read_content(private_data_dir, raw_env, inventory_update): # assert that all files laid down are used if ( abs_file_path not in referenced_paths - and to_container_path(abs_file_path, private_data_dir) not in inventory_content + and get_incontainer_path(abs_file_path, private_data_dir) not in inventory_content and abs_file_path not in ignore_files ): raise AssertionError( diff --git a/awx/main/tests/unit/test_tasks.py b/awx/main/tests/unit/test_tasks.py index 6c460e3236ed..d003569c82a2 100644 --- a/awx/main/tests/unit/test_tasks.py +++ b/awx/main/tests/unit/test_tasks.py @@ -12,6 +12,8 @@ import yaml import jinja2 +from awx_plugins.interfaces._temporary_private_container_api import CONTAINER_ROOT + from django.conf import settings from awx.main.models import ( @@ -37,7 +39,6 @@ from awx.main.tasks import jobs, system, receptor from awx.main.utils import encrypt_field, encrypt_value from awx.main.utils.safe_yaml import SafeLoader -from awx.main.utils.execution_environments import CONTAINER_ROOT from awx.main.utils.licensing import Licenser from awx.main.constants import JOB_VARIABLE_PREFIXES diff --git a/awx/main/tests/unit/utils/test_execution_environments.py b/awx/main/tests/unit/utils/test_execution_environments.py index 04a8b05f5f72..941623d7e127 100644 --- a/awx/main/tests/unit/utils/test_execution_environments.py +++ b/awx/main/tests/unit/utils/test_execution_environments.py @@ -4,7 +4,7 @@ import pytest -from awx.main.utils.execution_environments import to_container_path +from awx_plugins.interfaces._temporary_private_container_api import get_incontainer_path private_data_dir = '/tmp/pdd_iso/awx_xxx' @@ -22,7 +22,7 @@ ], ) def test_switch_paths(container_path, host_path): - assert to_container_path(host_path, private_data_dir) == container_path + assert get_incontainer_path(host_path, private_data_dir) == container_path def test_symlink_isolation_dir(request): @@ -40,7 +40,7 @@ def remove_folders(): pdd = f'{dst_path}/awx_xxx' - assert to_container_path(f'{pdd}/env/tmp1234', pdd) == '/runner/env/tmp1234' + assert get_incontainer_path(f'{pdd}/env/tmp1234', pdd) == '/runner/env/tmp1234' @pytest.mark.parametrize( @@ -53,4 +53,4 @@ def remove_folders(): ) def test_invalid_host_path(host_path): with pytest.raises(RuntimeError): - to_container_path(host_path, private_data_dir) + get_incontainer_path(host_path, private_data_dir) diff --git a/awx/main/utils/execution_environments.py b/awx/main/utils/execution_environments.py index 7b197287b331..f1f7faa34f7e 100644 --- a/awx/main/utils/execution_environments.py +++ b/awx/main/utils/execution_environments.py @@ -1,6 +1,4 @@ -import os import logging -from pathlib import Path from django.conf import settings @@ -51,24 +49,3 @@ def get_default_pod_spec(): ], }, } - - -# this is the root of the private data dir as seen from inside -# of the container running a job -CONTAINER_ROOT = '/runner' - - -def to_container_path(path, private_data_dir): - """Given a path inside of the host machine filesystem, - this returns the expected path which would be observed by the job running - inside of the EE container. - This only handles the volume mount from private_data_dir to /runner - """ - if not os.path.isabs(private_data_dir): - raise RuntimeError('The private_data_dir path must be absolute') - # due to how tempfile.mkstemp works, we are probably passed a resolved path, but unresolved private_data_dir - resolved_path = Path(path).resolve() - resolved_pdd = Path(private_data_dir).resolve() - if resolved_pdd != resolved_path and resolved_pdd not in resolved_path.parents: - raise RuntimeError(f'Cannot convert path {resolved_path} unless it is a subdir of {resolved_pdd}') - return str(resolved_path).replace(str(resolved_pdd), CONTAINER_ROOT, 1)