]> git.proxmox.com Git - mirror_acme.sh.git/blob - dnsapi/dns_huaweicloud.sh
Replace some functions.
[mirror_acme.sh.git] / dnsapi / dns_huaweicloud.sh
1 #!/usr/bin/env sh
2
3 # HUAWEICLOUD_Username
4 # HUAWEICLOUD_Password
5 # HUAWEICLOUD_DomainName
6
7 iam_api="https://iam.myhuaweicloud.com"
8 dns_api="https://dns.ap-southeast-1.myhuaweicloud.com" # Should work
9
10 ######## Public functions #####################
11
12 # Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
13 # Used to add txt record
14 #
15 # Ref: https://support.huaweicloud.com/intl/zh-cn/api-dns/zh-cn_topic_0132421999.html
16 #
17 # About "DomainName" parameters see: https://support.huaweicloud.com/api-iam/iam_01_0006.html
18 #
19
20 dns_huaweicloud_add() {
21 fulldomain=$1
22 txtvalue=$2
23
24 HUAWEICLOUD_Username="${HUAWEICLOUD_Username:-$(_readaccountconf_mutable HUAWEICLOUD_Username)}"
25 HUAWEICLOUD_Password="${HUAWEICLOUD_Password:-$(_readaccountconf_mutable HUAWEICLOUD_Password)}"
26 HUAWEICLOUD_DomainName="${HUAWEICLOUD_DomainName:-$(_readaccountconf_mutable HUAWEICLOUD_DomainName)}"
27
28 # Check information
29 if [ -z "${HUAWEICLOUD_Username}" ] || [ -z "${HUAWEICLOUD_Password}" ] || [ -z "${HUAWEICLOUD_DomainName}" ]; then
30 _err "Not enough information provided to dns_huaweicloud!"
31 return 1
32 fi
33
34 unset token # Clear token
35 token="$(_get_token "${HUAWEICLOUD_Username}" "${HUAWEICLOUD_Password}" "${HUAWEICLOUD_DomainName}")"
36 if [ -z "${token}" ]; then # Check token
37 _err "dns_api(dns_huaweicloud): Error getting token."
38 return 1
39 fi
40 _secure_debug "Access token is:" "${token}"
41
42 unset zoneid
43 zoneid="$(_get_zoneid "${token}" "${fulldomain}")"
44 if [ -z "${zoneid}" ]; then
45 _err "dns_api(dns_huaweicloud): Error getting zone id."
46 return 1
47 fi
48 _debug "Zone ID is:" "${zoneid}"
49
50 _debug "Adding Record"
51 _add_record "${token}" "${fulldomain}" "${txtvalue}"
52 ret="$?"
53 if [ "${ret}" != "0" ]; then
54 _err "dns_api(dns_huaweicloud): Error adding record."
55 return 1
56 fi
57
58 # Do saving work if all succeeded
59 _saveaccountconf_mutable HUAWEICLOUD_Username "${HUAWEICLOUD_Username}"
60 _saveaccountconf_mutable HUAWEICLOUD_Password "${HUAWEICLOUD_Password}"
61 _saveaccountconf_mutable HUAWEICLOUD_DomainName "${HUAWEICLOUD_DomainName}"
62 return 0
63 }
64
65 # Usage: fulldomain txtvalue
66 # Used to remove the txt record after validation
67 #
68 # Ref: https://support.huaweicloud.com/intl/zh-cn/api-dns/dns_api_64005.html
69 #
70
71 dns_huaweicloud_rm() {
72 fulldomain=$1
73 txtvalue=$2
74
75 HUAWEICLOUD_Username="${HUAWEICLOUD_Username:-$(_readaccountconf_mutable HUAWEICLOUD_Username)}"
76 HUAWEICLOUD_Password="${HUAWEICLOUD_Password:-$(_readaccountconf_mutable HUAWEICLOUD_Password)}"
77 HUAWEICLOUD_DomainName="${HUAWEICLOUD_DomainName:-$(_readaccountconf_mutable HUAWEICLOUD_DomainName)}"
78
79 # Check information
80 if [ -z "${HUAWEICLOUD_Username}" ] || [ -z "${HUAWEICLOUD_Password}" ] || [ -z "${HUAWEICLOUD_DomainName}" ]; then
81 _err "Not enough information provided to dns_huaweicloud!"
82 return 1
83 fi
84
85 unset token # Clear token
86 token="$(_get_token "${HUAWEICLOUD_Username}" "${HUAWEICLOUD_Password}" "${HUAWEICLOUD_DomainName}")"
87 if [ -z "${token}" ]; then # Check token
88 _err "dns_api(dns_huaweicloud): Error getting token."
89 return 1
90 fi
91 _secure_debug "Access token is:" "${token}"
92
93 unset zoneid
94 zoneid="$(_get_zoneid "${token}" "${fulldomain}")"
95 if [ -z "${zoneid}" ]; then
96 _err "dns_api(dns_huaweicloud): Error getting zone id."
97 return 1
98 fi
99 _debug "Zone ID is:" "${zoneid}"
100
101 record_id="$(_get_recordset_id "${token}" "${fulldomain}" "${zoneid}")"
102 _recursive_rm_record "${token}" "${fulldomain}" "${zoneid}" "${record_id}"
103 ret="$?"
104 if [ "${ret}" != "0" ]; then
105 _err "dns_api(dns_huaweicloud): Error removing record."
106 return 1
107 fi
108
109 return 0
110 }
111
112 ################### Private functions below ##################################
113
114 # _recursive_rm_record
115 # remove all records from the record set
116 #
117 # _token=$1
118 # _domain=$2
119 # _zoneid=$3
120 # _record_id=$4
121 #
122 # Returns 0 on success
123 _recursive_rm_record() {
124 _token=$1
125 _domain=$2
126 _zoneid=$3
127 _record_id=$4
128
129 # Most likely to have problems will huaweicloud side if more than 50 attempts but still cannot fully remove the record set
130 # Maybe can be removed manually in the dashboard
131 _retry_cnt=50
132
133 # Remove all records
134 # Therotically HuaweiCloud does not allow more than one record set
135 # But remove them recurringly to increase robusty
136
137 while [ "${_record_id}" != "0" ] && [ "${_retry_cnt}" != "0" ]; do
138 _debug "Removing Record"
139 _retry_cnt=$((_retry_cnt - 1))
140 _rm_record "${_token}" "${_zoneid}" "${_record_id}"
141 _record_id="$(_get_recordset_id "${_token}" "${_domain}" "${_zoneid}")"
142 _debug2 "Checking record exists: record_id=${_record_id}"
143 done
144
145 # Check if retry count is reached
146 if [ "${_retry_cnt}" = "0" ]; then
147 _debug "Failed to remove record after 50 attempts, please try removing it manually in the dashboard"
148 return 1
149 fi
150
151 return 0
152 }
153
154 # _get_zoneid
155 #
156 # _token=$1
157 # _domain_string=$2
158 #
159 # printf "%s" "${_zoneid}"
160 _get_zoneid() {
161 _token=$1
162 _domain_string=$2
163 export _H1="X-Auth-Token: ${_token}"
164
165 i=1
166 while true; do
167 h=$(printf "%s" "${_domain_string}" | cut -d . -f "$i"-100)
168 if [ -z "$h" ]; then
169 #not valid
170 return 1
171 fi
172 _debug "$h"
173 response=$(_get "${dns_api}/v2/zones?name=${h}")
174 _debug2 "$response"
175 if _contains "${response}" '"id"'; then
176 zoneidlist=$(echo "${response}" | _egrep_o "\"id\": *\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | tr -d " ")
177 zonenamelist=$(echo "${response}" | _egrep_o "\"name\": *\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | tr -d " ")
178 _debug2 "Returned Zone ID(s):" "${zoneidlist}"
179 _debug2 "Returned Zone Name(s):" "${zonenamelist}"
180 zoneidnum=0
181 zoneidcount=$(echo "${zoneidlist}" | grep -c '^')
182 _debug "Returned Zone ID(s) Count:" "${zoneidcount}"
183 while [ "${zoneidnum}" -lt "${zoneidcount}" ]; do
184 zoneidnum=$(_math "$zoneidnum" + 1)
185 _zoneid=$(echo "${zoneidlist}" | sed -n "${zoneidnum}p")
186 zonename=$(echo "${zonenamelist}" | sed -n "${zoneidnum}p")
187 _debug "Check Zone Name" "${zonename}"
188 if [ "${zonename}" = "${h}." ]; then
189 _debug "Get Zone ID Success."
190 _debug "ZoneID:" "${_zoneid}"
191 printf "%s" "${_zoneid}"
192 return 0
193 fi
194 done
195 fi
196 i=$(_math "$i" + 1)
197 done
198 return 1
199 }
200
201 _get_recordset_id() {
202 _token=$1
203 _domain=$2
204 _zoneid=$3
205 export _H1="X-Auth-Token: ${_token}"
206
207 response=$(_get "${dns_api}/v2/zones/${_zoneid}/recordsets?name=${_domain}")
208 if _contains "${response}" '"id"'; then
209 _id="$(echo "${response}" | _egrep_o "\"id\": *\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | tr -d " ")"
210 printf "%s" "${_id}"
211 return 0
212 fi
213 printf "%s" "0"
214 return 1
215 }
216
217 _add_record() {
218 _token=$1
219 _domain=$2
220 _txtvalue=$3
221
222 # Get Existing Records
223 export _H1="X-Auth-Token: ${_token}"
224 response=$(_get "${dns_api}/v2/zones/${zoneid}/recordsets?name=${_domain}")
225
226 _debug2 "${response}"
227 _exist_record=$(echo "${response}" | _egrep_o '"records":[^]]*' | sed 's/\"records\"\:\[//g')
228 _debug "${_exist_record}"
229
230 # Check if record exist
231 # Generate body data
232 if [ -z "${_exist_record}" ]; then
233 _post_body="{
234 \"name\": \"${_domain}.\",
235 \"description\": \"ACME Challenge\",
236 \"type\": \"TXT\",
237 \"ttl\": 1,
238 \"records\": [
239 \"\\\"${_txtvalue}\\\"\"
240 ]
241 }"
242 else
243 _post_body="{
244 \"name\": \"${_domain}.\",
245 \"description\": \"ACME Challenge\",
246 \"type\": \"TXT\",
247 \"ttl\": 1,
248 \"records\": [
249 ${_exist_record},\"\\\"${_txtvalue}\\\"\"
250 ]
251 }"
252 fi
253
254 _record_id="$(_get_recordset_id "${_token}" "${_domain}" "${zoneid}")"
255 _debug "Record Set ID is:" "${_record_id}"
256
257 # Add brand new records with all old and new records
258 export _H2="Content-Type: application/json"
259 export _H1="X-Auth-Token: ${_token}"
260
261 _debug2 "${_post_body}"
262 if [ -z "${_exist_record}" ]; then
263 _post "${_post_body}" "${dns_api}/v2/zones/${zoneid}/recordsets" >/dev/null
264 else
265 _post "${_post_body}" "${dns_api}/v2/zones/${zoneid}/recordsets/${_record_id}" false "PUT" >/dev/null
266 fi
267 _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")"
268 if [ "$_code" != "202" ]; then
269 _err "dns_huaweicloud: http code ${_code}"
270 return 1
271 fi
272 return 0
273 }
274
275 # _rm_record $token $zoneid $recordid
276 # assume ${dns_api} exist
277 # no output
278 # return 0
279 _rm_record() {
280 _token=$1
281 _zone_id=$2
282 _record_id=$3
283
284 export _H2="Content-Type: application/json"
285 export _H1="X-Auth-Token: ${_token}"
286
287 _post "" "${dns_api}/v2/zones/${_zone_id}/recordsets/${_record_id}" false "DELETE" >/dev/null
288 return $?
289 }
290
291 _get_token() {
292 _username=$1
293 _password=$2
294 _domain_name=$3
295
296 _debug "Getting Token"
297 body="{
298 \"auth\": {
299 \"identity\": {
300 \"methods\": [
301 \"password\"
302 ],
303 \"password\": {
304 \"user\": {
305 \"name\": \"${_username}\",
306 \"password\": \"${_password}\",
307 \"domain\": {
308 \"name\": \"${_domain_name}\"
309 }
310 }
311 }
312 },
313 \"scope\": {
314 \"project\": {
315 \"name\": \"ap-southeast-1\"
316 }
317 }
318 }
319 }"
320 export _H1="Content-Type: application/json;charset=utf8"
321 _post "${body}" "${iam_api}/v3/auth/tokens" >/dev/null
322 _code=$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")
323 _token=$(grep "^X-Subject-Token" "$HTTP_HEADER" | cut -d " " -f 2-)
324 _secure_debug "${_code}"
325 printf "%s" "${_token}"
326 return 0
327 }