---
# Reusable management JMAP call: in `stalwart_jmap_body` (JSON), out `stalwart_jmap`.
# Param: stalwart_jmap_body - JSON request; a batch carries one method call per object owner, its call id naming that owner in a refusal.
# Param: stalwart_jmap_tolerate_rejected - true when the caller reads a set-level rejection itself (e.g. primaryKeyViolation).
- name: "π§ Resolve the Stalwart management URL and admin login once per run"
ansible.builtin.set_fact:
stalwart_jmap_url: "{{ STALWART_JMAP_URL }}"
stalwart_jmap_user_password: "{{ STALWART_ADMIN_USER ~ ':' ~ STALWART_ADMIN_PASSWORD }}"
when: stalwart_jmap_user_password is not defined
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
- name: "π§ Stalwart JMAP call"
ansible.builtin.shell:
cmd: >-
container exec -i {{ STALWART_CONTAINER_ADDRESS }}
{{ 30 | curl }} -sS -f -K -
-H "Content-Type:application/json"
{{ stalwart_jmap_url }}
stdin: |-
user = {{ stalwart_jmap_user_password | to_json(ensure_ascii=False) }}
data-binary = {{ stalwart_jmap_body | to_json(ensure_ascii=False) }}
register: stalwart_jmap_raw
changed_when: false
retries: 12
delay: 5
until: >-
stalwart_jmap_raw.rc == 0
and (stalwart_jmap_raw.stdout | from_json).methodResponses
| selectattr('0', 'equalto', 'error') | map(attribute='1.type')
| select('in', STALWART_JMAP_TRANSIENT_ERRORS) | list | length == 0
timeout: "{{ lookup('timeout', 120) | int }}"
# nocheck: include-uniform-apply-keyword β seven call sites include this file; the in-file no_log is the SPOT, per-site apply would repeat it 7Γ
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
- name: "π§ Parse Stalwart JMAP response"
ansible.builtin.set_fact:
stalwart_jmap: "{{ stalwart_jmap_raw.stdout | from_json }}"
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
- name: "β
Ensure Stalwart accepted the JMAP call"
ansible.builtin.assert:
that:
- stalwart_jmap_refused | length == 0
fail_msg: "Stalwart refused the JMAP call {{ stalwart_jmap_refused }}"
quiet: true
vars:
stalwart_jmap_refused: >-
{%- set refused = {} -%}
{%- for method, result, call in stalwart_jmap.methodResponses -%}
{%- set rejected = {} if (method == 'error' or (stalwart_jmap_tolerate_rejected | default(false) | bool))
else (result.notCreated | default({}, true))
| combine(result.notUpdated | default({}, true))
| combine(result.notDestroyed | default({}, true)
| dict2items | rejectattr('value.type', 'equalto', 'notFound') | items2dict) -%}
{%- if method == 'error' or rejected | length > 0 -%}
{%- set _ = refused.update({call: {method: result if method == 'error' else rejected}}) -%}
{%- endif -%}
{%- endfor -%}
{{ refused }}