docker_swarm_service: Make secret_id and config_id optional (#58299)

* Lookup secret id by name if not set

* Lookup config id by name if not set

* Add changelog fragment

* Remove usage of secret/config_id in examples

* Python 2.6 compat

* Extend secrets and configs tests
pull/57588/head
Hannes Ljungberg 5 years ago committed by Felix Fontein
parent 4d5a3d3341
commit 1b90e10cf0

@ -0,0 +1,2 @@
minor_changes:
- "docker_swarm_service - Remove requirement of ``secret_id`` on ``secrets`` and ``config_id`` on ``configs``."

@ -44,7 +44,6 @@ options:
description: description:
- Config's ID. - Config's ID.
type: str type: str
required: yes
config_name: config_name:
description: description:
- Config's name as defined at its creation. - Config's name as defined at its creation.
@ -598,7 +597,6 @@ options:
description: description:
- Secret's ID. - Secret's ID.
type: str type: str
required: yes
secret_name: secret_name:
description: description:
- Secret's name as defined at its creation. - Secret's name as defined at its creation.
@ -993,8 +991,7 @@ EXAMPLES = '''
name: myservice name: myservice
image: alpine:edge image: alpine:edge
configs: configs:
- config_id: myconfig_id - config_name: myconfig_name
config_name: myconfig_name
filename: "/tmp/config.txt" filename: "/tmp/config.txt"
- name: Set networks - name: Set networks
@ -1009,8 +1006,7 @@ EXAMPLES = '''
name: myservice name: myservice
image: alpine:edge image: alpine:edge
secrets: secrets:
- secret_id: mysecret_id - secret_name: mysecret_name
secret_name: mysecret_name
filename: "/run/secrets/secret.txt" filename: "/run/secrets/secret.txt"
- name: Start service with healthcheck - name: Start service with healthcheck
@ -1480,7 +1476,9 @@ class DockerService(DockerBaseClass):
} }
@classmethod @classmethod
def from_ansible_params(cls, ap, old_service, image_digest, can_update_networks): def from_ansible_params(
cls, ap, old_service, image_digest, can_update_networks, secret_ids, config_ids
):
s = DockerService() s = DockerService()
s.image = image_digest s.image = image_digest
s.can_update_networks = can_update_networks s.can_update_networks = can_update_networks
@ -1616,9 +1614,10 @@ class DockerService(DockerBaseClass):
s.configs = [] s.configs = []
for param_m in ap['configs']: for param_m in ap['configs']:
service_c = {} service_c = {}
service_c['config_id'] = param_m['config_id'] config_name = param_m['config_name']
service_c['config_name'] = param_m['config_name'] service_c['config_id'] = param_m['config_id'] or config_ids[config_name]
service_c['filename'] = param_m['filename'] or service_c['config_name'] service_c['config_name'] = config_name
service_c['filename'] = param_m['filename'] or config_name
service_c['uid'] = param_m['uid'] service_c['uid'] = param_m['uid']
service_c['gid'] = param_m['gid'] service_c['gid'] = param_m['gid']
service_c['mode'] = param_m['mode'] service_c['mode'] = param_m['mode']
@ -1628,9 +1627,10 @@ class DockerService(DockerBaseClass):
s.secrets = [] s.secrets = []
for param_m in ap['secrets']: for param_m in ap['secrets']:
service_s = {} service_s = {}
service_s['secret_id'] = param_m['secret_id'] secret_name = param_m['secret_name']
service_s['secret_name'] = param_m['secret_name'] service_s['secret_id'] = param_m['secret_id'] or secret_ids[secret_name]
service_s['filename'] = param_m['filename'] or service_s['secret_name'] service_s['secret_name'] = secret_name
service_s['filename'] = param_m['filename'] or secret_name
service_s['uid'] = param_m['uid'] service_s['uid'] = param_m['uid']
service_s['gid'] = param_m['gid'] service_s['gid'] = param_m['gid']
service_s['mode'] = param_m['mode'] service_s['mode'] = param_m['mode']
@ -2326,6 +2326,54 @@ class DockerServiceManager(object):
self.client.docker_py_version >= LooseVersion('2.7') self.client.docker_py_version >= LooseVersion('2.7')
) )
def get_missing_secret_ids(self):
"""
Resolve missing secret ids by looking them up by name
"""
secret_names = [
secret['secret_name']
for secret in self.client.module.params.get('secrets') or []
if secret['secret_id'] is None
]
if not secret_names:
return {}
secrets = self.client.secrets(filters={'name': secret_names})
secrets = dict(
(secret['Spec']['Name'], secret['ID'])
for secret in secrets
if secret['Spec']['Name'] in secret_names
)
for secret_name in secret_names:
if secret_name not in secrets:
self.client.fail(
'Could not find a secret named "%s"' % secret_name
)
return secrets
def get_missing_config_ids(self):
"""
Resolve missing config ids by looking them up by name
"""
config_names = [
config['config_name']
for config in self.client.module.params.get('configs') or []
if config['config_id'] is None
]
if not config_names:
return {}
configs = self.client.configs(filters={'name': config_names})
configs = dict(
(config['Spec']['Name'], config['ID'])
for config in configs
if config['Spec']['Name'] in config_names
)
for config_name in config_names:
if config_name not in configs:
self.client.fail(
'Could not find a config named "%s"' % config_name
)
return configs
def run(self): def run(self):
self.diff_tracker = DifferenceTracker() self.diff_tracker = DifferenceTracker()
module = self.client.module module = self.client.module
@ -2351,11 +2399,15 @@ class DockerServiceManager(object):
) )
try: try:
can_update_networks = self.can_update_networks() can_update_networks = self.can_update_networks()
secret_ids = self.get_missing_secret_ids()
config_ids = self.get_missing_config_ids()
new_service = DockerService.from_ansible_params( new_service = DockerService.from_ansible_params(
module.params, module.params,
current_service, current_service,
image_digest, image_digest,
can_update_networks can_update_networks,
secret_ids,
config_ids
) )
except Exception as e: except Exception as e:
return self.client.fail( return self.client.fail(
@ -2375,7 +2427,9 @@ class DockerServiceManager(object):
msg = 'Service removed' msg = 'Service removed'
changed = True changed = True
else: else:
changed, differences, need_rebuild, force_update = new_service.compare(current_service) changed, differences, need_rebuild, force_update = new_service.compare(
current_service
)
if changed: if changed:
self.diff_tracker.merge(differences) self.diff_tracker.merge(differences)
if need_rebuild: if need_rebuild:
@ -2504,7 +2558,7 @@ def main():
tmpfs_mode=dict(type='int') tmpfs_mode=dict(type='int')
)), )),
configs=dict(type='list', elements='dict', options=dict( configs=dict(type='list', elements='dict', options=dict(
config_id=dict(type='str', required=True), config_id=dict(type='str'),
config_name=dict(type='str', required=True), config_name=dict(type='str', required=True),
filename=dict(type='str'), filename=dict(type='str'),
uid=dict(type='str'), uid=dict(type='str'),
@ -2512,7 +2566,7 @@ def main():
mode=dict(type='int'), mode=dict(type='int'),
)), )),
secrets=dict(type='list', elements='dict', options=dict( secrets=dict(type='list', elements='dict', options=dict(
secret_id=dict(type='str', required=True), secret_id=dict(type='str'),
secret_name=dict(type='str', required=True), secret_name=dict(type='str', required=True),
filename=dict(type='str'), filename=dict(type='str'),
uid=dict(type='str'), uid=dict(type='str'),

@ -48,8 +48,7 @@
resolve_image: no resolve_image: no
command: '/bin/sh -v -c "sleep 10m"' command: '/bin/sh -v -c "sleep 10m"'
configs: configs:
- config_id: "{{ config_result_1.config_id|default('') }}" - config_name: "{{ config_name_1 }}"
config_name: "{{ config_name_1 }}"
filename: "/tmp/{{ config_name_1 }}.txt" filename: "/tmp/{{ config_name_1 }}.txt"
register: configs_2 register: configs_2
ignore_errors: yes ignore_errors: yes
@ -64,10 +63,38 @@
- config_id: "{{ config_result_1.config_id|default('') }}" - config_id: "{{ config_result_1.config_id|default('') }}"
config_name: "{{ config_name_1 }}" config_name: "{{ config_name_1 }}"
filename: "/tmp/{{ config_name_1 }}.txt" filename: "/tmp/{{ config_name_1 }}.txt"
- config_name: "{{ config_name_2 }}"
filename: "/tmp/{{ config_name_2 }}.txt"
register: configs_3
ignore_errors: yes
- name: configs (add idempotency)
docker_swarm_service:
name: "{{ service_name }}"
image: alpine:3.8
resolve_image: no
command: '/bin/sh -v -c "sleep 10m"'
configs:
- config_name: "{{ config_name_1 }}"
filename: "/tmp/{{ config_name_1 }}.txt"
- config_id: "{{ config_result_2.config_id|default('') }}" - config_id: "{{ config_result_2.config_id|default('') }}"
config_name: "{{ config_name_2 }}" config_name: "{{ config_name_2 }}"
filename: "/tmp/{{ config_name_2 }}.txt" filename: "/tmp/{{ config_name_2 }}.txt"
register: configs_3 register: configs_4
ignore_errors: yes
- name: configs (add idempotency no id)
docker_swarm_service:
name: "{{ service_name }}"
image: alpine:3.8
resolve_image: no
command: '/bin/sh -v -c "sleep 10m"'
configs:
- config_name: "{{ config_name_1 }}"
filename: "/tmp/{{ config_name_1 }}.txt"
- config_name: "{{ config_name_2 }}"
filename: "/tmp/{{ config_name_2 }}.txt"
register: configs_5
ignore_errors: yes ignore_errors: yes
- name: configs (empty) - name: configs (empty)
@ -77,7 +104,7 @@
resolve_image: no resolve_image: no
command: '/bin/sh -v -c "sleep 10m"' command: '/bin/sh -v -c "sleep 10m"'
configs: [] configs: []
register: configs_4 register: configs_6
ignore_errors: yes ignore_errors: yes
- name: configs (empty idempotency) - name: configs (empty idempotency)
@ -87,7 +114,7 @@
resolve_image: no resolve_image: no
command: '/bin/sh -v -c "sleep 10m"' command: '/bin/sh -v -c "sleep 10m"'
configs: [] configs: []
register: configs_5 register: configs_7
ignore_errors: yes ignore_errors: yes
- name: cleanup - name: cleanup
@ -101,8 +128,10 @@
- configs_1 is changed - configs_1 is changed
- configs_2 is not changed - configs_2 is not changed
- configs_3 is changed - configs_3 is changed
- configs_4 is changed - configs_4 is not changed
- configs_5 is not changed - configs_5 is not changed
- configs_6 is changed
- configs_7 is not changed
when: docker_api_version is version('1.30', '>=') and docker_py_version is version('2.6.0', '>=') when: docker_api_version is version('1.30', '>=') and docker_py_version is version('2.6.0', '>=')
- assert: - assert:

@ -48,8 +48,7 @@
resolve_image: no resolve_image: no
command: '/bin/sh -v -c "sleep 10m"' command: '/bin/sh -v -c "sleep 10m"'
secrets: secrets:
- secret_id: "{{ secret_result_1.secret_id|default('') }}" - secret_name: "{{ secret_name_1 }}"
secret_name: "{{ secret_name_1 }}"
filename: "/run/secrets/{{ secret_name_1 }}.txt" filename: "/run/secrets/{{ secret_name_1 }}.txt"
register: secrets_2 register: secrets_2
ignore_errors: yes ignore_errors: yes
@ -64,10 +63,38 @@
- secret_id: "{{ secret_result_1.secret_id|default('') }}" - secret_id: "{{ secret_result_1.secret_id|default('') }}"
secret_name: "{{ secret_name_1 }}" secret_name: "{{ secret_name_1 }}"
filename: "/run/secrets/{{ secret_name_1 }}.txt" filename: "/run/secrets/{{ secret_name_1 }}.txt"
- secret_name: "{{ secret_name_2 }}"
filename: "/run/secrets/{{ secret_name_2 }}.txt"
register: secrets_3
ignore_errors: yes
- name: secrets (add idempotency)
docker_swarm_service:
name: "{{ service_name }}"
image: alpine:3.8
resolve_image: no
command: '/bin/sh -v -c "sleep 10m"'
secrets:
- secret_name: "{{ secret_name_1 }}"
filename: "/run/secrets/{{ secret_name_1 }}.txt"
- secret_id: "{{ secret_result_2.secret_id|default('') }}" - secret_id: "{{ secret_result_2.secret_id|default('') }}"
secret_name: "{{ secret_name_2 }}" secret_name: "{{ secret_name_2 }}"
filename: "/run/secrets/{{ secret_name_2 }}.txt" filename: "/run/secrets/{{ secret_name_2 }}.txt"
register: secrets_3 register: secrets_4
ignore_errors: yes
- name: secrets (add idempotency no id)
docker_swarm_service:
name: "{{ service_name }}"
image: alpine:3.8
resolve_image: no
command: '/bin/sh -v -c "sleep 10m"'
secrets:
- secret_name: "{{ secret_name_1 }}"
filename: "/run/secrets/{{ secret_name_1 }}.txt"
- secret_name: "{{ secret_name_2 }}"
filename: "/run/secrets/{{ secret_name_2 }}.txt"
register: secrets_5
ignore_errors: yes ignore_errors: yes
- name: secrets (empty) - name: secrets (empty)
@ -77,7 +104,7 @@
resolve_image: no resolve_image: no
command: '/bin/sh -v -c "sleep 10m"' command: '/bin/sh -v -c "sleep 10m"'
secrets: [] secrets: []
register: secrets_4 register: secrets_6
ignore_errors: yes ignore_errors: yes
- name: secrets (empty idempotency) - name: secrets (empty idempotency)
@ -87,7 +114,7 @@
resolve_image: no resolve_image: no
command: '/bin/sh -v -c "sleep 10m"' command: '/bin/sh -v -c "sleep 10m"'
secrets: [] secrets: []
register: secrets_5 register: secrets_7
ignore_errors: yes ignore_errors: yes
- name: cleanup - name: cleanup
@ -101,8 +128,10 @@
- secrets_1 is changed - secrets_1 is changed
- secrets_2 is not changed - secrets_2 is not changed
- secrets_3 is changed - secrets_3 is changed
- secrets_4 is changed - secrets_4 is not changed
- secrets_5 is not changed - secrets_5 is not changed
- secrets_6 is changed
- secrets_7 is not changed
when: docker_api_version is version('1.25', '>=') and docker_py_version is version('2.4.0', '>=') when: docker_api_version is version('1.25', '>=') and docker_py_version is version('2.4.0', '>=')
- assert: - assert:
that: that:

Loading…
Cancel
Save