Kevin Veen-Birkenbach 2620ee088e
refactor(dns): unify Cloudflare + Hetzner handling across roles
- replaced CERTBOT_DNS_API_TOKEN with CLOUDFLARE_API_TOKEN everywhere
- introduced generic sys-dns-cloudflare-records role for managing DNS records
- added sys-dns-hetzner-rdns role with both Cloud (hcloud) and Robot API flavors
- updated Mailu role to:
  - generate DKIM before DNS setup
  - delegate DNS + rDNS records to the new generic roles
- removed legacy per-role Cloudflare vars (MAILU_CLOUDFLARE_API_TOKEN)
- extended group vars with HOSTING_PROVIDER for rDNS flavor decision
- added hetzner.hcloud collection to requirements

This consolidates DNS management into reusable roles,
supports both Cloudflare and Hetzner providers,
and standardizes variable naming across the project.
2025-08-16 21:43:01 +02:00

105 lines
3.9 KiB
YAML

---
# run_once_sys_dns_cloudflare_records: deactivated
- name: Assert token
ansible.builtin.assert:
that: [ "CLOUDFLARE_API_TOKEN | length > 0" ]
no_log: "{{ cloudflare_no_log | bool }}"
- name: Apply A/AAAA
community.general.cloudflare_dns:
api_token: "{{ CLOUDFLARE_API_TOKEN }}"
zone: "{{ item.zone }}"
type: "{{ item.type }}"
name: "{{ item.name }}"
content: "{{ item.content }}"
proxied: "{{ item.proxied | default(false) }}"
ttl: "{{ item.ttl | default(1) }}"
state: "{{ item.state | default('present') }}"
loop: "{{ cloudflare_records | selectattr('type','in',['A','AAAA']) | list }}"
loop_control: { label: "{{ item.type }} {{ item.name }} -> {{ item.content }}" }
async: "{{ cloudflare_async_enabled | ternary(cloudflare_async_time, omit) }}"
poll: "{{ cloudflare_async_enabled | ternary(cloudflare_async_poll, omit) }}"
no_log: "{{ cloudflare_no_log | bool }}"
register: _cf_call
failed_when: >
_cf_call is failed and
(
('An identical record already exists' not in (_cf_call.msg | default('') | string))
and
('81058' not in (_cf_call.msg | default('') | string))
)
changed_when: >
(_cf_call.changed | default(false)) and
(
('An identical record already exists' not in (_cf_call.msg | default('') | string))
and
('81058' not in (_cf_call.msg | default('') | string))
)
- name: Apply CNAME/MX/TXT
community.general.cloudflare_dns:
api_token: "{{ CLOUDFLARE_API_TOKEN }}"
zone: "{{ item.zone }}"
type: "{{ item.type }}"
name: "{{ item.name }}"
value: "{{ item.value }}"
ttl: "{{ item.ttl | default(1) }}"
priority: "{{ (item.type == 'MX') | ternary(item.priority | default(10), omit) }}"
state: "{{ item.state | default('present') }}"
loop: "{{ cloudflare_records | selectattr('type','in',['CNAME','MX','TXT']) | list }}"
loop_control: { label: "{{ item.type }} {{ item.name }} -> {{ item.value }}" }
async: "{{ cloudflare_async_enabled | ternary(cloudflare_async_time, omit) }}"
poll: "{{ cloudflare_async_enabled | ternary(cloudflare_async_poll, omit) }}"
no_log: "{{ cloudflare_no_log | bool }}"
register: _cf_call
failed_when: >
_cf_call is failed and
(
('An identical record already exists' not in (_cf_call.msg | default('') | string))
and
('81058' not in (_cf_call.msg | default('') | string))
)
changed_when: >
(_cf_call.changed | default(false)) and
(
('An identical record already exists' not in (_cf_call.msg | default('') | string))
and
('81058' not in (_cf_call.msg | default('') | string))
)
- name: Apply SRV
community.general.cloudflare_dns:
api_token: "{{ CLOUDFLARE_API_TOKEN }}"
zone: "{{ item.zone }}"
type: SRV
service: "{{ item.service }}"
proto: "{{ item.proto }}"
name: "{{ item.name }}"
priority: "{{ item.priority }}"
weight: "{{ item.weight }}"
port: "{{ item.port }}"
value: "{{ item.value }}"
ttl: "{{ item.ttl | default(1) }}"
state: "{{ item.state | default('present') }}"
loop: "{{ cloudflare_records | selectattr('type','equalto','SRV') | list }}"
loop_control: { label: "SRV {{ item.service }}.{{ item.proto }} {{ item.name }} -> {{ item.value }}:{{ item.port }}" }
ignore_errors: "{{ item.ignore_errors | default(true) }}"
async: "{{ cloudflare_async_enabled | ternary(cloudflare_async_time, omit) }}"
poll: "{{ cloudflare_async_enabled | ternary(cloudflare_async_poll, omit) }}"
no_log: "{{ cloudflare_no_log | bool }}"
register: _cf_call
failed_when: >
_cf_call is failed and
(
('An identical record already exists' not in (_cf_call.msg | default('') | string))
and
('81058' not in (_cf_call.msg | default('') | string))
)
changed_when: >
(_cf_call.changed | default(false)) and
(
('An identical record already exists' not in (_cf_call.msg | default('') | string))
and
('81058' not in (_cf_call.msg | default('') | string))
)