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.

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