3 # Author: Janos Lenart <janos@lenart.io>
5 ######## Public functions #####################
7 # Usage: dns_gcloud_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
12 _debug fulldomain
"$fulldomain"
13 _debug txtvalue
"$txtvalue"
15 _dns_gcloud_find_zone ||
return $?
18 _dns_gcloud_start_tr ||
return $?
19 _dns_gcloud_get_rrdatas ||
return $?
20 echo "$rrdatas" | _dns_gcloud_remove_rrs ||
return $?
21 printf "%s\n%s\n" "$rrdatas" "\"$txtvalue\"" |
grep -v '^$' | _dns_gcloud_add_rrs ||
return $?
22 _dns_gcloud_execute_tr ||
return $?
24 _info
"$fulldomain record added"
27 # Usage: dns_gcloud_rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
28 # Remove the txt record after validation.
33 _debug fulldomain
"$fulldomain"
34 _debug txtvalue
"$txtvalue"
36 _dns_gcloud_find_zone ||
return $?
39 _dns_gcloud_start_tr ||
return $?
40 _dns_gcloud_get_rrdatas ||
return $?
41 echo "$rrdatas" | _dns_gcloud_remove_rrs ||
return $?
42 echo "$rrdatas" |
grep -F -v "\"$txtvalue\"" | _dns_gcloud_add_rrs ||
return $?
43 _dns_gcloud_execute_tr ||
return $?
45 _info
"$fulldomain record added"
48 #################### Private functions below ##################################
50 _dns_gcloud_start_tr
() {
51 if ! trd
=$
(mktemp
-d); then
52 _err
"_dns_gcloud_start_tr: failed to create temporary directory"
58 if ! gcloud dns record-sets transaction start \
59 --transaction-file="$tr" \
60 --zone="$managedZone"; then
62 _err
"_dns_gcloud_start_tr: failed to execute transaction"
67 _dns_gcloud_execute_tr
() {
68 if ! gcloud dns record-sets transaction execute \
69 --transaction-file="$tr" \
70 --zone="$managedZone"; then
71 _debug
tr "$(cat "$tr")"
73 _err
"_dns_gcloud_execute_tr: failed to execute transaction"
78 for i
in $
(seq 1 120); do
79 if gcloud dns record-sets changes list \
80 --zone="$managedZone" \
81 --filter='status != done' |
83 _info
"_dns_gcloud_execute_tr: waiting for transaction to be comitted ($i/120)..."
90 _err
"_dns_gcloud_execute_tr: transaction is still pending after 10 minutes"
95 _dns_gcloud_remove_rrs
() {
96 if ! xargs -r gcloud dns record-sets transaction remove \
97 --name="$fulldomain." \
100 --zone="$managedZone" \
101 --transaction-file="$tr" --; then
102 _debug
tr "$(cat "$tr")"
104 _err
"_dns_gcloud_remove_rrs: failed to remove RRs"
109 _dns_gcloud_add_rrs
() {
111 if ! xargs -r gcloud dns record-sets transaction add \
112 --name="$fulldomain." \
115 --zone="$managedZone" \
116 --transaction-file="$tr" --; then
117 _debug
tr "$(cat "$tr")"
119 _err
"_dns_gcloud_add_rrs: failed to add RRs"
124 _dns_gcloud_find_zone
() {
125 # Prepare a filter that matches zones that are suiteable for this entry.
126 # For example, _acme-challenge.something.domain.com might need to go into something.domain.com or domain.com;
127 # this function finds the longest postfix that has a managed zone.
130 while [ "$part" != "" ]; do
131 filter
="$filter$part. "
132 part
="$(echo "$part" | sed 's/[^.]*\.*//')"
134 filter
="$filter) AND visibility=public"
135 _debug filter
"$filter"
137 # List domains and find the zone with the deepest sub-domain (in case of some levels of delegation)
138 if ! match
=$
(gcloud dns managed-zones list \
139 --format="value(name, dnsName)" \
141 while read -r dnsName name
; do
142 printf "%s\t%s\t%s\n" "$(echo "$name" | awk -F".
" '{print NF-1}')" "$dnsName" "$name"
144 sort -n -r | _head_n
1 | cut
-f2,3 |
grep '^.*'); then
145 _err
"_dns_gcloud_find_zone: Can't find a matching managed zone! Perhaps wrong project or gcloud credentials?"
149 dnsName
=$
(echo "$match" | cut
-f2)
150 _debug dnsName
"$dnsName"
151 managedZone
=$
(echo "$match" | cut
-f1)
152 _debug managedZone
"$managedZone"
155 _dns_gcloud_get_rrdatas
() {
156 if ! rrdatas
=$
(gcloud dns record-sets list \
157 --zone="$managedZone" \
158 --name="$fulldomain." \
160 --format="value(ttl,rrdatas)"); then
161 _err
"_dns_gcloud_get_rrdatas: Failed to list record-sets"
165 ttl
=$
(echo "$rrdatas" | cut
-f1)
166 # starting with version 353.0.0 gcloud seems to
167 # separate records with a semicolon instead of commas
168 # see also https://cloud.google.com/sdk/docs/release-notes#35300_2021-08-17
169 rrdatas
=$
(echo "$rrdatas" | cut
-f2 |
sed 's/"[,;]"/"\n"/g')