diff --git a/awx/main/tasks.py b/awx/main/tasks.py index b6ab905837..16f79ee5ef 100644 --- a/awx/main/tasks.py +++ b/awx/main/tasks.py @@ -887,6 +887,9 @@ class BaseTask(object): ''' return os.path.abspath(os.path.join(os.path.dirname(__file__), *args)) + def build_execution_environment_params(self, instance): + return {} + def build_private_data(self, instance, private_data_dir): ''' Return SSH private key data (only if stored in DB as ssh_key_data). @@ -1129,12 +1132,13 @@ class BaseTask(object): for hostname, hv in script_data.get('_meta', {}).get('hostvars', {}).items() } json_data = json.dumps(script_data) - handle, path = tempfile.mkstemp(dir=private_data_dir) - f = os.fdopen(handle, 'w') - f.write('#! /usr/bin/env python\n# -*- coding: utf-8 -*-\nprint(%r)\n' % json_data) - f.close() - os.chmod(path, stat.S_IRUSR | stat.S_IXUSR | stat.S_IWUSR) - return path + path = os.path.join(private_data_dir, 'inventory') + os.makedirs(path, mode=0o700) + fn = os.path.join(path, 'hosts') + with open(fn, 'w') as f: + os.chmod(fn, stat.S_IRUSR | stat.S_IXUSR | stat.S_IWUSR) + f.write('#! /usr/bin/env python3\n# -*- coding: utf-8 -*-\nprint(%r)\n' % json_data) + return fn def build_args(self, instance, private_data_dir, passwords): raise NotImplementedError @@ -1429,6 +1433,7 @@ class BaseTask(object): process_isolation_params = self.build_params_process_isolation(self.instance, private_data_dir, cwd) + execution_environment_params = self.build_execution_environment_params(self.instance) env = self.build_env(self.instance, private_data_dir, isolated, private_data_files=private_data_files) self.safe_env = build_safe_env(env) @@ -1463,7 +1468,8 @@ class BaseTask(object): 'settings': { 'job_timeout': self.get_instance_timeout(self.instance), 'suppress_ansible_output': True, - **process_isolation_params, + #**process_isolation_params, + **execution_environment_params, **resource_profiling_params, }, } @@ -2003,6 +2009,14 @@ class RunJob(BaseTask): if inventory is not None: update_inventory_computed_fields.delay(inventory.id) + def build_execution_environment_params(self, instance): + execution_environment_params = { + "container_image": settings.AWX_EXECUTION_ENVIRONMENT_DEFAULT_IMAGE, + "process_isolation": True + } + return execution_environment_params + + @task(queue=get_local_queuename) class RunProjectUpdate(BaseTask): @@ -2349,7 +2363,7 @@ class RunProjectUpdate(BaseTask): # the project update playbook is not in a git repo, but uses a vendoring directory # to be consistent with the ansible-runner model, - # that is moved into the runner projecct folder here + # that is moved into the runner project folder here awx_playbooks = self.get_path_to('..', 'playbooks') copy_tree(awx_playbooks, os.path.join(private_data_dir, 'project')) @@ -2484,6 +2498,18 @@ class RunProjectUpdate(BaseTask): ''' return getattr(settings, 'AWX_PROOT_ENABLED', False) + def build_execution_environment_params(self, instance): + project_path = os.path.dirname(instance.get_project_path(check_if_exists=False)) + execution_environment_params = { + "process_isolation": True, + "container_image": settings.AWX_EXECUTION_ENVIRONMENT_DEFAULT_IMAGE, + "container_volume_mounts": [ + f"{project_path}:{project_path}", + ] + + } + return execution_environment_params + @task(queue=get_local_queuename) class RunInventoryUpdate(BaseTask): @@ -2983,6 +3009,13 @@ class RunAdHocCommand(BaseTask): if isolated_manager_instance: isolated_manager_instance.cleanup() + def build_execution_environment_params(self, instance): + execution_environment_params = { + "container_image": settings.AWX_EXECUTION_ENVIRONMENT_DEFAULT_IMAGE, + "process_isolation": True + } + return execution_environment_params + @task(queue=get_local_queuename) class RunSystemJob(BaseTask): diff --git a/awx/settings/defaults.py b/awx/settings/defaults.py index e0c1db197b..849d6220bc 100644 --- a/awx/settings/defaults.py +++ b/awx/settings/defaults.py @@ -65,6 +65,8 @@ AWX_CONTAINER_GROUP_POD_LAUNCH_RETRY_DELAY = 5 AWX_CONTAINER_GROUP_DEFAULT_NAMESPACE = 'default' AWX_CONTAINER_GROUP_DEFAULT_IMAGE = 'ansible/ansible-runner' +AWX_EXECUTION_ENVIRONMENT_DEFAULT_IMAGE = 'quay.io/ansible/ansible-runner:devel' + # Internationalization # https://docs.djangoproject.com/en/dev/topics/i18n/ # diff --git a/requirements/requirements.txt b/requirements/requirements.txt index 5829401c78..a6901fd3ef 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -1,7 +1,7 @@ adal==1.2.2 # via msrestazure aiohttp==3.6.2 # via -r /awx_devel/requirements/requirements.in aioredis==1.3.1 # via channels-redis -ansible-runner==1.4.7 # via -r /awx_devel/requirements/requirements.in +# ansible-runner==1.4.7 # via -r /awx_devel/requirements/requirements.in ansiconv==1.0.0 # via -r /awx_devel/requirements/requirements.in asciichartpy==1.5.25 # via -r /awx_devel/requirements/requirements.in asgiref==3.2.5 # via channels, channels-redis, daphne diff --git a/requirements/requirements_git.txt b/requirements/requirements_git.txt index 340cbfdcc7..04eac859a4 100644 --- a/requirements/requirements_git.txt +++ b/requirements/requirements_git.txt @@ -1 +1,2 @@ git+https://github.com/ansible/system-certifi.git@devel#egg=certifi +git+git://github.com/ansible/ansible-runner@devel#egg=ansible-runner diff --git a/tools/ansible/roles/dockerfile/templates/Dockerfile.j2 b/tools/ansible/roles/dockerfile/templates/Dockerfile.j2 index a03ac7d238..e056b10fb1 100644 --- a/tools/ansible/roles/dockerfile/templates/Dockerfile.j2 +++ b/tools/ansible/roles/dockerfile/templates/Dockerfile.j2 @@ -103,6 +103,7 @@ RUN dnf -y update && \ krb5-workstation \ libcgroup-tools \ nginx \ + podman \ @postgresql:12 \ python3-devel \ python3-libselinux \ @@ -216,6 +217,7 @@ RUN for dir in \ /var/lib/awx \ /var/lib/awx/rsyslog \ /var/lib/awx/rsyslog/conf.d \ + /var/lib/awx/.local/share/containers/storage \ /var/run/awx-rsyslog \ /var/log/tower \ /var/log/nginx \ @@ -225,6 +227,8 @@ RUN for dir in \ /var/lib/nginx ; \ do mkdir -m 0775 -p $dir ; chmod g+rw $dir ; chgrp root $dir ; done && \ for file in \ + /etc/subuid \ + /etc/subgid \ /etc/passwd \ /var/lib/awx/rsyslog/rsyslog.conf ; \ do touch $file ; chmod g+rw $file ; chgrp root $file ; done @@ -255,6 +259,8 @@ RUN ln -sf /dev/stdout /var/log/nginx/access.log && \ ln -sf /dev/stderr /var/log/nginx/error.log {% endif %} +RUN echo -e 'cgroup_manager = "cgroupfs"\nevents_logger = "file"' > /etc/containers/libpod.conf + ENV HOME="/var/lib/awx" ENV PATH="/usr/pgsql-10/bin:${PATH}" @@ -272,3 +278,5 @@ ENTRYPOINT ["/usr/bin/tini", "--"] CMD /usr/bin/launch_awx.sh VOLUME /var/lib/nginx {% endif %} + +VOLUME /var/lib/awx/.local/share/containers/storage diff --git a/tools/docker-compose/ansible/roles/sources/templates/docker-compose.yml.j2 b/tools/docker-compose/ansible/roles/sources/templates/docker-compose.yml.j2 index 0cdf4f6728..754bc803f9 100644 --- a/tools/docker-compose/ansible/roles/sources/templates/docker-compose.yml.j2 +++ b/tools/docker-compose/ansible/roles/sources/templates/docker-compose.yml.j2 @@ -33,6 +33,7 @@ services: - "../../docker-compose/_sources/local_settings.py:/etc/tower/conf.d/local_settings.py" - "../../docker-compose/_sources/SECRET_KEY:/etc/tower/SECRET_KEY" - "redis_socket:/var/run/redis/:rw" + - "/sys/fs/cgroup:/sys/fs/cgroup" privileged: true tty: true # A useful container that simply passes through log messages to the console diff --git a/tools/docker-compose/entrypoint.sh b/tools/docker-compose/entrypoint.sh index 8ed9bf2abd..13c858b441 100755 --- a/tools/docker-compose/entrypoint.sh +++ b/tools/docker-compose/entrypoint.sh @@ -2,13 +2,23 @@ if [ `id -u` -ge 500 ] || [ -z "${CURRENT_UID}" ]; then - cat << EOF > /tmp/passwd +cat << EOF > /etc/passwd root:x:0:0:root:/root:/bin/bash -awx:x:`id -u`:`id -g`:,,,:/tmp:/bin/bash +awx:x:`id -u`:`id -g`:,,,:/var/lib/awx:/bin/bash +EOF + +cat < /etc/subuid +awx:100000:50001 +EOF + +cat < /etc/subgid +awx:100000:50001 EOF - cat /tmp/passwd > /etc/passwd - rm /tmp/passwd fi +# Required to get rootless podman working after +# writing out the sub*id files above +podman system migrate + exec $@