]> git.proxmox.com Git - mirror_acme.sh.git/blob - dnsapi/dns_gcloud.sh
Merge pull request #4531 from NCDGHA/bugfix/issue_4530_fix_http_status_503
[mirror_acme.sh.git] / dnsapi / dns_gcloud.sh
1 #!/usr/bin/env sh
2
3 # Author: Janos Lenart <janos@lenart.io>
4
5 ######## Public functions #####################
6
7 # Usage: dns_gcloud_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
8 dns_gcloud_add() {
9 fulldomain=$1
10 txtvalue=$2
11 _info "Using gcloud"
12 _debug fulldomain "$fulldomain"
13 _debug txtvalue "$txtvalue"
14
15 _dns_gcloud_find_zone || return $?
16
17 # Add an extra RR
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 $?
23
24 _info "$fulldomain record added"
25 }
26
27 # Usage: dns_gcloud_rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
28 # Remove the txt record after validation.
29 dns_gcloud_rm() {
30 fulldomain=$1
31 txtvalue=$2
32 _info "Using gcloud"
33 _debug fulldomain "$fulldomain"
34 _debug txtvalue "$txtvalue"
35
36 _dns_gcloud_find_zone || return $?
37
38 # Remove one RR
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 $?
44
45 _info "$fulldomain record added"
46 }
47
48 #################### Private functions below ##################################
49
50 _dns_gcloud_start_tr() {
51 if ! trd=$(mktemp -d); then
52 _err "_dns_gcloud_start_tr: failed to create temporary directory"
53 return 1
54 fi
55 tr="$trd/tr.yaml"
56 _debug tr "$tr"
57
58 if ! gcloud dns record-sets transaction start \
59 --transaction-file="$tr" \
60 --zone="$managedZone"; then
61 rm -r "$trd"
62 _err "_dns_gcloud_start_tr: failed to execute transaction"
63 return 1
64 fi
65 }
66
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")"
72 rm -r "$trd"
73 _err "_dns_gcloud_execute_tr: failed to execute transaction"
74 return 1
75 fi
76 rm -r "$trd"
77
78 for i in $(seq 1 120); do
79 if gcloud dns record-sets changes list \
80 --zone="$managedZone" \
81 --filter='status != done' |
82 grep -q '^.*'; then
83 _info "_dns_gcloud_execute_tr: waiting for transaction to be comitted ($i/120)..."
84 sleep 5
85 else
86 return 0
87 fi
88 done
89
90 _err "_dns_gcloud_execute_tr: transaction is still pending after 10 minutes"
91 rm -r "$trd"
92 return 1
93 }
94
95 _dns_gcloud_remove_rrs() {
96 if ! xargs -r gcloud dns record-sets transaction remove \
97 --name="$fulldomain." \
98 --ttl="$ttl" \
99 --type=TXT \
100 --zone="$managedZone" \
101 --transaction-file="$tr" --; then
102 _debug tr "$(cat "$tr")"
103 rm -r "$trd"
104 _err "_dns_gcloud_remove_rrs: failed to remove RRs"
105 return 1
106 fi
107 }
108
109 _dns_gcloud_add_rrs() {
110 ttl=60
111 if ! xargs -r gcloud dns record-sets transaction add \
112 --name="$fulldomain." \
113 --ttl="$ttl" \
114 --type=TXT \
115 --zone="$managedZone" \
116 --transaction-file="$tr" --; then
117 _debug tr "$(cat "$tr")"
118 rm -r "$trd"
119 _err "_dns_gcloud_add_rrs: failed to add RRs"
120 return 1
121 fi
122 }
123
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.
128 part="$fulldomain"
129 filter="dnsName=( "
130 while [ "$part" != "" ]; do
131 filter="$filter$part. "
132 part="$(echo "$part" | sed 's/[^.]*\.*//')"
133 done
134 filter="$filter) AND visibility=public"
135 _debug filter "$filter"
136
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)" \
140 --filter="$filter" |
141 while read -r dnsName name; do
142 printf "%s\t%s\t%s\n" "$(echo "$name" | awk -F"." '{print NF-1}')" "$dnsName" "$name"
143 done |
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?"
146 return 1
147 fi
148
149 dnsName=$(echo "$match" | cut -f2)
150 _debug dnsName "$dnsName"
151 managedZone=$(echo "$match" | cut -f1)
152 _debug managedZone "$managedZone"
153 }
154
155 _dns_gcloud_get_rrdatas() {
156 if ! rrdatas=$(gcloud dns record-sets list \
157 --zone="$managedZone" \
158 --name="$fulldomain." \
159 --type=TXT \
160 --format="value(ttl,rrdatas)"); then
161 _err "_dns_gcloud_get_rrdatas: Failed to list record-sets"
162 rm -r "$trd"
163 return 1
164 fi
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')
170 }