docker_config and docker_secret: add data_src option (#203)

* Add data_src options to docker_config and docker_secret.

* Add examples.

* Fix test.

* Another fix.
This commit is contained in:
Felix Fontein 2021-09-12 09:42:03 +02:00 committed by GitHub
parent 668f77d7d2
commit 5d861004db
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 99 additions and 6 deletions

View File

@ -0,0 +1,3 @@
minor_changes:
- "docker_config - add option ``data_src`` to read configuration data from target (https://github.com/ansible-collections/community.docker/issues/64, https://github.com/ansible-collections/community.docker/pull/203)."
- "docker_secret - add option ``data_src`` to read secret data from target (https://github.com/ansible-collections/community.docker/issues/64, https://github.com/ansible-collections/community.docker/pull/203)."

View File

@ -23,7 +23,8 @@ description:
options: options:
data: data:
description: description:
- The value of the config. Required when state is C(present). - The value of the config.
- Mutually exclusive with I(data_src). One of I(data) and I(data_src) is required if I(state=present).
type: str type: str
data_is_b64: data_is_b64:
description: description:
@ -33,6 +34,12 @@ options:
be decoded by this option. be decoded by this option.
type: bool type: bool
default: no default: no
data_src:
description:
- The file on the target from which to read the config.
- Mutually exclusive with I(data). One of I(data) and I(data_src) is required if I(state=present).
type: path
version_added: 1.10.0
labels: labels:
description: description:
- "A map of key:value meta data, where both the I(key) and I(value) are expected to be a string." - "A map of key:value meta data, where both the I(key) and I(value) are expected to be a string."
@ -84,6 +91,12 @@ EXAMPLES = '''
data_is_b64: true data_is_b64: true
state: present state: present
- name: Create config foo (from a file on the target machine)
community.docker.docker_config:
name: foo
data_src: /path/to/config/file
state: present
- name: Change the config data - name: Change the config data
community.docker.docker_config: community.docker.docker_config:
name: foo name: foo
@ -183,6 +196,13 @@ class ConfigManager(DockerBaseClass):
self.data = base64.b64decode(self.data) self.data = base64.b64decode(self.data)
else: else:
self.data = to_bytes(self.data) self.data = to_bytes(self.data)
data_src = parameters.get('data_src')
if data_src is not None:
try:
with open(data_src, 'rb') as f:
self.data = f.read()
except Exception as exc:
self.client.fail('Error while reading {src}: {error}'.format(src=data_src, error=to_native(exc)))
self.labels = parameters.get('labels') self.labels = parameters.get('labels')
self.force = parameters.get('force') self.force = parameters.get('force')
self.data_key = None self.data_key = None
@ -266,18 +286,24 @@ def main():
state=dict(type='str', default='present', choices=['absent', 'present']), state=dict(type='str', default='present', choices=['absent', 'present']),
data=dict(type='str'), data=dict(type='str'),
data_is_b64=dict(type='bool', default=False), data_is_b64=dict(type='bool', default=False),
data_src=dict(type='path'),
labels=dict(type='dict'), labels=dict(type='dict'),
force=dict(type='bool', default=False) force=dict(type='bool', default=False)
) )
required_if = [ required_if = [
('state', 'present', ['data']) ('state', 'present', ['data', 'data_src'], True),
]
mutually_exclusive = [
('data', 'data_src'),
] ]
client = AnsibleDockerClient( client = AnsibleDockerClient(
argument_spec=argument_spec, argument_spec=argument_spec,
supports_check_mode=True, supports_check_mode=True,
required_if=required_if, required_if=required_if,
mutually_exclusive=mutually_exclusive,
min_docker_version='2.6.0', min_docker_version='2.6.0',
min_docker_api_version='1.30', min_docker_api_version='1.30',
) )

View File

@ -23,7 +23,8 @@ description:
options: options:
data: data:
description: description:
- The value of the secret. Required when state is C(present). - The value of the secret.
- Mutually exclusive with I(data_src). One of I(data) and I(data_src) is required if I(state=present).
type: str type: str
data_is_b64: data_is_b64:
description: description:
@ -33,6 +34,12 @@ options:
be decoded by this option. be decoded by this option.
type: bool type: bool
default: no default: no
data_src:
description:
- The file on the target from which to read the secret.
- Mutually exclusive with I(data). One of I(data) and I(data_src) is required if I(state=present).
type: path
version_added: 1.10.0
labels: labels:
description: description:
- "A map of key:value meta data, where both key and value are expected to be strings." - "A map of key:value meta data, where both key and value are expected to be strings."
@ -83,6 +90,12 @@ EXAMPLES = '''
data_is_b64: true data_is_b64: true
state: present state: present
- name: Create secret foo (from a file on the target machine)
community.docker.docker_secret:
name: foo
data_src: /path/to/secret/file
state: present
- name: Change the secret data - name: Change the secret data
community.docker.docker_secret: community.docker.docker_secret:
name: foo name: foo
@ -182,6 +195,13 @@ class SecretManager(DockerBaseClass):
self.data = base64.b64decode(self.data) self.data = base64.b64decode(self.data)
else: else:
self.data = to_bytes(self.data) self.data = to_bytes(self.data)
data_src = parameters.get('data_src')
if data_src is not None:
try:
with open(data_src, 'rb') as f:
self.data = f.read()
except Exception as exc:
self.client.fail('Error while reading {src}: {error}'.format(src=data_src, error=to_native(exc)))
self.labels = parameters.get('labels') self.labels = parameters.get('labels')
self.force = parameters.get('force') self.force = parameters.get('force')
self.data_key = None self.data_key = None
@ -268,18 +288,24 @@ def main():
state=dict(type='str', default='present', choices=['absent', 'present']), state=dict(type='str', default='present', choices=['absent', 'present']),
data=dict(type='str', no_log=True), data=dict(type='str', no_log=True),
data_is_b64=dict(type='bool', default=False), data_is_b64=dict(type='bool', default=False),
data_src=dict(type='path'),
labels=dict(type='dict'), labels=dict(type='dict'),
force=dict(type='bool', default=False) force=dict(type='bool', default=False)
) )
required_if = [ required_if = [
('state', 'present', ['data']) ('state', 'present', ['data', 'data_src'], True),
]
mutually_exclusive = [
('data', 'data_src'),
] ]
client = AnsibleDockerClient( client = AnsibleDockerClient(
argument_spec=argument_spec, argument_spec=argument_spec,
supports_check_mode=True, supports_check_mode=True,
required_if=required_if, required_if=required_if,
mutually_exclusive=mutually_exclusive,
min_docker_version='2.1.0', min_docker_version='2.1.0',
min_docker_api_version='1.25', min_docker_api_version='1.25',
) )

View File

@ -1,3 +1,4 @@
--- ---
dependencies: dependencies:
- setup_docker - setup_docker
- setup_remote_tmp_dir

View File

@ -37,7 +37,7 @@
assert: assert:
that: that:
- 'output.failed' - 'output.failed'
- 'output.msg == "state is present but all of the following are missing: data"' - 'output.msg == "state is present but any of the following are missing: data, data_src"'
- name: Create config - name: Create config
docker_config: docker_config:
@ -80,6 +80,24 @@
that: that:
- not output.changed - not output.changed
- name: Write config into file
copy:
dest: "{{ remote_tmp_dir }}/data"
content: |-
opensesame!
- name: Create config again (from file)
docker_config:
name: db_password
data_src: "{{ remote_tmp_dir }}/data"
state: present
register: output
- name: assert create config is idempotent
assert:
that:
- not output.changed
- name: Create config again (base64) - name: Create config again (base64)
docker_config: docker_config:
name: db_password name: db_password

View File

@ -1,3 +1,4 @@
--- ---
dependencies: dependencies:
- setup_docker - setup_docker
- setup_remote_tmp_dir

View File

@ -33,7 +33,7 @@
assert: assert:
that: that:
- 'output.failed' - 'output.failed'
- 'output.msg == "state is present but all of the following are missing: data"' - 'output.msg == "state is present but any of the following are missing: data, data_src"'
- name: Create secret - name: Create secret
docker_secret: docker_secret:
@ -76,6 +76,24 @@
that: that:
- not output.changed - not output.changed
- name: Write secret into file
copy:
dest: "{{ remote_tmp_dir }}/data"
content: |-
opensesame!
- name: Create secret again (from file)
docker_secret:
name: db_password
data_src: "{{ remote_tmp_dir }}/data"
state: present
register: output
- name: assert create secret is idempotent
assert:
that:
- not output.changed
- name: Create secret again (base64) - name: Create secret again (base64)
docker_secret: docker_secret:
name: db_password name: db_password