Skip to content

Commit

Permalink
Docker* connection plugins: add working_dir and privileged options (#943
Browse files Browse the repository at this point in the history
)

* Add working_dir option.

* Add privileged option.

* Add basic tests.

* Also test privileged.
  • Loading branch information
felixfontein authored Jul 25, 2024
1 parent 7464002 commit c3aceeb
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 3 deletions.
3 changes: 3 additions & 0 deletions changelogs/fragments/943-connection.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
minor_changes:
- "docker, docker_api connection plugins - allow to determine the working directory when executing commands with the new ``working_dir`` option (https://github.com/ansible-collections/community.docker/pull/943)."
- "docker, docker_api connection plugins - allow to execute commands with extended privileges with the new ``privileges`` option (https://github.com/ansible-collections/community.docker/pull/943)."
39 changes: 39 additions & 0 deletions plugins/connection/docker.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,33 @@
- name: ansible_docker_extra_env
type: dict
version_added: 3.12.0
working_dir:
description:
- The directory inside the container to run commands in.
- Requires Docker CLI version 18.06 or later.
env:
- name: ANSIBLE_DOCKER_WORKING_DIR
ini:
- key: working_dir
section: docker_connection
vars:
- name: ansible_docker_working_dir
type: string
version_added: 3.12.0
privileged:
description:
- Whether commands should be run with extended privileges.
- B(Note) that this allows command to potentially break out of the container. Use with care!
env:
- name: ANSIBLE_DOCKER_PRIVILEGED
ini:
- key: privileged
section: docker_connection
vars:
- name: ansible_docker_privileged
type: boolean
default: false
version_added: 3.12.0
'''

import fcntl
Expand Down Expand Up @@ -239,6 +266,18 @@ def _build_exec_cmd(self, cmd):
)
local_cmd += [b'-e', b'%s=%s' % (to_bytes(k, errors='surrogate_or_strict'), to_bytes(v, errors='surrogate_or_strict'))]

if self.get_option('working_dir') is not None:
local_cmd += [b'-w', to_bytes(self.get_option('working_dir'), errors='surrogate_or_strict')]
if self.docker_version != u'dev' and LooseVersion(self.docker_version) < LooseVersion(u'18.06'):
# https://github.com/docker/cli/pull/732, first appeared in release 18.06.0
raise AnsibleConnectionFailure(
'Providing the working directory requires Docker CLI version 18.06 or newer. You have Docker CLI version {0}.'
.format(self.docker_version)
)

if self.get_option('privileged'):
local_cmd += [b'--privileged']

# -i is needed to keep stdin open which allows pipelining to work
local_cmd += [b'-i', self.get_option('remote_addr')] + cmd

Expand Down
40 changes: 39 additions & 1 deletion plugins/connection/docker_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,33 @@
- name: ansible_docker_extra_env
type: dict
version_added: 3.12.0
working_dir:
description:
- The directory inside the container to run commands in.
- Requires Docker API version 1.35 or later.
env:
- name: ANSIBLE_DOCKER_WORKING_DIR
ini:
- key: working_dir
section: docker_connection
vars:
- name: ansible_docker_working_dir
type: string
version_added: 3.12.0
privileged:
description:
- Whether commands should be run with extended privileges.
- B(Note) that this allows command to potentially break out of the container. Use with care!
env:
- name: ANSIBLE_DOCKER_PRIVILEGED
ini:
- key: privileged
section: docker_connection
vars:
- name: ansible_docker_privileged
type: boolean
default: false
version_added: 3.12.0
'''

import os
Expand Down Expand Up @@ -116,6 +143,8 @@

from ansible_collections.community.docker.plugins.module_utils._api.errors import APIError, DockerException, NotFound

from ansible_collections.community.docker.plugins.module_utils.version import LooseVersion

MIN_DOCKER_API = None


Expand Down Expand Up @@ -210,7 +239,7 @@ def exec_command(self, cmd, in_data=None, sudoable=False):
data = {
'Container': self.get_option('remote_addr'),
'User': self.get_option('remote_user') or '',
'Privileged': False,
'Privileged': self.get_option('privileged'),
'Tty': False,
'AttachStdin': need_stdin,
'AttachStdout': True,
Expand All @@ -233,6 +262,15 @@ def exec_command(self, cmd, in_data=None, sudoable=False):
)
data['Env'].append(u'{0}={1}'.format(to_text(k, errors='surrogate_or_strict'), to_text(v, errors='surrogate_or_strict')))

if self.get_option('working_dir') is not None:
data['WorkingDir'] = self.get_option('working_dir')
if self.client.docker_api_version < LooseVersion('1.35'):
raise AnsibleConnectionFailure(
'Providing the working directory requires Docker API version 1.35 or newer.'
' The Docker daemon the connection is using has API version {0}.'
.format(self.client.docker_api_version_str)
)

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']

Expand Down
2 changes: 1 addition & 1 deletion tests/integration/targets/connection_docker/aliases
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
# SPDX-License-Identifier: GPL-3.0-or-later

azp/4
skip/docker # coverage does not work if we're inside a docker container, since we cannot access this container's /tmp dir from the new container
skip/docker # coverage does not work if we're inside a docker container, since we cannot access this container's /tmp dir from the new container; also privileged doesn't work
destructive
2 changes: 2 additions & 0 deletions tests/integration/targets/connection_docker/runme.sh
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ cat > test_connection.inventory << EOF
[docker]
docker-no-pipelining ansible_pipelining=false
docker-pipelining ansible_pipelining=true
docker-working-dir ansible_docker_working_dir=/home
docker-privileged ansible_docker_privileged=true
[docker:vars]
ansible_host=docker-connection-test-container${CONTAINER_SUFFIX}
Expand Down
2 changes: 1 addition & 1 deletion tests/integration/targets/connection_docker_api/aliases
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
# SPDX-License-Identifier: GPL-3.0-or-later

azp/4
skip/docker # coverage does not work if we're inside a docker container, since we cannot access this container's /tmp dir from the new container
skip/docker # coverage does not work if we're inside a docker container, since we cannot access this container's /tmp dir from the new container; also privileged doesn't work
destructive
2 changes: 2 additions & 0 deletions tests/integration/targets/connection_docker_api/runme.sh
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ cat > test_connection.inventory << EOF
[docker_api]
docker_api-no-pipelining ansible_pipelining=false
docker_api-pipelining ansible_pipelining=true
docker_api-working-dir ansible_docker_working_dir=/home
docker_api-privileged ansible_docker_privileged=true
[docker_api:vars]
ansible_host=docker-connection-test-container${CONTAINER_SUFFIX}
Expand Down

0 comments on commit c3aceeb

Please sign in to comment.