]>
Commit | Line | Data |
---|---|---|
b8e5c0d8 EM |
1 | #!/usr/bin/env sh |
2 | ||
3 | # HUAWEICLOUD_Username | |
4 | # HUAWEICLOUD_Password | |
789ebb89 | 5 | # HUAWEICLOUD_DomainName |
6 | ||
b8e5c0d8 | 7 | iam_api="https://iam.myhuaweicloud.com" |
86639dbc | 8 | dns_api="https://dns.ap-southeast-1.myhuaweicloud.com" # Should work |
b8e5c0d8 EM |
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 | # | |
789ebb89 | 17 | # About "DomainName" parameters see: https://support.huaweicloud.com/api-iam/iam_01_0006.html |
18 | # | |
b8e5c0d8 EM |
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)}" | |
789ebb89 | 26 | HUAWEICLOUD_DomainName="${HUAWEICLOUD_DomainName:-$(_readaccountconf_mutable HUAWEICLOUD_Username)}" |
b8e5c0d8 | 27 | |
c4ddddd4 | 28 | # Check information |
789ebb89 | 29 | if [ -z "${HUAWEICLOUD_Username}" ] || [ -z "${HUAWEICLOUD_Password}" ] || [ -z "${HUAWEICLOUD_DomainName}" ]; then |
c4ddddd4 | 30 | _err "Not enough information provided to dns_huaweicloud!" |
f6f6550b EM |
31 | return 1 |
32 | fi | |
33 | ||
86639dbc | 34 | unset token # Clear token |
789ebb89 | 35 | token="$(_get_token "${HUAWEICLOUD_Username}" "${HUAWEICLOUD_Password}" "${HUAWEICLOUD_DomainName}")" |
86639dbc EM |
36 | if [ -z "${token}" ]; then # Check token |
37 | _err "dns_api(dns_huaweicloud): Error getting token." | |
38 | return 1 | |
39 | fi | |
9d2ee212 | 40 | _secure_debug "Access token is:" "${token}" |
86639dbc EM |
41 | |
42 | unset zoneid | |
b8e5c0d8 | 43 | zoneid="$(_get_zoneid "${token}" "${fulldomain}")" |
86639dbc EM |
44 | if [ -z "${zoneid}" ]; then |
45 | _err "dns_api(dns_huaweicloud): Error getting zone id." | |
46 | return 1 | |
47 | fi | |
9d2ee212 | 48 | _debug "Zone ID is:" "${zoneid}" |
b8e5c0d8 EM |
49 | |
50 | _debug "Adding Record" | |
51 | _add_record "${token}" "${fulldomain}" "${txtvalue}" | |
52 | ret="$?" | |
53 | if [ "${ret}" != "0" ]; then | |
86639dbc | 54 | _err "dns_api(dns_huaweicloud): Error adding record." |
b8e5c0d8 EM |
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}" | |
789ebb89 | 61 | _saveaccountconf_mutable HUAWEICLOUD_DomainName "${HUAWEICLOUD_DomainName}" |
b8e5c0d8 EM |
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)}" | |
789ebb89 | 77 | HUAWEICLOUD_DomainName="${HUAWEICLOUD_DomainName:-$(_readaccountconf_mutable HUAWEICLOUD_Username)}" |
b8e5c0d8 | 78 | |
c4ddddd4 | 79 | # Check information |
789ebb89 | 80 | if [ -z "${HUAWEICLOUD_Username}" ] || [ -z "${HUAWEICLOUD_Password}" ] || [ -z "${HUAWEICLOUD_DomainName}" ]; then |
c4ddddd4 | 81 | _err "Not enough information provided to dns_huaweicloud!" |
e01fb503 EM |
82 | return 1 |
83 | fi | |
84 | ||
86639dbc | 85 | unset token # Clear token |
789ebb89 | 86 | token="$(_get_token "${HUAWEICLOUD_Username}" "${HUAWEICLOUD_Password}" "${HUAWEICLOUD_DomainName}")" |
86639dbc EM |
87 | if [ -z "${token}" ]; then # Check token |
88 | _err "dns_api(dns_huaweicloud): Error getting token." | |
89 | return 1 | |
90 | fi | |
9d2ee212 | 91 | _secure_debug "Access token is:" "${token}" |
86639dbc EM |
92 | |
93 | unset zoneid | |
b8e5c0d8 | 94 | zoneid="$(_get_zoneid "${token}" "${fulldomain}")" |
86639dbc EM |
95 | if [ -z "${zoneid}" ]; then |
96 | _err "dns_api(dns_huaweicloud): Error getting zone id." | |
97 | return 1 | |
98 | fi | |
9d2ee212 | 99 | _debug "Zone ID is:" "${zoneid}" |
7db592d2 | 100 | |
0cce2d60 | 101 | record_id="$(_get_recordset_id "${token}" "${fulldomain}" "${zoneid}")" |
acbd8bce EM |
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 | |
4dba84d0 | 108 | |
acbd8bce EM |
109 | return 0 |
110 | } | |
111 | ||
112 | ################### Private functions below ################################## | |
113 | ||
acbd8bce EM |
114 | # _recursive_rm_record |
115 | # remove all records from the record set | |
4dba84d0 | 116 | # |
acbd8bce EM |
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 | ||
7db592d2 | 133 | # Remove all records |
c4ddddd4 EM |
134 | # Therotically HuaweiCloud does not allow more than one record set |
135 | # But remove them recurringly to increase robusty | |
acbd8bce | 136 | |
0cce2d60 | 137 | while [ "${_record_id}" != "0" ] && [ "${_retry_cnt}" != "0" ]; do |
28ce1c12 | 138 | _debug "Removing Record" |
0cce2d60 | 139 | _retry_cnt=$((_retry_cnt - 1)) |
acbd8bce EM |
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}" | |
b8e5c0d8 | 143 | done |
acbd8bce EM |
144 | |
145 | # Check if retry count is reached | |
0cce2d60 | 146 | if [ "${_retry_cnt}" = "0" ]; then |
acbd8bce EM |
147 | _debug "Failed to remove record after 50 attempts, please try removing it manually in the dashboard" |
148 | return 1 | |
149 | fi | |
150 | ||
b8e5c0d8 EM |
151 | return 0 |
152 | } | |
153 | ||
b8e5c0d8 EM |
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 | |
0cce2d60 | 167 | h=$(printf "%s" "${_domain_string}" | cut -d . -f "$i"-100) |
b8e5c0d8 EM |
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}") | |
9d2ee212 | 174 | _debug2 "$response" |
e49ece87 YM |
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 " ") | |
9d2ee212 YM |
178 | _debug2 "Return Zone ID(s):" "${zoneidlist}" |
179 | _debug2 "Return Zone Name(s):" "${zonenamelist}" | |
e49ece87 | 180 | zoneidnum=0 |
9088c874 YM |
181 | zoneidcount=$(echo "${zoneidlist}" | grep -c '^') |
182 | _debug "Retund Zone ID(s) Count:" "${zoneidcount}" | |
183 | while [ "${zoneidnum}" -lt "${zoneidcount}" ]; do | |
e49ece87 | 184 | zoneidnum=$(_math "$zoneidnum" + 1) |
9088c874 YM |
185 | _zoneid=$(echo "${zoneidlist}" | sed -n "${zoneidnum}p") |
186 | zonename=$(echo "${zonenamelist}" | sed -n "${zoneidnum}p") | |
9d2ee212 | 187 | _debug "Check Zone Name" "${zonename}" |
e49ece87 YM |
188 | if [ "${zonename}" = "${h}." ]; then |
189 | _debug "Get Zone ID Success." | |
9088c874 | 190 | _debug "ZoneID:" "${_zoneid}" |
e49ece87 YM |
191 | printf "%s" "${_zoneid}" |
192 | return 0 | |
193 | fi | |
194 | done | |
b8e5c0d8 | 195 | fi |
b8e5c0d8 EM |
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}") | |
e49ece87 | 208 | if _contains "${response}" '"id"'; then |
b8e5c0d8 EM |
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 | |
f6f6550b EM |
221 | |
222 | # Get Existing Records | |
223 | export _H1="X-Auth-Token: ${_token}" | |
5d0657c4 EM |
224 | response=$(_get "${dns_api}/v2/zones/${zoneid}/recordsets?name=${_domain}") |
225 | ||
c4ddddd4 | 226 | _debug2 "${response}" |
fd511966 | 227 | _exist_record=$(echo "${response}" | _egrep_o '"records":[^]]*' | sed 's/\"records\"\:\[//g') |
f6f6550b EM |
228 | _debug "${_exist_record}" |
229 | ||
230 | # Check if record exist | |
231 | # Generate body data | |
f6f6550b | 232 | if [ -z "${_exist_record}" ]; then |
5d0657c4 | 233 | _post_body="{ |
f6f6550b EM |
234 | \"name\": \"${_domain}.\", |
235 | \"description\": \"ACME Challenge\", | |
236 | \"type\": \"TXT\", | |
237 | \"ttl\": 1, | |
238 | \"records\": [ | |
239 | \"\\\"${_txtvalue}\\\"\" | |
240 | ] | |
241 | }" | |
c4ddddd4 EM |
242 | else |
243 | _post_body="{ | |
244 | \"name\": \"${_domain}.\", | |
245 | \"description\": \"ACME Challenge\", | |
246 | \"type\": \"TXT\", | |
247 | \"ttl\": 1, | |
248 | \"records\": [ | |
249 | ${_exist_record}, | |
250 | \"\\\"${_txtvalue}\\\"\" | |
251 | ] | |
252 | }" | |
f6f6550b | 253 | fi |
5d0657c4 EM |
254 | |
255 | _record_id="$(_get_recordset_id "${_token}" "${_domain}" "${zoneid}")" | |
9d2ee212 | 256 | _debug "Record Set ID is:" "${_record_id}" |
5d0657c4 EM |
257 | |
258 | # Remove all records | |
acbd8bce EM |
259 | _recursive_rm_record "${token}" "${_domain}" "${_zoneid}" "${_record_id}" |
260 | ret="$?" | |
261 | if [ "${ret}" != "0" ]; then | |
262 | return 1 | |
263 | fi | |
5d0657c4 EM |
264 | |
265 | # Add brand new records with all old and new records | |
b8e5c0d8 EM |
266 | export _H2="Content-Type: application/json" |
267 | export _H1="X-Auth-Token: ${_token}" | |
268 | ||
c4ddddd4 | 269 | _debug2 "${_post_body}" |
5d0657c4 | 270 | _post "${_post_body}" "${dns_api}/v2/zones/${zoneid}/recordsets" >/dev/null |
b8e5c0d8 EM |
271 | _code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")" |
272 | if [ "$_code" != "202" ]; then | |
273 | _err "dns_huaweicloud: http code ${_code}" | |
274 | return 1 | |
275 | fi | |
276 | return 0 | |
277 | } | |
278 | ||
5d0657c4 EM |
279 | # _rm_record $token $zoneid $recordid |
280 | # assume ${dns_api} exist | |
281 | # no output | |
282 | # return 0 | |
b8e5c0d8 EM |
283 | _rm_record() { |
284 | _token=$1 | |
285 | _zone_id=$2 | |
286 | _record_id=$3 | |
287 | ||
288 | export _H2="Content-Type: application/json" | |
289 | export _H1="X-Auth-Token: ${_token}" | |
290 | ||
5d0657c4 EM |
291 | _post "" "${dns_api}/v2/zones/${_zone_id}/recordsets/${_record_id}" false "DELETE" >/dev/null |
292 | return $? | |
b8e5c0d8 EM |
293 | } |
294 | ||
295 | _get_token() { | |
296 | _username=$1 | |
297 | _password=$2 | |
789ebb89 | 298 | _domain_name=$3 |
b8e5c0d8 EM |
299 | |
300 | _debug "Getting Token" | |
301 | body="{ | |
302 | \"auth\": { | |
303 | \"identity\": { | |
304 | \"methods\": [ | |
305 | \"password\" | |
306 | ], | |
307 | \"password\": { | |
308 | \"user\": { | |
309 | \"name\": \"${_username}\", | |
310 | \"password\": \"${_password}\", | |
311 | \"domain\": { | |
789ebb89 | 312 | \"name\": \"${_domain_name}\" |
b8e5c0d8 EM |
313 | } |
314 | } | |
315 | } | |
316 | }, | |
317 | \"scope\": { | |
318 | \"project\": { | |
789ebb89 | 319 | \"name\": \"ap-southeast-1\" |
b8e5c0d8 EM |
320 | } |
321 | } | |
322 | } | |
323 | }" | |
324 | export _H1="Content-Type: application/json;charset=utf8" | |
325 | _post "${body}" "${iam_api}/v3/auth/tokens" >/dev/null | |
326 | _code=$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n") | |
327 | _token=$(grep "^X-Subject-Token" "$HTTP_HEADER" | cut -d " " -f 2-) | |
9d2ee212 | 328 | _secure_debug "${_code}" |
b8e5c0d8 EM |
329 | printf "%s" "${_token}" |
330 | return 0 | |
331 | } |