mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2025-08-18 17:55:09 +02:00
- 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.
94 lines
3.9 KiB
YAML
94 lines
3.9 KiB
YAML
---
|
|
# Cloud flavor (hcloud API)
|
|
- name: Resolve effective hcloud token
|
|
set_fact:
|
|
_hz_token: >-
|
|
{{ HETZNER_API_TOKEN
|
|
| default(lookup('env','HETZNER_API_TOKEN'), true)
|
|
| default('', true)
|
|
}}
|
|
no_log: "{{ hetzner_no_log | bool }}"
|
|
|
|
- name: Assert hcloud token present
|
|
ansible.builtin.assert:
|
|
that: [ "_hz_token | length > 0" ]
|
|
fail_msg: "HETZNER_API_TOKEN is required for the Cloud flavor."
|
|
no_log: "{{ hetzner_no_log | bool }}"
|
|
|
|
- name: Collect hcloud servers if needed (server records without identifier)
|
|
hetzner.hcloud.server_info:
|
|
api_token: "{{ _hz_token }}"
|
|
register: _servers_info
|
|
when: rdns_records | selectattr('resource','equalto','server') | selectattr('identifier','undefined') | list | length > 0
|
|
no_log: "{{ hetzner_no_log | bool }}"
|
|
|
|
- name: Init normalized records list
|
|
set_fact:
|
|
_rdns_records: []
|
|
|
|
- name: Normalize records (autofill server.identifier by IPv4)
|
|
vars:
|
|
_match_name: >-
|
|
{{
|
|
(_servers_info.servers | default([]))
|
|
| selectattr('public_net.ipv4.ip','equalto', rec.ip_address | default(''))
|
|
| map(attribute='name') | list | first | default('')
|
|
}}
|
|
_needs_autofill: >-
|
|
{{
|
|
rec.resource == 'server'
|
|
and (rec.identifier is not defined)
|
|
and (rec.ip_address | default('') | length > 0)
|
|
}}
|
|
_normalized: >-
|
|
{{
|
|
rec if (not _needs_autofill or _match_name == '')
|
|
else (rec | combine({'identifier': _match_name}))
|
|
}}
|
|
set_fact:
|
|
_rdns_records: "{{ _rdns_records + [ _normalized ] }}"
|
|
loop: "{{ rdns_records }}"
|
|
loop_control: { loop_var: rec }
|
|
|
|
- name: Ensure server identifiers are resolved when required
|
|
assert:
|
|
that:
|
|
- >
|
|
(
|
|
(_rdns_records | selectattr('resource','equalto','server') | selectattr('identifier','defined') | list | length)
|
|
==
|
|
(_rdns_records | selectattr('resource','equalto','server') | list | length)
|
|
)
|
|
fail_msg: "Could not resolve hcloud server by IPv4 for one or more records."
|
|
no_log: "{{ hetzner_no_log | bool }}"
|
|
|
|
- name: Validate records (cloud)
|
|
ansible.builtin.assert:
|
|
that:
|
|
- (_rdns_records | default(rdns_records)) | length > 0
|
|
- (_rdns_records | default(rdns_records)) | selectattr('dns_ptr','defined') | list | length == ((_rdns_records | default(rdns_records)) | length)
|
|
- (_rdns_records | default(rdns_records)) | selectattr('ip_address','defined') | list | length == ((_rdns_records | default(rdns_records)) | length)
|
|
- (_rdns_records | default(rdns_records)) | selectattr('resource','defined') | list | length == ((_rdns_records | default(rdns_records)) | length)
|
|
- (
|
|
(_rdns_records | default(rdns_records)) | selectattr('resource','equalto','server') | selectattr('identifier','defined') | list | length
|
|
+ ((_rdns_records | default(rdns_records)) | rejectattr('resource','equalto','server') | list | length)
|
|
) == ((_rdns_records | default(rdns_records)) | length)
|
|
no_log: "{{ hetzner_no_log | bool }}"
|
|
|
|
- name: Apply rDNS via hcloud
|
|
hetzner.hcloud.hcloud_rdns:
|
|
api_token: "{{ _hz_token }}"
|
|
server: "{{ (item.resource == 'server') | ternary(item.identifier, omit) }}"
|
|
primary_ip: "{{ (item.resource == 'primary_ip') | ternary(item.identifier, omit) }}"
|
|
floating_ip: "{{ (item.resource == 'floating_ip') | ternary(item.identifier, omit) }}"
|
|
load_balancer: "{{ (item.resource == 'load_balancer') | ternary(item.identifier, omit) }}"
|
|
ip_address: "{{ item.ip_address }}"
|
|
dns_ptr: "{{ item.dns_ptr }}"
|
|
state: present
|
|
loop: "{{ _rdns_records | default(rdns_records) }}"
|
|
loop_control:
|
|
label: "{{ item.resource }}[{{ item.identifier | default('auto-by-ipv4') }}] {{ item.ip_address }} -> {{ item.dns_ptr }}"
|
|
async: "{{ hetzner_async_enabled | ternary(hetzner_async_time, omit) }}"
|
|
poll: "{{ hetzner_async_enabled | ternary(hetzner_async_poll, omit) }}"
|
|
no_log: "{{ hetzner_no_log | bool }}"
|