From a2ca0e6012e860d329554c86ef852d51b7e64dec Mon Sep 17 00:00:00 2001 From: Ryan Petrello Date: Thu, 24 Aug 2017 16:37:59 -0400 Subject: [PATCH] add process isolation to project updates see: https://github.com/ansible/ansible-tower/issues/7506 --- awx/main/tasks.py | 12 ++++++++++++ awx/main/tests/unit/test_tasks.py | 20 ++++++++++++++++++++ awx/main/utils/common.py | 1 + 3 files changed, 33 insertions(+) diff --git a/awx/main/tasks.py b/awx/main/tasks.py index 2c884802c2..63e597ef0c 100644 --- a/awx/main/tasks.py +++ b/awx/main/tasks.py @@ -478,6 +478,7 @@ class BaseTask(LogErrorsTask): model = None abstract = True cleanup_paths = [] + proot_show_paths = [] def update_model(self, pk, _attempt=0, **updates): """Reload the model instance from the database and update the @@ -793,6 +794,7 @@ class BaseTask(LogErrorsTask): # May have to serialize the value kwargs['private_data_files'] = self.build_private_data_files(instance, **kwargs) kwargs['passwords'] = self.build_passwords(instance, **kwargs) + kwargs['proot_show_paths'] = self.proot_show_paths args = self.build_args(instance, **kwargs) safe_args = self.build_safe_args(instance, **kwargs) output_replacements = self.build_output_replacements(instance, **kwargs) @@ -1288,6 +1290,10 @@ class RunProjectUpdate(BaseTask): name = 'awx.main.tasks.run_project_update' model = ProjectUpdate + @property + def proot_show_paths(self): + return [settings.PROJECTS_ROOT] + def build_private_data(self, project_update, **kwargs): ''' Return SSH private key data needed for this project update. @@ -1594,6 +1600,12 @@ class RunProjectUpdate(BaseTask): if status == 'successful' and instance.launch_type != 'sync': self._update_dependent_inventories(instance, dependent_inventory_sources) + def should_use_proot(self, instance, **kwargs): + ''' + Return whether this task should use proot. + ''' + return getattr(settings, 'AWX_PROOT_ENABLED', False) + class RunInventoryUpdate(BaseTask): diff --git a/awx/main/tests/unit/test_tasks.py b/awx/main/tests/unit/test_tasks.py index 99ad34d766..d262e4b1ac 100644 --- a/awx/main/tests/unit/test_tasks.py +++ b/awx/main/tests/unit/test_tasks.py @@ -1096,6 +1096,26 @@ class TestProjectUpdateCredentials(TestJobExecution): ] } + def test_bwrap_exposes_projects_root(self): + ssh = CredentialType.defaults['ssh']() + self.instance.scm_type = 'git' + self.instance.credential = Credential( + pk=1, + credential_type=ssh, + ) + self.task.run(self.pk) + + assert self.run_pexpect.call_count == 1 + call_args, call_kwargs = self.run_pexpect.call_args_list[0] + args, cwd, env, stdout = call_args + + assert ' '.join(args).startswith('bwrap') + ' '.join([ + '--bind', + settings.PROJECTS_ROOT, + settings.PROJECTS_ROOT, + ]) in ' '.join(args) + def test_username_and_password_auth(self, scm_type): ssh = CredentialType.defaults['ssh']() self.instance.scm_type = scm_type diff --git a/awx/main/utils/common.py b/awx/main/utils/common.py index 58d795567f..11869e846b 100644 --- a/awx/main/utils/common.py +++ b/awx/main/utils/common.py @@ -701,6 +701,7 @@ def wrap_args_with_proot(args, cwd, **kwargs): show_paths = [cwd] show_paths.extend([settings.ANSIBLE_VENV_PATH, settings.AWX_VENV_PATH]) show_paths.extend(getattr(settings, 'AWX_PROOT_SHOW_PATHS', None) or []) + show_paths.extend(kwargs.get('proot_show_paths', [])) for path in sorted(set(show_paths)): if not os.path.exists(path): continue