From c625e54e820c58fb5382a20023e2a162d4d8fedd Mon Sep 17 00:00:00 2001 From: Felix Fontein Date: Thu, 25 Jul 2024 10:48:25 +0200 Subject: [PATCH] Allow to pass extra environment variables when running commands. --- changelogs/fragments/940-connection-env.yml | 2 ++ plugins/connection/docker.py | 26 ++++++++++++++++++++- plugins/connection/docker_api.py | 25 ++++++++++++++++++++ 3 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 changelogs/fragments/940-connection-env.yml diff --git a/changelogs/fragments/940-connection-env.yml b/changelogs/fragments/940-connection-env.yml new file mode 100644 index 000000000..28b99153c --- /dev/null +++ b/changelogs/fragments/940-connection-env.yml @@ -0,0 +1,2 @@ +minor_changes: + - "docker, docker_api connection plugins - allow to pass extra environment variables when executing commands with the new ``extra_env`` option (https://github.com/ansible-collections/community.docker/issues/937, https://github.com/ansible-collections/community.docker/pull/940)." diff --git a/plugins/connection/docker.py b/plugins/connection/docker.py index 133fe6a75..235f211b5 100644 --- a/plugins/connection/docker.py +++ b/plugins/connection/docker.py @@ -75,6 +75,18 @@ cli: - name: timeout type: integer + extra_env: + description: + - Provide extra environment variables to set when running commands in the Docker container. + env: + - name: ANSIBLE_DOCKER_EXTRA_ENV + ini: + - key: extra_env + section: docker_connection + vars: + - name: ansible_docker_extra_env + type: dict + version_added: 3.12.0 ''' import fcntl @@ -83,8 +95,9 @@ import subprocess import re -from ansible.errors import AnsibleError, AnsibleFileNotFound +from ansible.errors import AnsibleError, AnsibleFileNotFound, AnsibleConnectionFailure from ansible.module_utils.six.moves import shlex_quote +from ansible.module_utils.six import string_types from ansible.module_utils.common.process import get_bin_path from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text from ansible.plugins.connection import ConnectionBase, BUFSIZE @@ -210,6 +223,17 @@ def _build_exec_cmd(self, cmd): if self.remote_user is not None: local_cmd += [b'-u', self.remote_user] + if self.get_option('extra_env'): + for k, v in self.get_option('extra_env').items(): + for val, what in ((k, 'Key'), (v, 'Value')): + if not isinstance(val, string_types): + raise AnsibleConnectionFailure( + 'Non-string {0} found for extra_env option. Ambiguous env options must be ' + 'wrapped in quotes to avoid them being interpreted. {1}: {2!r}' + .format(what.lower(), what, val) + ) + local_cmd += [b'-e', b'{0}={1}'.format(to_bytes(k, errors='surrogate_or_strict'), to_bytes(v, errors='surrogate_or_strict'))] + # -i is needed to keep stdin open which allows pipelining to work local_cmd += [b'-i', self.get_option('remote_addr')] + cmd diff --git a/plugins/connection/docker_api.py b/plugins/connection/docker_api.py index a6dec85aa..861a71ad9 100644 --- a/plugins/connection/docker_api.py +++ b/plugins/connection/docker_api.py @@ -69,6 +69,18 @@ cli: - name: timeout type: integer + extra_env: + description: + - Provide extra environment variables to set when running commands in the Docker container. + env: + - name: ANSIBLE_DOCKER_EXTRA_ENV + ini: + - key: extra_env + section: docker_connection + vars: + - name: ansible_docker_extra_env + type: dict + version_added: 3.12.0 ''' import os @@ -76,6 +88,7 @@ from ansible.errors import AnsibleFileNotFound, AnsibleConnectionFailure from ansible.module_utils.common.text.converters import to_bytes, to_native, to_text +from ansible.module_utils.six import string_types from ansible.plugins.connection import ConnectionBase from ansible.utils.display import Display @@ -203,6 +216,18 @@ def exec_command(self, cmd, in_data=None, sudoable=False): if 'detachKeys' in self.client._general_configs: data['detachKeys'] = self.client._general_configs['detachKeys'] + if self.get_option('extra_env'): + data['Env'] = [] + for k, v in self.get_option('extra_env').items(): + for val, what in ((k, 'Key'), (v, 'Value')): + if not isinstance(val, string_types): + raise AnsibleConnectionFailure( + 'Non-string {0} found for extra_env option. Ambiguous env options must be ' + 'wrapped in quotes to avoid them being interpreted. {1}: {2!r}' + .format(what.lower(), what, val) + ) + data['Env'].append(u'{0}={1}'.format(to_text(k, errors='surrogate_or_strict'), to_text(v, errors='surrogate_or_strict'))) + exec_data = self._call_client(lambda: self.client.post_json_to_json('/containers/{0}/exec', self.get_option('remote_addr'), data=data)) exec_id = exec_data['Id']