]>
Commit | Line | Data |
---|---|---|
0a3ac1f5 JL |
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 $? | |
16775800 | 21 | printf "%s\n%s\n" "$rrdatas" "\"$txtvalue\"" | grep -v '^$' | _dns_gcloud_add_rrs || return $? |
0a3ac1f5 JL |
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 $? | |
16775800 | 42 | echo "$rrdatas" | grep -F -v "\"$txtvalue\"" | _dns_gcloud_add_rrs || return $? |
0a3ac1f5 JL |
43 | _dns_gcloud_execute_tr || return $? |
44 | ||
45 | _info "$fulldomain record added" | |
46 | } | |
47 | ||
48 | #################### Private functions below ################################## | |
49 | ||
50 | _dns_gcloud_start_tr() { | |
16775800 | 51 | if ! trd=$(mktemp -d); then |
0a3ac1f5 JL |
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 \ | |
16775800 JL |
59 | --transaction-file="$tr" \ |
60 | --zone="$managedZone"; then | |
0a3ac1f5 JL |
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 \ | |
16775800 JL |
69 | --transaction-file="$tr" \ |
70 | --zone="$managedZone"; then | |
71 | _debug tr "$(cat "$tr")" | |
0a3ac1f5 JL |
72 | rm -r "$trd" |
73 | _err "_dns_gcloud_execute_tr: failed to execute transaction" | |
74 | return 1 | |
75 | fi | |
76 | rm -r "$trd" | |
77 | ||
16775800 | 78 | for i in $(seq 1 120); do |
0a3ac1f5 | 79 | if gcloud dns record-sets changes list \ |
441f8f3c | 80 | --zone="$managedZone" \ |
19c43451 | 81 | --filter='status != done' | |
82 | grep -q '^.*'; then | |
16775800 JL |
83 | _info "_dns_gcloud_execute_tr: waiting for transaction to be comitted ($i/120)..." |
84 | sleep 5 | |
0a3ac1f5 JL |
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() { | |
145b1f4f | 96 | if ! xargs -r gcloud dns record-sets transaction remove \ |
16775800 JL |
97 | --name="$fulldomain." \ |
98 | --ttl="$ttl" \ | |
99 | --type=TXT \ | |
100 | --zone="$managedZone" \ | |
101 | --transaction-file="$tr"; then | |
102 | _debug tr "$(cat "$tr")" | |
0a3ac1f5 JL |
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 | |
145b1f4f | 111 | if ! xargs -r gcloud dns record-sets transaction add \ |
16775800 JL |
112 | --name="$fulldomain." \ |
113 | --ttl="$ttl" \ | |
114 | --type=TXT \ | |
115 | --zone="$managedZone" \ | |
116 | --transaction-file="$tr"; then | |
117 | _debug tr "$(cat "$tr")" | |
0a3ac1f5 JL |
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. " | |
16775800 | 132 | part="$(echo "$part" | sed 's/[^.]*\.*//')" |
0a3ac1f5 | 133 | done |
70fdb104 | 134 | filter="$filter) AND visibility=public" |
0a3ac1f5 JL |
135 | _debug filter "$filter" |
136 | ||
98d27c4a | 137 | # List domains and find the zone with the deepest sub-domain (in case of some levels of delegation) |
0a3ac1f5 | 138 | if ! match=$(gcloud dns managed-zones list \ |
16775800 | 139 | --format="value(name, dnsName)" \ |
19c43451 | 140 | --filter="$filter" | |
141 | while read -r dnsName name; do | |
2d72b25c | 142 | printf "%s\t%s\t%s\n" "$(echo "$name" | awk -F"." '{print NF-1}')" "$dnsName" "$name" |
19c43451 | 143 | done | |
144 | sort -n -r | _head_n 1 | cut -f2,3 | grep '^.*'); then | |
0a3ac1f5 JL |
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 \ | |
16775800 JL |
157 | --zone="$managedZone" \ |
158 | --name="$fulldomain." \ | |
159 | --type=TXT \ | |
160 | --format="value(ttl,rrdatas)"); then | |
0a3ac1f5 JL |
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) | |
401fd37e RS |
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') | |
0a3ac1f5 | 170 | } |