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