You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

289 lines
8.3 KiB

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