From 836335b4c5112a0357c270a5c0c7acfb691cc073 Mon Sep 17 00:00:00 2001 From: Shane McDonald Date: Sat, 6 Mar 2021 11:24:56 -0500 Subject: [PATCH] Update inventory_import to run inside of an EE --- .../management/commands/inventory_import.py | 82 +++---------------- 1 file changed, 10 insertions(+), 72 deletions(-) diff --git a/awx/main/management/commands/inventory_import.py b/awx/main/management/commands/inventory_import.py index a86cc3db48..86188a14c8 100644 --- a/awx/main/management/commands/inventory_import.py +++ b/awx/main/management/commands/inventory_import.py @@ -4,7 +4,6 @@ # Python import json import logging -import fnmatch import os import re import subprocess @@ -34,11 +33,7 @@ from awx.main.utils.safe_yaml import sanitize_jinja # other AWX imports from awx.main.models.rbac import batch_role_ancestor_rebuilding -# TODO: remove proot utils once we move to running inv. updates in containers from awx.main.utils import ( - check_proot_installed, - wrap_args_with_proot, - build_proot_temp_dir, ignore_inventory_computed_fields, get_licenser ) @@ -89,27 +84,6 @@ class AnsibleInventoryLoader(object): else: self.venv_path = settings.ANSIBLE_VENV_PATH - def build_env(self): - env = dict(os.environ.items()) - env['VIRTUAL_ENV'] = self.venv_path - env['PATH'] = os.path.join(self.venv_path, "bin") + ":" + env['PATH'] - # Set configuration items that should always be used for updates - for key, value in STANDARD_INVENTORY_UPDATE_ENV.items(): - if key not in env: - env[key] = value - venv_libdir = os.path.join(self.venv_path, "lib") - env.pop('PYTHONPATH', None) # default to none if no python_ver matches - for version in os.listdir(venv_libdir): - if fnmatch.fnmatch(version, 'python[23].*'): - if os.path.isdir(os.path.join(venv_libdir, version)): - env['PYTHONPATH'] = os.path.join(venv_libdir, version, "site-packages") + ":" - break - # For internal inventory updates, these are not reported in the job_env API - logger.info('Using VIRTUAL_ENV: {}'.format(env['VIRTUAL_ENV'])) - logger.info('Using PATH: {}'.format(env['PATH'])) - logger.info('Using PYTHONPATH: {}'.format(env.get('PYTHONPATH', None))) - return env - def get_path_to_ansible_inventory(self): venv_exe = os.path.join(self.venv_path, 'bin', 'ansible-inventory') if os.path.exists(venv_exe): @@ -128,66 +102,29 @@ class AnsibleInventoryLoader(object): return shutil.which('ansible-inventory') def get_base_args(self): - # get ansible-inventory absolute path for running in bubblewrap/proot, in Popen - ansible_inventory_path = self.get_path_to_ansible_inventory() - # NOTE: why do we add "python" to the start of these args? - # the script that runs ansible-inventory specifies a python interpreter - # that makes no sense in light of the fact that we put all the dependencies - # inside of /var/lib/awx/venv/ansible, so we override the specified interpreter - # https://github.com/ansible/ansible/issues/50714 - bargs = ['python', ansible_inventory_path, '-i', self.source] + bargs = ['podman', 'run', '--user=root', '--quiet'] + bargs.extend(['-v', '{0}:{0}:Z'.format(self.source)]) + for key, value in STANDARD_INVENTORY_UPDATE_ENV.items(): + bargs.extend(['-e', '{0}={1}'.format(key, value)]) + bargs.extend([settings.AWX_CONTAINER_GROUP_DEFAULT_IMAGE]) + bargs.extend(['ansible-inventory', '-i', self.source]) bargs.extend(['--playbook-dir', functioning_dir(self.source)]) if self.verbosity: # INFO: -vvv, DEBUG: -vvvvv, for inventory, any more than 3 makes little difference bargs.append('-{}'.format('v' * min(5, self.verbosity * 2 + 1))) + bargs.append('--list') logger.debug('Using base command: {}'.format(' '.join(bargs))) return bargs - # TODO: Remove this once we move to running ansible-inventory in containers - # and don't need proot for process isolation anymore - def get_proot_args(self, cmd, env): - cwd = os.getcwd() - if not check_proot_installed(): - raise RuntimeError("proot is not installed but is configured for use") - - kwargs = {} - # we cannot safely store tmp data in source dir or trust script contents - if env['AWX_PRIVATE_DATA_DIR']: - # If this is non-blank, file credentials are being used and we need access - private_data_dir = functioning_dir(env['AWX_PRIVATE_DATA_DIR']) - logger.debug("Using private credential data in '{}'.".format(private_data_dir)) - kwargs['private_data_dir'] = private_data_dir - self.tmp_private_dir = build_proot_temp_dir() - logger.debug("Using fresh temporary directory '{}' for isolation.".format(self.tmp_private_dir)) - kwargs['proot_temp_dir'] = self.tmp_private_dir - kwargs['proot_show_paths'] = [functioning_dir(self.source), settings.AWX_ANSIBLE_COLLECTIONS_PATHS] - logger.debug("Running from `{}` working directory.".format(cwd)) - - if self.venv_path != settings.ANSIBLE_VENV_PATH: - kwargs['proot_custom_virtualenv'] = self.venv_path - - return wrap_args_with_proot(cmd, cwd, **kwargs) - - def command_to_json(self, cmd): data = {} stdout, stderr = '', '' - env = self.build_env() - # TODO: remove proot args once inv. updates run in containers - if (('AWX_PRIVATE_DATA_DIR' in env) and - getattr(settings, 'AWX_PROOT_ENABLED', False)): - cmd = self.get_proot_args(cmd, env) - - proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env) + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = proc.communicate() stdout = smart_text(stdout) stderr = smart_text(stderr) - # TODO: can be removed when proot is removed - if self.tmp_private_dir: - shutil.rmtree(self.tmp_private_dir, True) - if proc.returncode != 0: raise RuntimeError('%s failed (rc=%d) with stdout:\n%s\nstderr:\n%s' % ( 'ansible-inventory', proc.returncode, stdout, stderr)) @@ -205,9 +142,10 @@ class AnsibleInventoryLoader(object): def load(self): base_args = self.get_base_args() + logger.info('Reading Ansible inventory source: %s', self.source) - return self.command_to_json(base_args + ['--list']) + return self.command_to_json(base_args) class Command(BaseCommand):