mirror of
https://github.com/ansible/awx.git
synced 2026-04-06 02:29:21 -02:30
Use awx-plugins-shared code from awx_plugins.interfaces (#15566)
* Add `awx_plugins.interfaces` runtime dependency * Use `awx_plugins.interfaces` for runtime detection The original function name was `server_product_name()` but it didn't really represent what it did. So it was renamed into `detect_server_product_name()` in an attempt of disambiguation. * 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. * Add license file for awx_plugins.interfaces --------- Co-authored-by: Hao Liu <44379968+TheRealHaoLiu@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
97ececa8b4
commit
ece21b15d0
@@ -26,6 +26,9 @@ from django.utils.functional import cached_property
|
||||
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.fields import (
|
||||
)
|
||||
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 CredentialType(CommonModelNameNotUnique):
|
||||
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 @@ class CredentialType(CommonModelNameNotUnique):
|
||||
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])
|
||||
|
||||
|
||||
|
||||
@@ -18,6 +18,9 @@ import urllib.parse as urlparse
|
||||
# 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.receptor import AWXReceptorJob
|
||||
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 @@ class RunJob(SourceControlMixin, BaseTask):
|
||||
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 @@ class RunInventoryUpdate(SourceControlMixin, BaseTask):
|
||||
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),
|
||||
|
||||
@@ -5,11 +5,12 @@ import json
|
||||
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(
|
||||
|
||||
@@ -12,6 +12,8 @@ import pytest
|
||||
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.models.credential import HIDDEN_PASSWORD, ManagedCredentialType
|
||||
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
|
||||
|
||||
@@ -4,7 +4,7 @@ from uuid import uuid4
|
||||
|
||||
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 @@ private_data_dir = '/tmp/pdd_iso/awx_xxx'
|
||||
],
|
||||
)
|
||||
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 test_symlink_isolation_dir(request):
|
||||
|
||||
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 test_symlink_isolation_dir(request):
|
||||
)
|
||||
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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -15,7 +15,6 @@ from datetime import datetime, timezone
|
||||
import collections
|
||||
import copy
|
||||
import io
|
||||
import os
|
||||
import json
|
||||
import logging
|
||||
import re
|
||||
@@ -35,6 +34,9 @@ from cryptography import x509
|
||||
from django.conf import settings
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
# Shared code for the AWX platform
|
||||
from awx_plugins.interfaces._temporary_private_licensing_api import detect_server_product_name
|
||||
|
||||
from awx.main.constants import SUBSCRIPTION_USAGE_MODEL_UNIQUE_HOSTS
|
||||
|
||||
MAX_INSTANCES = 9999999
|
||||
@@ -480,13 +482,9 @@ def get_licenser(*args, **kwargs):
|
||||
from awx.main.utils.licensing import Licenser, OpenLicense
|
||||
|
||||
try:
|
||||
if os.path.exists('/var/lib/awx/.tower_version'):
|
||||
return Licenser(*args, **kwargs)
|
||||
else:
|
||||
if detect_server_product_name() == 'AWX':
|
||||
return OpenLicense()
|
||||
else:
|
||||
return Licenser(*args, **kwargs)
|
||||
except Exception as e:
|
||||
raise ValueError(_('Error importing License: %s') % e)
|
||||
|
||||
|
||||
def server_product_name():
|
||||
return 'AWX' if isinstance(get_licenser(), OpenLicense) else 'Red Hat Ansible Automation Platform'
|
||||
|
||||
Reference in New Issue
Block a user