refactor: reduce nesting, update err codes
- detect curl vs CF API errors separately - error 25 changed to error 3 (curl/network) - error 25 reservedfor CF API errors - add CF error messages to all err 25s - change error 98 (updates) to error 26 - remove error code for exit with warning - add CF error messages on update failures - drastically reduce if/else nesting
This commit is contained in:
parent
a7064805c3
commit
f4f3c89e5e
115
cfddns.sh
115
cfddns.sh
@ -47,6 +47,9 @@ badParam() {
|
|||||||
|
|
||||||
exitError() {
|
exitError() {
|
||||||
case "$1" in
|
case "$1" in
|
||||||
|
3)
|
||||||
|
errMsg="Unable to connect to Cloudflare servers. This is probably a temporary networking issue. Please try again later."
|
||||||
|
;;
|
||||||
10)
|
10)
|
||||||
errMsg="Unable to auto-detect IP address. Try again later or supply the IP address to be used."
|
errMsg="Unable to auto-detect IP address. Try again later or supply the IP address to be used."
|
||||||
;;
|
;;
|
||||||
@ -60,10 +63,10 @@ exitError() {
|
|||||||
errMsg="Cloudflare zone id (cfZoneId) is either null or undefined. Please check your Cloudflare credentials file."
|
errMsg="Cloudflare zone id (cfZoneId) is either null or undefined. Please check your Cloudflare credentials file."
|
||||||
;;
|
;;
|
||||||
25)
|
25)
|
||||||
errMsg="Unable to query Cloudflare account. Please re-check your credentials and try again later."
|
errMsg="Cloudflare API error. Please check the logs for 'CF-ERR-NO' and 'CF-ERR-MESSAGE' entries for details."
|
||||||
;;
|
;;
|
||||||
98)
|
26)
|
||||||
errMsg="One or more domain updates failed. Please review this log file for details."
|
errMsg="${failedDomainCount} domain update(s) failed. Please review this log file for details."
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
printf "%s[%s] ERROR: An unspecified error occurred. Exiting.%s\n" "$err" "$(stamp)" "$norm" >>"$logFile"
|
printf "%s[%s] ERROR: An unspecified error occurred. Exiting.%s\n" "$err" "$(stamp)" "$norm" >>"$logFile"
|
||||||
@ -367,6 +370,7 @@ case "$accountFile" in
|
|||||||
. "./$accountFile"
|
. "./$accountFile"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
# TODO: cfEmail is *not* required when using bearer tokens
|
||||||
if [ -z "$cfEmail" ]; then
|
if [ -z "$cfEmail" ]; then
|
||||||
printf "%sERROR%s\n" "$err" "$norm" >>"$logFile"
|
printf "%sERROR%s\n" "$err" "$norm" >>"$logFile"
|
||||||
exitError 20
|
exitError 20
|
||||||
@ -379,57 +383,92 @@ elif [ -z "$cfZoneId" ]; then
|
|||||||
fi
|
fi
|
||||||
printf "DONE%s\n" "$norm" >>"$logFile"
|
printf "DONE%s\n" "$norm" >>"$logFile"
|
||||||
|
|
||||||
### check if records to be updated exist and if they need updating, update as required
|
### connect to Cloudflare and do what needs to be done!
|
||||||
dnsRecordsToUpdate="$dnsRecords$dnsSeparator"
|
dnsRecordsToUpdate="$dnsRecords$dnsSeparator"
|
||||||
if [ "$ip4" -eq 1 ]; then
|
if [ "$ip4" -eq 1 ]; then
|
||||||
recordType="A"
|
recordType="A"
|
||||||
elif [ "$ip6" -eq 1 ]; then
|
elif [ "$ip6" -eq 1 ]; then
|
||||||
recordType="AAAA"
|
recordType="AAAA"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# iterate hosts to update
|
||||||
while [ "$dnsRecordsToUpdate" != "${dnsRecordsToUpdate#*${dnsSeparator}}" ] && { [ -n "${dnsRecordsToUpdate%%${dnsSeparator}*}" ] || [ -n "${dnsRecordsToUpdate#*${dnsSeparator}}" ]; }; do
|
while [ "$dnsRecordsToUpdate" != "${dnsRecordsToUpdate#*${dnsSeparator}}" ] && { [ -n "${dnsRecordsToUpdate%%${dnsSeparator}*}" ] || [ -n "${dnsRecordsToUpdate#*${dnsSeparator}}" ]; }; do
|
||||||
record="${dnsRecordsToUpdate%%${dnsSeparator}*}"
|
record="${dnsRecordsToUpdate%%${dnsSeparator}*}"
|
||||||
dnsRecordsToUpdate="${dnsRecordsToUpdate#*${dnsSeparator}}"
|
dnsRecordsToUpdate="${dnsRecordsToUpdate#*${dnsSeparator}}"
|
||||||
printf "[%s] Processing %s... " "$(stamp)" "$record" >>"$logFile"
|
printf "[%s] Processing %s... " "$(stamp)" "$record" >>"$logFile"
|
||||||
# check for existing record, else exit with error (this script does NOT create new records, only updates them!)
|
|
||||||
if ! cfResult="$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/${cfZoneId}/dns_records?name=${record}&type=${recordType}" \
|
# exit if curl/network error
|
||||||
|
if ! cfLookup="$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/${cfZoneId}/dns_records?name=${record}&type=${recordType}" \
|
||||||
-H "Authorization: Bearer ${cfKey}" \
|
-H "Authorization: Bearer ${cfKey}" \
|
||||||
-H "Content-Type: application/json")"; then
|
-H "Content-Type: application/json")"; then
|
||||||
printf "%sERROR%s\n" "$err" "$norm" >>"$logFile"
|
printf "%sERROR%s\n" "$err" "$norm" >>"$logFile"
|
||||||
|
exitError 3
|
||||||
|
fi
|
||||||
|
|
||||||
|
# exit if API error
|
||||||
|
# exit here since API errors on GET request probably indicates authentication error which would affect all remaining operations
|
||||||
|
# no reason to continue processing other hosts and pile-up errors which might look like a DoS attempt
|
||||||
|
cfSuccess="$(printf "%s" "$cfLookup" | jq -r '.success')"
|
||||||
|
if [ "$cfSuccess" = "false" ]; then
|
||||||
|
printf "%sERROR%s\n" "$err" "$norm"
|
||||||
|
# get error code and message from CF API
|
||||||
|
cfErrCode="$(printf "%s" "$cfLookup" | jq -r '.errors | .[] | .code')"
|
||||||
|
cfErrMessage="$(printf "%s" "$cfLookup" | jq -r '.errors | .[] | .message')"
|
||||||
|
printf "[%s] CF-ERR-NO: %s\n" "$(stamp)" "$cfErrCode"
|
||||||
|
printf "[%s] CF-ERR-MSG: %s\n" "$(stamp)" "$cfErrMessage"
|
||||||
exitError 25
|
exitError 25
|
||||||
fi
|
fi
|
||||||
resultCount="$(printf "%s" "$cfResult" | jq '.result_info.count')"
|
|
||||||
|
resultCount="$(printf "%s" "$cfLookup" | jq '.result_info.count')"
|
||||||
|
|
||||||
|
# skip to next host if cannot find existing host record (this script *updates* only, does not create!)
|
||||||
if [ "$resultCount" = "0" ]; then
|
if [ "$resultCount" = "0" ]; then
|
||||||
|
# warn if record of host not found
|
||||||
printf "%sNOT FOUND%s\n" "$warn" "$norm" >>"$logFile"
|
printf "%sNOT FOUND%s\n" "$warn" "$norm" >>"$logFile"
|
||||||
printf "%s[%s] WARNING: Cannot find existing record to update for DNS entry: %s%s\n" "$warn" "$(stamp)" "$record" "$norm" >>"$logFile"
|
printf "%s[%s] WARNING: Cannot find existing record to update for DNS entry: %s%s\n" "$warn" "$(stamp)" "$record" "$norm" >>"$logFile"
|
||||||
invalidDomainCount=$((invalidDomainCount + 1))
|
invalidDomainCount=$((invalidDomainCount + 1))
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
objectId=$(printf "%s" "$cfLookup" | jq -r '.result | .[] | .id')
|
||||||
|
currentIpAddr=$(printf "%s" "$cfLookup" | jq -r '.result | .[] | .content')
|
||||||
|
printf "FOUND: IP = %s\n" "$currentIpAddr" >>"$logFile"
|
||||||
|
|
||||||
|
# skip to next hostname if record already up-to-date
|
||||||
|
if [ "$currentIpAddr" = "$ipAddress" ]; then
|
||||||
|
printf "%s[%s] IP address for %s is already up-to-date%s\n" "$ok" "$(stamp)" "$record" "$norm" >>"$logFile"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
# update record
|
||||||
|
printf "%s[%s] Updating IP address for %s... " "$cyan" "$(stamp)" "$record" >>"$logFile"
|
||||||
|
updateJSON="$(jq -n --arg key0 content --arg value0 "${ipAddress}" '{($key0):$value0}')"
|
||||||
|
|
||||||
|
# exit if curl/network error
|
||||||
|
if ! cfResult="$(curl -s -X PATCH "https://api.cloudflare.com/client/v4/zones/${cfZoneId}/dns_records/${objectId}" \
|
||||||
|
-H "Authorization: Bearer ${cfKey}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
--data "${updateJSON}")"; then
|
||||||
|
printf "%sERROR%s\n" "$err" "$norm" >>"$logFile"
|
||||||
|
exitError 3
|
||||||
|
fi
|
||||||
|
|
||||||
|
# note update success or failure
|
||||||
|
cfSuccess="$(printf "%s" "$cfResult" | jq '.success')"
|
||||||
|
if [ "$cfSuccess" = "true" ]; then
|
||||||
|
printf "DONE%s\n" "$norm" >>"$logFile"
|
||||||
|
printf "%s[%s] SUCCESS: IP address for %s updated%s\n" "$ok" "$(stamp)" "$record" "$norm" >>"$logFile"
|
||||||
else
|
else
|
||||||
objectId=$(printf "%s" "$cfResult" | jq -r '.result | .[] | .id')
|
printf "%sFAILED%s\n" "$err" "$norm" >>"$logFile"
|
||||||
currentIpAddr=$(printf "%s" "$cfResult" | jq -r '.result | .[] | .content')
|
# get error code and message from CF API
|
||||||
printf "FOUND: IP = %s\n" "$currentIpAddr" >>"$logFile"
|
cfErrCode="$(printf "%s" "$cfResult" | jq -r '.errors | .[] | .code')"
|
||||||
# check if record needs updating
|
cfErrMessage="$(printf "%s" "$cfResult" | jq -r '.errors | .[] | .message')"
|
||||||
if [ "$currentIpAddr" = "$ipAddress" ]; then
|
printf "[%s] CF-ERR-NO: %s\n" "$(stamp)" "$cfErrCode"
|
||||||
printf "%s[%s] IP address for %s is already up-to-date%s\n" "$ok" "$(stamp)" "$record" "$norm" >>"$logFile"
|
printf "[%s] CF-ERR-MSG: %s\n" "$(stamp)" "$cfErrMessage"
|
||||||
else
|
printf "%s[%s] ERROR: Unable to update IP address for %s%s\n" "$err" "$(stamp)" "$record" "$norm" >>"$logFile"
|
||||||
# update record
|
# do not exit with error, API error here is probably an update issue specific to this host
|
||||||
printf "%s[%s] Updating IP address for %s... " "$cyan" "$(stamp)" "$record" >>"$logFile"
|
# increment counter and note it after all processing finished
|
||||||
updateJSON="$(jq -n --arg key0 content --arg value0 "${ipAddress}" '{($key0):$value0}')"
|
failedDomainCount=$((failedDomainCount + 1))
|
||||||
if ! cfResult="$(curl -s -X PATCH "https://api.cloudflare.com/client/v4/zones/${cfZoneId}/dns_records/${objectId}" \
|
|
||||||
-H "Authorization: Bearer ${cfKey}" \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
--data "${updateJSON}")"; then
|
|
||||||
printf "%sERROR%s\n" "$err" "$norm" >>"$logFile"
|
|
||||||
exitError 25
|
|
||||||
fi
|
|
||||||
updateSuccess="$(printf "%s" "$cfResult" | jq '.success')"
|
|
||||||
if [ "$updateSuccess" = "true" ]; then
|
|
||||||
printf "DONE%s\n" "$norm" >>"$logFile"
|
|
||||||
printf "%s[%s] SUCCESS: IP address for %s updated%s\n" "$ok" "$(stamp)" "$record" "$norm" >>"$logFile"
|
|
||||||
else
|
|
||||||
printf "%sFAILED%s\n" "$err" "$norm" >>"$logFile"
|
|
||||||
printf "%s[%s] ERROR: Unable to update IP address for %s%s\n" "$err" "$(stamp)" "$record" "$norm" >>"$logFile"
|
|
||||||
failedDomainCount=$((failedDomainCount + 1))
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
@ -438,7 +477,7 @@ if [ "$invalidDomainCount" -ne 0 ]; then
|
|||||||
printf "%s[%s] -- WARNING: %s invalid domain(s) were supplied for updating --%s\n" "$warn" "$(stamp)" "$invalidDomainCount" "$norm" >>"$logFile"
|
printf "%s[%s] -- WARNING: %s invalid domain(s) were supplied for updating --%s\n" "$warn" "$(stamp)" "$invalidDomainCount" "$norm" >>"$logFile"
|
||||||
fi
|
fi
|
||||||
if [ "$failedDomainCount" -ne 0 ]; then
|
if [ "$failedDomainCount" -ne 0 ]; then
|
||||||
exitError 98
|
exitError 26
|
||||||
else
|
else
|
||||||
exitOK
|
exitOK
|
||||||
fi
|
fi
|
||||||
@ -447,11 +486,11 @@ fi
|
|||||||
# 0: normal exit, no errors
|
# 0: normal exit, no errors
|
||||||
# 1: invalid or unknown parameter
|
# 1: invalid or unknown parameter
|
||||||
# 2: cannot find or access required external program(s)
|
# 2: cannot find or access required external program(s)
|
||||||
|
# 3: curl error (probably connection)
|
||||||
# 10: cannot auto-detect IP address
|
# 10: cannot auto-detect IP address
|
||||||
# 20: accountFile has a null or missing cfEmail variable
|
# 20: accountFile has a null or missing cfEmail variable
|
||||||
# 21: accountFile has a null or missing cfKey variable
|
# 21: accountFile has a null or missing cfKey variable
|
||||||
# 22: accountFile has a null or missing cfZoneId variable
|
# 22: accountFile has a null or missing cfZoneId variable
|
||||||
# 25: unable to query Cloudflare account
|
# 25: Cloudflare API error
|
||||||
# 97: script completed with warnings
|
# 26: one or more updates failed
|
||||||
# 98: one or more updates failed
|
|
||||||
# 99: unspecified error occurred
|
# 99: unspecified error occurred
|
||||||
|
Loading…
Reference in New Issue
Block a user