Last active
December 28, 2023 15:00
-
-
Save pirate/d3e6312b999409705fade0eaf67dd9a0 to your computer and use it in GitHub Desktop.
Dynamic DNS updater script for DigitalOcean and CloudFlare (using bash, curl, and jq)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
# set -o xtrace | |
set -o errexit | |
set -o errtrace | |
set -o nounset | |
set -o pipefail | |
SCRIPTNAME="$0" | |
HELP_TEXT=" | |
DNS update helper script (to get or update a DNS record on multiple providers). | |
Usage: | |
$SCRIPTNAME domain.example.com A [--get|--set=value] [...options] | |
Options: | |
[domain] The DNS domain you want to get or set (required) | |
[type] The DNS record type, e.g. A, CNAME, etc. (required) | |
-g|--get Get the record value (the default) | |
-s=|--set=value Set the record value, e.g. 123.235.324.234 or the | |
special value 'pubip' to use current public ip | |
-t=|--ttl=n Set the record TTL to n seconds (overrides api default) | |
-p=|--proxied Set the record to be proxied through CDN (Cloudflare only) | |
-a=|--api=api1,api2 Comma-separated list of DNS providers to use, e.g. cf,do | |
(cf=cloudflare, do=digitalocean, default is all) | |
-c=|--config=file Path to a dotenv-formatted config file to load | |
-r=|--refresh=n Run continusouly every n seconds in a loop | |
-w=|--timeout=n Wait n seconds before aborting and retrying | |
-h|--help Show this help message | |
-v|--verbose Show more verbose output | |
-q|--quiet Supress all output except for errors and warnings | |
--color Force showing of colors in the stderr output | |
--nocolor Force hiding of colors in the stderr output | |
--notimestamps Force hiding of timestamps in stderr output | |
--nologlevels Force hiding of log levels in stderr output | |
Config: (passed via --config=file or environment variables) | |
CF_API_KEY=12345 Clouflare API token: https://dash.cloudflare.com/<account_id>/profile/api-tokens | |
DO_API_KEY=12345 DigitalOcean API token: https://cloud.digitalocean.com/account/api/tokens | |
VEBOSE=1 Show debug output [0]/1 | |
QUIET=0 Hide info output: [0]/1 | |
COLOR=1 Colorize stderr output: [1]/0 | |
TIMEOUT=15 Seconds to wait before aborting and retrying | |
NS1=1.1.1.1 Nameserver #1 to use for lookups (default) | |
NS2=8.8.8.8 Nameserver #2 to use for lookups (fallback) | |
NS3=208.67.222.222 Nameserver #3 to use for lookups (fallback) | |
Examples: | |
$SCRIPTNAME abc.example.com A | |
$SCRIPTNAME abc.example.com A --set=1.2.3.4 --ttl=300 --api=digitalocean | |
$SCRIPTNAME abc.example.com A --set=pubip --api=digitalocean,cloudflare --refresh=30 --config=./secrets.env | |
$SCRIPTNAME abc.example.com A --get --refresh=30 --config=~/.cloudflare.conf | |
" | |
API_KEY_PLACEHOLDER="set-this-value-in-your-config-file" | |
### Config | |
CF_API_KEY="$API_KEY_PLACEHOLDER" | |
DO_API_KEY="$API_KEY_PLACEHOLDER" | |
TTL='default' | |
PROXIED='false' | |
APIS='all' | |
CONFIG='' | |
REFRESH='0' | |
TIMEOUT=15 | |
VERBOSE=0 | |
QUIET=0 | |
COLOR=1 | |
TIMESTAMPS=1 | |
LOGLEVELS=1 | |
NS1="1.1.1.1" | |
NS2="8.8.8.8" | |
NS3="208.67.222.222" | |
AVAILABLE_APIS="cf,do" | |
CF_API_URL="https://api.cloudflare.com/client/v4" | |
DO_API_URL="https://api.digitalocean.com/v2" | |
CF_DEFAULT_TTL="1" | |
DO_DEFAULT_TTL="300" | |
### Helpers | |
[[ ! -t 2 ]] && COLOR='0' # if stderr is not a tty, turn of log coloring | |
GRAY='\033[2;37m' | |
RED='\033[0;31m' | |
YELLOW='\033[0;33m' | |
CYAN='\033[0;36m' | |
RESET='\033[0m' | |
function log { | |
LEVEL="$1"; shift; STRING="$*"; | |
case "$LEVEL" in | |
DEBUG) ANSI="$GRAY";; | |
INFO) ANSI="$CYAN";; | |
WARN) ANSI="$YELLOW";; | |
ERROR) ANSI="$RED";; | |
FATAL) ANSI="$RED";; | |
*) ANSI="";; | |
esac | |
# replace newlines and repeated whitespace with a single space | |
STRING="$(echo -e "$STRING" | sed -e "s/[[:space:]]\+/ /g")" | |
if [[ "$TIMESTAMPS" == "1" ]]; then | |
TS="[$(date +"%Y-%m-%d %H:%M")] " | |
else | |
TS="" | |
fi | |
if [[ "$LOGLEVELS" == "1" ]]; then | |
LEVEL="$(printf '%-7s' "[${LEVEL}] ")" | |
else | |
LEVEL="" | |
fi | |
if [[ "$COLOR" == "1" ]]; then | |
echo -e "${GRAY}${TS}${ANSI}${LEVEL}$RESET${STRING}" >&2 | |
else | |
echo -e "${TS}${LEVEL}${STRING}" >&2 | |
fi | |
} | |
function debug { | |
set +o xtrace | |
[[ ! "$VERBOSE" == "1" ]] && return 0 | |
log DEBUG "$*" | |
# set -o xtrace | |
} | |
function info { | |
set +o xtrace | |
[[ "$QUIET" == "1" ]] && return 0 | |
log INFO "$*" | |
# set -o xtrace | |
} | |
function warn { | |
set +o xtrace | |
log WARN "$*" | |
# set -o xtrace | |
} | |
function error { | |
set +o xtrace | |
log ERROR "$*" | |
# set -o xtrace | |
} | |
function fatal { | |
set +o xtrace | |
echo "" >&2 | |
log FATAL "$*" | |
exit 3 | |
} | |
function on_quit { | |
local reason="$*" | |
fatal "Stopped. (received $reason)" | |
} | |
trap 'on_quit SIGINT' SIGINT | |
trap 'on_quit SIGQUIT' SIGQUIT | |
trap 'on_quit SIGTSTP' SIGTSTP | |
trap 'on_quit TIMEOUT' SIGALRM | |
function timed { | |
MAX="$1"; shift; CMD="$*"; | |
ppid="$$" | |
( | |
eval "$CMD" & cmd_pid=$! | |
( | |
sleep "$MAX" | |
warn "Reached ${MAX}s timeout, aborting and retrying..." | |
kill $cmd_pid 2> /dev/null | |
) & killer_pid=$! | |
debug "[timed][1/2] Timer started ppid=$ppid cmd_pid=$cmd_pid killer=$killer_pid" | |
wait $cmd_pid || true | |
kill $killer_pid | |
debug "[timed][2/2] Finished sucesfully ppid=$ppid cmd_pid=$cmd_pid killer=$killer_pid" | |
) | |
} | |
IPV4_BLOCK='(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)' | |
IPV4_REGEX="$IPV4_BLOCK\.$IPV4_BLOCK\.$IPV4_BLOCK\.$IPV4_BLOCK" | |
function get_rootdomain { | |
# www.sub.example.dev -> example.dev | |
DOMAIN="$1" | |
echo "$DOMAIN" | rev | cut -d "." -f1-2 | rev | |
} | |
function get_subdomain { | |
# www.sub.example.dev -> www.sub | |
DOMAIN="$1" | |
ROOTDOMAIN="$(get_rootdomain "$DOMAIN")" | |
echo "$DOMAIN" | replace ".$ROOTDOMAIN" '' | |
} | |
function canonical_ip { | |
DOMAIN="$1"; TYPE="${2:-A}"; shift 2; NS="$*"; | |
debug "[canonical_ip][1/3] dig $DOMAIN $TYPE @$NS | grep -Eo '\$IPV4_REGEX'" | |
if [[ -n "$NS" ]]; then | |
# Resolve domain to IP using NS | |
OUTPUT="$(dig -4 +short +tries=5 +time=5 "$DOMAIN" "$TYPE" "@$NS" 2>&1)" | |
STATUS="$?" | |
else | |
for NS in "$NS1" "$NS2" "$NS3"; do | |
OUTPUT="$(dig -4 +short +tries=2 +time=3 "$DOMAIN" "$TYPE" "@$NS" 2>&1)" && break | |
STATUS="$?" | |
done | |
fi | |
debug "[canonical_ip][2/3] dig (exitstatus=$STATUS) => $OUTPUT" | |
if ((STATUS>0)); then | |
error "Resolving $DOMAIN $TYPE @$NS failed. (Is the internet down?)" | |
return 1 | |
fi | |
PARSED_OUTPUT="$(echo "$OUTPUT" | grep -Eo "$IPV4_REGEX" | head -1)"; STATUS="$?" | |
debug "[canonical_ip][3/3] grep (exitstatus=$STATUS) => $PARSED_OUTPUT" | |
if ((STATUS>0)); then | |
error "Parsing $DOMAIN $TYPE @$NS failed. (got $OUTPUT)" | |
return 1 | |
fi | |
echo "$PARSED_OUTPUT" | |
} | |
function akamai_get_public_ip { | |
curl --silent "http://whatismyip.akamai.com/" | grep -Eo "$IPV4_REGEX" || return 1 | |
} | |
function tyk_get_public_ip { | |
curl --silent 'http://ip.tyk.nu/' | grep -Eo "$IPV4_REGEX" || return 1 | |
} | |
function openhttp_get_public_ip { | |
curl --silent "https://diagnostic.opendns.com/myip" | grep -Eo "$IPV4_REGEX" || return 1 | |
} | |
function ifconfig_get_public_ip { | |
curl --silent 'https://ifconfig.me' | grep -Eo "$IPV4_REGEX" || return 1 | |
} | |
function opendns_get_public_ip { | |
canonical_ip "myip.opendns.com" "A" "resolver1.opendns.com" || return 1 | |
} | |
function google_get_public_ip { | |
canonical_ip "o-o.myaddr.l.google.com" "TXT" "ns1.google.com" || return 1 | |
} | |
function dnscrypt_get_public_ip { | |
canonical_ip "resolver.dnscrypt.info" "TXT" "$NS1" || return 1 | |
} | |
function get_public_ip { | |
akamai_get_public_ip || \ | |
ifconfig_get_public_ip || \ | |
openhttp_get_public_ip || \ | |
tyk_get_public_ip || \ | |
dnscrypt_get_public_ip || \ | |
opendns_get_public_ip || \ | |
google_get_public_ip || \ | |
{ | |
error "Unable to get public IP from any source!" | |
return 1 | |
} | |
} | |
function call_api { | |
API="$1"; METHOD="$2"; URL="$3"; JSON_PATH="$4"; shift 4; DATA="$*"; | |
case "$API" in | |
digitalocean|'do') | |
API_KEY="$DO_API_KEY"; URL="$DO_API_URL$URL";; | |
cloudflare|'cf') | |
API_KEY="$CF_API_KEY"; URL="$CF_API_URL$URL";; | |
*) | |
fatal "Invalid API type $API";; | |
esac | |
IFS="" | |
CMD=( | |
"curl" | |
"--silent" | |
"--request" "$METHOD" | |
"--url" "'$URL'" | |
"--header" "'Authorization: Bearer $API_KEY'" | |
"--header" "'Content-Type: application/json'" | |
) | |
[[ -n "$DATA" ]] && { | |
CMD+=("--data" "'$DATA'") | |
} | |
debug "[call_api][1/3] curl -X $METHOD $URL --data '$DATA' ($API) | jq '$JSON_PATH'" | |
IFS=" " | |
OUTPUT="$(eval "${CMD[@]}")"; STATUS="$?" | |
debug "[call_api][2/3] curl (exitstatus=$STATUS) => $OUTPUT" | |
if ((STATUS>0)); then | |
debug "> $OUTPUT" | |
error "API request to $API failed. (status=$?)" | |
return 1 | |
fi | |
PARSED_OUTPUT="$(echo "$OUTPUT" | jq --raw-output "$JSON_PATH")"; STATUS="$?" | |
debug "[call_api][3/3] jq (exitstatus=$STATUS) => $PARSED_OUTPUT" | |
if ((STATUS>0)); then | |
error "API response from $API could not be parsed. (status=$?)" | |
return 1 | |
fi | |
if [[ -z "$PARSED_OUTPUT" || "$PARSED_OUTPUT" == "null" || "$PARSED_OUTPUT" == "undefined" ]]; then | |
warn "API response from $API indicates no matching record exists. (got $PARSED_OUTPUT)" | |
echo "null" | |
return 1 | |
else | |
echo "$PARSED_OUTPUT" | |
return 0 | |
fi | |
} | |
### DigitalOcean | |
function do_record_url { | |
DOMAIN="$1"; TYPE="${2:-A}"; | |
ROOTDOMAIN="$(get_rootdomain "$DOMAIN")" | |
SUBDOMAIN="$(get_subdomain "$DOMAIN")" | |
RECORDS_URL="/domains/$ROOTDOMAIN/records" | |
RECORDS_JSON_PATH=".domain_records[] | select(.name == \"$SUBDOMAIN\" and .type == \"$TYPE\") | .id" | |
RECORD_ID="$(call_api digitalocean GET "$RECORDS_URL" "$RECORDS_JSON_PATH")" || return $? | |
echo "/domains/$ROOTDOMAIN/records/$RECORD_ID" | |
} | |
function do_get_record { | |
DOMAIN="$1"; TYPE="${2:-A}" | |
URL="$(do_record_url "$DOMAIN" "$TYPE")" || return $? | |
JSON_PATH=".domain_record.data" | |
call_api digitalocean GET "$URL" "$JSON_PATH" | |
} | |
function do_create_record { | |
DOMAIN="$1"; TYPE="$2"; VALUE="$3"; TTL="${4:-default}"; | |
[[ "$TTL" == "default" ]] && TTL="$DO_DEFAULT_TTL" | |
ROOTDOMAIN="$(get_rootdomain "$DOMAIN")" | |
SUBDOMAIN="$(get_subdomain "$DOMAIN")" | |
URL="/domains/$ROOTDOMAIN/records" | |
JSON_PATH=".domain_record.data" | |
DATA='{ | |
"type": "'$TYPE'", | |
"name": "'$SUBDOMAIN'", | |
"data": "'$VALUE'", | |
"ttl": '$TTL' | |
}' | |
call_api digitalocean POST "$URL" "$JSON_PATH" "$DATA" | |
} | |
function do_set_record { | |
DOMAIN="$1"; TYPE="$2"; VALUE="$3"; TTL="${4:-default}"; | |
[[ "$TTL" == "default" ]] && TTL="$DO_DEFAULT_TTL" | |
SUBDOMAIN="$(get_subdomain "$DOMAIN")" | |
URL="$(do_record_url "$DOMAIN" "$TYPE")" || return $? | |
JSON_PATH=".domain_record.data" | |
DATA='{ | |
"type": "'$TYPE'", | |
"name": "'$SUBDOMAIN'", | |
"data": "'$VALUE'", | |
"ttl": '$TTL' | |
}' | |
call_api digitalocean PUT "$URL" "$JSON_PATH" "$DATA" | |
} | |
### Cloudflare | |
function cf_record_url { | |
DOMAIN="$1"; TYPE="${2:-A}"; | |
ROOTDOMAIN="$(get_rootdomain "$DOMAIN")" | |
ZONES_URL="/zones" | |
ZONES_JSON_PATH=".result[] | select(.name == \"$ROOTDOMAIN\") | .id" | |
ZONE_ID="$(call_api cloudflare GET "$ZONES_URL" "$ZONES_JSON_PATH")" | |
RECORDS_URL="/zones/$ZONE_ID/dns_records?name=$DOMAIN&type=$TYPE" | |
RECORDS_JSON_PATH='.result[0].id' | |
RECORD_ID="$(call_api cloudflare GET "$RECORDS_URL" "$RECORDS_JSON_PATH")" | |
echo "/zones/$ZONE_ID/dns_records/$RECORD_ID" | |
} | |
function cf_get_record { | |
DOMAIN="$1"; TYPE="${2:-A}" | |
URL="$(cf_record_url "$DOMAIN" "$TYPE")" | |
JSON_PATH='.result.content' | |
call_api cloudflare GET "$URL" "$JSON_PATH" | |
} | |
function cf_create_record { | |
DOMAIN="$1"; TYPE="$2"; VALUE="$3"; TTL="${4:-default}"; PROXIED="${5:-$PROXIED}" | |
[[ "$TTL" == "default" ]] && TTL="$CF_DEFAULT_TTL" | |
ROOTDOMAIN="$(get_rootdomain "$DOMAIN")" | |
ZONES_URL="/zones" | |
ZONES_JSON_PATH=".result[] | select(.name == \"$ROOTDOMAIN\") | .id" | |
ZONE_ID="$(call_api cloudflare GET "$ZONES_URL" "$ZONES_JSON_PATH")" | |
URL="/zones/$ZONE_ID/dns_records" | |
JSON_PATH='.result.content' | |
DATA='{ | |
"type": "'$TYPE'", | |
"name": "'$DOMAIN'", | |
"content": "'$VALUE'", | |
"ttl": '$TTL', | |
"proxied": '$PROXIED' | |
}' | |
call_api cloudflare POST "$URL" "$JSON_PATH" "$DATA" | |
} | |
function cf_set_record { | |
DOMAIN="$1"; TYPE="$2"; VALUE="$3"; TTL="${4:-default}"; PROXIED="${5:-$PROXIED}" | |
[[ "$TTL" == "default" ]] && TTL="$CF_DEFAULT_TTL" | |
URL="$(cf_record_url "$DOMAIN" "$TYPE")" | |
JSON_PATH='.result.content' | |
DATA='{ | |
"type": "'$TYPE'", | |
"name": "'$DOMAIN'", | |
"content": "'$VALUE'", | |
"ttl": '$TTL', | |
"proxied": '$PROXIED' | |
}' | |
call_api cloudflare PUT "$URL" "$JSON_PATH" "$DATA" | |
} | |
### Main Functions | |
function get_record { | |
API="$1"; DOMAIN="$2"; TYPE="$3"; | |
VALUE="$( | |
"${API}_get_record" \ | |
"$DOMAIN" \ | |
"$TYPE" | |
)" | |
echo "$VALUE" | |
} | |
function update_record { | |
API="$1"; DOMAIN="$2"; TYPE="$3"; VALUE="$4"; TTL="$5"; PROXIED="$6" | |
[[ "$VALUE" == "pubip" ]] && VALUE="$(get_public_ip)" | |
VALUE_BEFORE="$( | |
"${API}_get_record" \ | |
"$DOMAIN" \ | |
"$TYPE" | |
)" | |
if [[ "$VALUE_BEFORE" == "null" ]]; then | |
warn "$API/$DOMAIN/$TYPE=$VALUE creating new record..." | |
VALUE_AFTER="$( | |
"${API}_create_record" \ | |
"$DOMAIN" \ | |
"$TYPE" \ | |
"$VALUE" \ | |
"$TTL" \ | |
"$PROXIED" | |
)" | |
elif [[ "$VALUE_BEFORE" == "$VALUE" ]]; then | |
info "$API/$DOMAIN/$TYPE=$VALUE_BEFORE is up-to-date." | |
return 0 | |
else | |
warn "$API/$DOMAIN/$TYPE=$VALUE_BEFORE updating to $VALUE..." | |
VALUE_AFTER="$( | |
"${API}_set_record" \ | |
"$DOMAIN" \ | |
"$TYPE" \ | |
"$VALUE" \ | |
"$TTL" \ | |
"$PROXIED" | |
)" | |
fi | |
if [[ "$VALUE_AFTER" != "$VALUE" ]]; then | |
error "$API/$DOMAIN/$TYPE=$VALUE update failed (got $VALUE_AFTER)." | |
return 1 | |
else | |
info "$API/$DOMAIN/$TYPE=$VALUE update succeeded." | |
return 0 | |
fi | |
} | |
function main { | |
declare -A KWARGS=( | |
[domain]='' | |
[type]='' | |
[set]='' | |
[api]='' | |
[ttl]='' | |
[proxied]='' | |
[refresh]='' | |
[config]='' | |
[verbose]='' | |
[quiet]='' | |
[color]='' | |
[timestamps]='' | |
[loglevels]='' | |
) | |
while (( "$#" )); do | |
case "$1" in | |
-h|--help|help) | |
echo "$HELP_TEXT" | |
exit 0;; | |
-v|--verbose) | |
KWARGS[verbose]='1' | |
KWARGS[quiet]='0' | |
shift;; | |
-q|--quiet) | |
KWARGS[verbose]='0' | |
KWARGS[quiet]='1' | |
shift;; | |
--color) | |
KWARGS[color]='1' | |
shift;; | |
--nocolor) | |
KWARGS[color]='0' | |
shift;; | |
--notimestamps) | |
KWARGS[timestamps]='0' | |
shift;; | |
--nologlevels) | |
KWARGS[loglevels]='0' | |
shift;; | |
-g|--get) | |
shift;; | |
-s|--set|-s=*|--set=*) | |
if [[ "$1" == *'='* ]]; then | |
KWARGS[set]="${1#*=}" | |
else | |
shift | |
KWARGS[set]="$1" | |
fi | |
shift;; | |
-t|-t=*|--ttl|--ttl=*) | |
if [[ "$1" == *'='* ]]; then | |
KWARGS[ttl]="${1#*=}" | |
else | |
shift | |
KWARGS[ttl]="$1" | |
fi | |
shift;; | |
-p|--proxied) | |
KWARGS[proxied]='true' | |
shift;; | |
-a|-a=*|--api|--api=*) | |
if [[ "$1" == *'='* ]]; then | |
KWARGS[api]="${1#*=}" | |
else | |
shift | |
KWARGS[api]="$1" | |
fi | |
shift;; | |
-c|--config|-c=*|--config=*) | |
if [[ "$1" == *'='* ]]; then | |
KWARGS[config]="${1#*=}" | |
else | |
shift | |
KWARGS[config]="$1" | |
fi | |
shift;; | |
-r|-r=*|-refresh|--refresh=*) | |
if [[ "$1" == *'='* ]]; then | |
KWARGS[refresh]="${1#*=}" | |
else | |
shift | |
KWARGS[refresh]="$1" | |
fi | |
shift;; | |
-w|-w=*|--timeout|--timeout=*) | |
if [[ "$1" == *'='* ]]; then | |
KWARGS[timeout]="${1#*=}" | |
else | |
shift | |
KWARGS[timeout]="$1" | |
fi | |
shift;; | |
*) | |
if [[ ! "${KWARGS[domain]}" ]]; then | |
KWARGS[domain]="$1" | |
elif [[ ! "${KWARGS[type]}" ]]; then | |
KWARGS[type]="$1" | |
else | |
fatal "Got unrecognized argument '$1'" | |
fi | |
shift;; | |
esac | |
done | |
echo "---------------------------------------------------------------------" | |
echo -n "$SCRIPTNAME " | |
for key in "${!KWARGS[@]}"; do | |
echo -n "$key=${KWARGS[$key]} " | |
done | |
echo | |
echo "---------------------------------------------------------------------" | |
DOMAIN="${KWARGS[domain]}" | |
TYPE="${KWARGS[type]}" | |
VALUE="${KWARGS[set]}" | |
TTL="${KWARGS[ttl]:-$TTL}" | |
PROXIED="${KWARGS[proxied]:-$PROXIED}" | |
APIS="${KWARGS[api]:-$APIS}" | |
CONFIG="${KWARGS[config]}" | |
REFRESH="${KWARGS[refresh]}" | |
TIMEOUT="${KWARGS[timeout]:-$TIMEOUT}" | |
VERBOSE="${KWARGS[verbose]:-$VERBOSE}" | |
QUIET="${KWARGS[quiet]:-$QUIET}" | |
COLOR="${KWARGS[color]:-$COLOR}" | |
TIMESTAMPS="${KWARGS[timestamps]:-$TIMESTAMPS}" | |
LOGLEVELS="${KWARGS[loglevels]:-$LOGLEVELS}" | |
# Load config from file | |
if [[ "$CONFIG" ]]; then | |
[[ ! -f "$CONFIG" ]] && fatal "Unable to find config file at $CONFIG." | |
source "$CONFIG" || { | |
fatal "Unable to load config values from $CONFIG." | |
} | |
fi | |
# Validate config | |
if [[ ! "$DOMAIN" || ! "$TYPE" ]]; then | |
fatal "Missing [domain] or [type] argument (pass --help for usage and examples)." | |
fi | |
if [[ "$REFRESH" ]] && ! ((REFRESH>0)); then | |
fatal "Invalid refresh value $REFRESH (pass --help for usage and examples)." | |
fi | |
[[ "$APIS" == "all" ]] && APIS="$AVAILABLE_APIS" | |
# Begin check/update process | |
((REFRESH>0)) && INTERVAL="every $REFRESH seconds" || INTERVAL="once" | |
if [[ "${KWARGS[set]}" ]]; then | |
info "Starting: ${APIS[*]}/$DOMAIN/$TYPE=$VALUE (updating $INTERVAL)..." | |
else | |
info "Starting: ${APIS[*]}/$DOMAIN/$TYPE (checking $INTERVAL)..." | |
fi | |
while :; do | |
for API in ${APIS//,/ }; do | |
case "$API" in | |
digitalocean|'do') | |
API="do" | |
[[ "$DO_API_KEY" == "$API_KEY_PLACEHOLDER" ]] && { | |
fatal "You must pass your DO_API_KEY via environment variable or --config=file.env (pass --help for more info)." | |
};; | |
cloudflare|'cf') | |
API="cf" | |
[[ "$CF_API_KEY" == "$API_KEY_PLACEHOLDER" ]] && { | |
fatal "You must pass your CF_API_KEY via environment variable or --config=file.env (pass --help for more info)." | |
};; | |
*) | |
fatal "Invalid API type '$API'. (must be one or more of: $AVAILABLE_APIS)";; | |
esac | |
if [[ "${KWARGS[set]}" ]]; then | |
timed "$TIMEOUT" update_record "$API" "$DOMAIN" "$TYPE" "$VALUE" "$TTL" "$PROXIED" | |
else | |
timed "$TIMEOUT" get_record "$API" "$DOMAIN" "$TYPE" | |
fi | |
done | |
((REFRESH>0)) || break | |
sleep "$REFRESH" | |
done | |
} | |
main "$@" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment