summaryrefslogtreecommitdiff
path: root/roles
diff options
context:
space:
mode:
authorJoe Carstairs <me@joeac.net>2026-08-28 15:23:36 +0100
committerJoe Carstairs <me@joeac.net>2026-08-28 15:23:36 +0100
commit4931117343a3105749b4a3698dd24c824a505441 (patch)
treefd4c10ac16fc37e694bea8fced8eb5aea55cc966 /roles
parent2a15e073bceaaf0765343dd57931c85cada6f89c (diff)
ovh-ify dyndns
Diffstat (limited to 'roles')
-rw-r--r--roles/domain-zone-management/tasks/main.yml34
-rw-r--r--roles/domain-zone-management/templates/ovh.conf7
-rwxr-xr-xroles/domain-zone-management/templates/update_ovhcloud_domain_zone156
-rw-r--r--roles/dyndns/files/DIGITALOCEAN_TOKEN9
-rw-r--r--roles/dyndns/tasks/main.yml75
-rw-r--r--roles/dyndns/templates/dyndns.zone4
-rw-r--r--roles/tls/files/ovh-dns-credentials.ini14
-rw-r--r--roles/tls/tasks/main.yml2
-rw-r--r--roles/tls/templates/ovh-dns-credentials.ini4
9 files changed, 213 insertions, 92 deletions
diff --git a/roles/domain-zone-management/tasks/main.yml b/roles/domain-zone-management/tasks/main.yml
new file mode 100644
index 0000000..c3592e4
--- /dev/null
+++ b/roles/domain-zone-management/tasks/main.yml
@@ -0,0 +1,34 @@
+- name: Install jq
+ community.general.apk:
+ name: jq
+
+- name: Install OVHCloud CLI
+ ansible.builtin.shell:
+ cmd: curl -fsSL https://raw.githubusercontent.com/ovh/ovhcloud-cli/main/install.sh | sh
+ creates: /usr/bin/ovhcloud
+
+- name: Install OVHCloud CLI config
+ ansible.builtin.template:
+ src: ovh.conf
+ dest: /etc/ovh.conf
+
+- name: Create OVH domain zone append records directory
+ ansible.builtin.file:
+ path: "{{ ovh_domain_zone_append_records_directory }}"
+ state: directory
+
+- name: Create OVH domain zone replace records directory
+ ansible.builtin.file:
+ path: "{{ ovh_domain_zone_replace_records_directory }}"
+ state: directory
+
+- name: Create OVH domain zone log directory
+ ansible.builtin.file:
+ path: "{{ ovh_domain_zone_log_directory }}"
+ state: directory
+
+- name: Install OVHCloud domain zone management script
+ ansible.builtin.template:
+ src: update_ovhcloud_domain_zone
+ dest: /usr/bin/update_ovhcloud_domain_zone
+ mode: "755"
diff --git a/roles/domain-zone-management/templates/ovh.conf b/roles/domain-zone-management/templates/ovh.conf
new file mode 100644
index 0000000..a2c3739
--- /dev/null
+++ b/roles/domain-zone-management/templates/ovh.conf
@@ -0,0 +1,7 @@
+[default]
+endpoint={{ ovhcloud_endpoint }}
+
+[ovh-eu]
+application_key={{ ovhcloud_application_key }}
+application_secret={{ ovhcloud_application_secret }}
+consumer_key={{ ovhcloud_consumer_key }}
diff --git a/roles/domain-zone-management/templates/update_ovhcloud_domain_zone b/roles/domain-zone-management/templates/update_ovhcloud_domain_zone
new file mode 100755
index 0000000..dfeac61
--- /dev/null
+++ b/roles/domain-zone-management/templates/update_ovhcloud_domain_zone
@@ -0,0 +1,156 @@
+#!/bin/sh
+
+
+SCRIPT="$0"
+SCRIPT_DIR=$(cd "${SCRIPT%/*}" && pwd )
+SCRIPT_NAME=${SCRIPT##*/}
+APPEND_RECORDS_DIR="{{ ovh_domain_zone_append_records_directory }}"
+REPLACE_RECORDS_DIR="{{ ovh_domain_zone_replace_records_directory }}"
+mkdir -p ${APPEND_RECORDS_DIR}
+mkdir -p ${REPLACE_RECORDS_DIR}
+
+cut_nth_word()
+{
+ echo "$1" | cut -d ' ' -f "$2"
+}
+
+get_record_subdomain()
+{
+ record="$1"
+ subdomain="$(cut_nth_word "$record" 1)"
+ if test "$(echo "$subdomain" | grep -q [A-Z])"
+ then
+ subdomain="$(cut_nth_word "$record" 2)"
+ fi
+ if test "$subdomain" == "@"
+ then
+ subdomain=""
+ fi
+ echo "$subdomain"
+}
+
+get_record_type()
+{
+ record="$1"
+ record_type="$(cut_nth_word "$record" 2)"
+ if test "$(echo "$record_type" | grep -q [0-9])"
+ then
+ record_type="$(cut_nth_word "$record" 1)"
+ fi
+ echo "$record_type"
+}
+
+get_record_target()
+{
+ record="$1"
+ target_and_ttl="$(cut_nth_word "$record" "3-")"
+ target="$(cut_nth_word "$(echo "$target_and_ttl" | rev)" "2-" | rev)"
+ echo "$target"
+}
+
+get_record_ttl()
+{
+ record="$1"
+ ttl="$(cut_nth_word "$(echo "$record" | rev)" 1 | rev)"
+ echo "$ttl"
+}
+
+find_existing_record_ids()
+{
+ subdomain="$1"
+ record_type="$2"
+ target="$3"
+ query=".subDomain == \"${subdomain}\" and .fieldType == \"${record_type}\""
+ if [ -n "$target" ]
+ then
+ query="${query} and .target == ${target}"
+ fi
+ ovhcloud domain-zone record list joeac.net -o json \
+ | jq "map(select($query))" \
+ | jq "map(.id)" \
+ | grep -Eo [0-9]\+
+}
+
+append_record()
+{
+ subdomain="$1"
+ record_type="$2"
+ target="$3"
+ ttl="$4"
+ echo "Appending record to joeac.net zone: ${record_type} ${subdomain:-@} ${target} ${ttl}"
+ ovhcloud domain-zone record create joeac.net \
+ --field-type "$record_type" \
+ --sub-domain "$subdomain" \
+ --target "$target" \
+ --ttl "$ttl"
+}
+
+replace_records()
+{
+ subdomain="$1"
+ target="$2"
+ ttl="$3"
+ first_existing_record_id="$4"
+ echo "Replacing record ${first_existing_record_id} in joeac.net zone: ${record_type} ${subdomain:-@} ${target} ${ttl}"
+ ovhcloud domain-zone record update joeac.net "$first_existing_record_id" \
+ --sub-domain "${subdomain}" \
+ --target "${target}" \
+ --ttl "${ttl}"
+ shift 4
+ excess_record_ids="$@"
+ if [ -n "$excess_record_ids" ]
+ then
+ for id in "$excess_record_ids"
+ do
+ echo "Removing record ${id} in joeac.net zone: ${record_type} ${subdomain:-@}"
+ ovhcloud domain-zone record delete joeac.net "$id"
+ done
+ fi
+}
+
+if test $(ls ${APPEND_RECORDS_DIR} | wc -l) -eq 0
+then
+ echo "Nothing to append: no zone files in ${APPEND_RECORDS_DIR}"
+else
+ for zone_file in ${APPEND_RECORDS_DIR}/*
+ do
+ while read record
+ do
+ subdomain="$(get_record_subdomain "$record")"
+ record_type="$(get_record_type "$record")"
+ target="$(get_record_target "$record")"
+ ttl="$(get_record_ttl "$record")"
+ if test -z "$(find_existing_record_ids "$subdomain" "$record_type" "$target")"
+ then
+ append_record "$subdomain" "$record_type" "$target" "$ttl"
+ fi
+ done < "${zone_file}"
+ done
+fi
+
+if test $(ls ${REPLACE_RECORDS_DIR} | wc -l) -eq 0
+then
+ echo "Nothing to replace: no zone files in ${REPLACE_RECORDS_DIR}"
+ exit 0
+else
+ for zone_file in ${REPLACE_RECORDS_DIR}/*
+ do
+ while read record
+ do
+ subdomain="$(get_record_subdomain "$record")"
+ record_type="$(get_record_type "$record")"
+ target="$(get_record_target "$record")"
+ ttl="$(get_record_ttl "$record")"
+
+ existing_record_ids="$(find_existing_record_ids "$subdomain" "$record_type")"
+ if test -n "$existing_record_ids"
+ then
+ replace_records "$subdomain" "$target" "$ttl" "$existing_record_ids"
+ else
+ append_record "$subdomain" "$record_type" "$target" "$ttl" "$existing_record_ids"
+ fi
+ done < "${zone_file}"
+ done
+fi
+
+ovhcloud domain-zone refresh joeac.net
diff --git a/roles/dyndns/files/DIGITALOCEAN_TOKEN b/roles/dyndns/files/DIGITALOCEAN_TOKEN
deleted file mode 100644
index 7f85a33..0000000
--- a/roles/dyndns/files/DIGITALOCEAN_TOKEN
+++ /dev/null
@@ -1,9 +0,0 @@
-$ANSIBLE_VAULT;1.2;AES256;ansible
-32323233343662343033613265383639303739386139363735646133633435393261346466666530
-3031303363663639343163633164393335663639353165300a373961376339336565353630303566
-32616562373263363365656531353633663830343633356462396464626164306337656665326463
-3336666530656539330a303238353335313130313130653138663266393430646662663066663036
-37626630396438336136303032633439323436323132616665353938373139353530613539366632
-39653161363765376262393933666163363230333037383033666138373439623838643833633463
-38393437353830356362393439366461623231653437613462666466643563323933366237313366
-33613166633665363238
diff --git a/roles/dyndns/tasks/main.yml b/roles/dyndns/tasks/main.yml
index e157644..9547f1a 100644
--- a/roles/dyndns/tasks/main.yml
+++ b/roles/dyndns/tasks/main.yml
@@ -1,72 +1,11 @@
-- name: Fetch digitalocean_dyndns source
- ansible.builtin.git:
- repo: git://git.joeac.net/digitalocean_dyndns.git
- dest: /usr/local/lib/digitalocean_dyndns
-
-- name: Mark get_ip_addr.sh executable
- ansible.builtin.file:
- path: /usr/local/lib/digitalocean_dyndns/get_ip_addr.sh
- owner: joeac.net
- group: joeac.net
- mode: "775"
-
-- name: Mark dyndns.sh executable
- ansible.builtin.file:
- path: /usr/local/lib/digitalocean_dyndns/dyndns.sh
- owner: joeac.net
- group: joeac.net
- mode: "775"
-
-- name: Symlink get_ip_addr.sh
- ansible.builtin.file:
- src: /usr/local/lib/digitalocean_dyndns/get_ip_addr.sh
- dest: /usr/bin/get_ip_addr.sh
- owner: joeac.net
- group: joeac.net
- state: link
-
-- name: Symlink dyndns.sh
- ansible.builtin.file:
- src: /usr/local/lib/digitalocean_dyndns/dyndns.sh
- dest: /usr/bin/dyndns.sh
- owner: joeac.net
- group: joeac.net
- state: link
-
-- name: Create config directory
- ansible.builtin.file:
- path: /etc/digitalocean_dyndns
- state: directory
+- name: Install DynDNS zone file
+ ansible.builtin.template:
+ src: dyndns.zone
+ dest: "{{ ovh_domain_zone_replace_records_directory }}/dyndns.zone"
mode: "644"
-- name: Create cache directory
- ansible.builtin.file:
- path: /var/digitalocean_dyndns
- state: directory
- mode: "666"
-
-- name: Create log directory
- ansible.builtin.file:
- path: /var/log/digitalocean_dyndns
- state: directory
- mode: "666"
-
-- name: Copy DIGITALOCEAN_TOKEN
- ansible.builtin.copy:
- src: DIGITALOCEAN_TOKEN
- dest: /etc/digitalocean_dyndns/DIGITALOCEAN_TOKEN
- mode: "640"
-
-- name: Install daily crontabs for dyndns (IPv4)
- loop: "{{ subdomains | map(attribute='name') }}"
- ansible.builtin.cron:
- special_time: daily
- name: daily crontab for dyndns for {{ item }}.joeac.net (IPv4)
- job: CACHE_DIR=/var/digitalocean_dyndns CONFIG_DIR=/etc/digitalocean_dyndns dyndns.sh 4 {{ item }}.joeac.net >> /var/log/digitalocean_dyndns/{{ item }}.joeac.net.ipv4.log
-
-- name: Install daily crontabs for dyndns (IPv6)
- loop: "{{ subdomains | map(attribute='name') }}"
+- name: Install daily crontabs for DynDNS
ansible.builtin.cron:
special_time: daily
- name: daily crontab for dyndns for {{ item }}.joeac.net (IPv6)
- job: CACHE_DIR=/var/digitalocean_dyndns CONFIG_DIR=/etc/digitalocean_dyndns CONN_DEVICE_NAME={{ ansible_facts.default_ipv4.alias }} dyndns.sh 6 {{ item }}.joeac.net >> /var/log/digitalocean_dyndns/{{ item }}.joeac.net.ipv6.log
+ name: daily crontab for DynDNS
+ job: update_ovhcloud_domain_zone >> {{ ovh_domain_zone_log_directory }}/cron.log
diff --git a/roles/dyndns/templates/dyndns.zone b/roles/dyndns/templates/dyndns.zone
new file mode 100644
index 0000000..c3a7e6a
--- /dev/null
+++ b/roles/dyndns/templates/dyndns.zone
@@ -0,0 +1,4 @@
+{% for subdomain in ( subdomains | rejectattr("service", "none") ) %}
+{{ subdomain.name }} A {{ router.wan.ipv4 }} {{ dns_default_ttl }}
+{{ subdomain.name }} AAAA {{ ansible_facts.default_ipv6.address }} {{ dns_default_ttl }}
+{% endfor %}
diff --git a/roles/tls/files/ovh-dns-credentials.ini b/roles/tls/files/ovh-dns-credentials.ini
deleted file mode 100644
index 210a403..0000000
--- a/roles/tls/files/ovh-dns-credentials.ini
+++ /dev/null
@@ -1,14 +0,0 @@
-$ANSIBLE_VAULT;1.2;AES256;ansible
-37333731336135353732336462623564633235633561336130376361646266363930626230616230
-6261356563343235353865663836643830616561613132320a643933303936343361336634313363
-38646163363939333662393666373335346565666236363163366137616137343734303531346531
-6135343839646662660a383339303664383235656431303333623661343638663631646131393164
-34666135616533656561626131323631303637663062363266663934666634386565656339663331
-65663135303661636564386266383333326536303161636230363461313131643664663739616434
-63366335623935656337313735623134323530393636373639633863346265343831363130623861
-30316233336335653233333633333461646364656435333936613733393835343931346536366430
-31333634346362346234613137623133633731353432363037306235393131356665323761643835
-37333562393362333033313932353363356536626565373939333230303435326635636639343262
-30366466636362653536613635653034313765646238383737386636306134633135326365333065
-33656335316330326439313235323862393134663062643562636434343839323232356661656633
-39653361313235396436366564366131313731346436346236356534363937303337
diff --git a/roles/tls/tasks/main.yml b/roles/tls/tasks/main.yml
index f637ff5..caf07b2 100644
--- a/roles/tls/tasks/main.yml
+++ b/roles/tls/tasks/main.yml
@@ -28,7 +28,7 @@
certbot renew --non-interactive
- name: Install OVH DNS credentials
- ansible.builtin.copy:
+ ansible.builtin.template:
src: ovh-dns-credentials.ini
dest: /etc/ovh-dns-credentials.ini
mode: "400"
diff --git a/roles/tls/templates/ovh-dns-credentials.ini b/roles/tls/templates/ovh-dns-credentials.ini
new file mode 100644
index 0000000..d8f9522
--- /dev/null
+++ b/roles/tls/templates/ovh-dns-credentials.ini
@@ -0,0 +1,4 @@
+dns_ovh_endpoint = {{ ovhcloud_endpoint }}
+dns_ovh_application_key = {{ ovhcloud_application_key }}
+dns_ovh_application_secret = {{ ovhcloud_application_secret }}
+dns_ovh_consumer_key = {{ ovhcloud_consumer_key }}