summaryrefslogtreecommitdiff
path: root/gemfeed/examples/conf/frontends/scripts/dns-failover.ksh
diff options
context:
space:
mode:
Diffstat (limited to 'gemfeed/examples/conf/frontends/scripts/dns-failover.ksh')
-rw-r--r--gemfeed/examples/conf/frontends/scripts/dns-failover.ksh133
1 files changed, 133 insertions, 0 deletions
diff --git a/gemfeed/examples/conf/frontends/scripts/dns-failover.ksh b/gemfeed/examples/conf/frontends/scripts/dns-failover.ksh
new file mode 100644
index 00000000..dfc24ee3
--- /dev/null
+++ b/gemfeed/examples/conf/frontends/scripts/dns-failover.ksh
@@ -0,0 +1,133 @@
+#!/bin/ksh
+
+ZONES_DIR=/var/nsd/zones/master/
+DEFAULT_MASTER=fishfinger.buetow.org
+DEFAULT_STANDBY=blowfish.buetow.org
+
+determine_master_and_standby () {
+ local master=$DEFAULT_MASTER
+ local standby=$DEFAULT_STANDBY
+
+ # Weekly auto-failover for Let's Encrypt automation
+ local -i -r week_of_the_year=$(date +%U)
+ if [ $(( week_of_the_year % 2 )) -ne 0 ]; then
+ local tmp=$master
+ master=$standby
+ standby=$tmp
+ fi
+
+ local -i health_ok=1
+ if ! ftp -4 -o - https://$master/index.txt | grep -q "Welcome to $master"; then
+ echo "https://$master/index.txt IPv4 health check failed"
+ health_ok=0
+ elif ! ftp -6 -o - https://$master/index.txt | grep -q "Welcome to $master"; then
+ echo "https://$master/index.txt IPv6 health check failed"
+ health_ok=0
+ fi
+
+ if [ $health_ok -eq 0 ]; then
+ local tmp=$master
+ master=$standby
+ standby=$tmp
+ fi
+
+ echo "Master is $master, standby is $standby"
+
+ host $master | awk '/has address/ { print $(NF) }' >/var/nsd/run/master_a
+ host $master | awk '/has IPv6 address/ { print $(NF) }' >/var/nsd/run/master_aaaa
+ host $standby | awk '/has address/ { print $(NF) }' >/var/nsd/run/standby_a
+ host $standby | awk '/has IPv6 address/ { print $(NF) }' >/var/nsd/run/standby_aaaa
+}
+
+transform () {
+ sed -E '
+ /IN A .*; Enable failover/ {
+ /^standby/! {
+ s/^(.*) 300 IN A (.*) ; (.*)/\1 300 IN A '$(cat /var/nsd/run/master_a)' ; \3/;
+ }
+ /^standby/ {
+ s/^(.*) 300 IN A (.*) ; (.*)/\1 300 IN A '$(cat /var/nsd/run/standby_a)' ; \3/;
+ }
+ }
+ /IN AAAA .*; Enable failover/ {
+ /^standby/! {
+ s/^(.*) 300 IN AAAA (.*) ; (.*)/\1 300 IN AAAA '$(cat /var/nsd/run/master_aaaa)' ; \3/;
+ }
+ /^standby/ {
+ s/^(.*) 300 IN AAAA (.*) ; (.*)/\1 300 IN AAAA '$(cat /var/nsd/run/standby_aaaa)' ; \3/;
+ }
+ }
+ / ; serial/ {
+ s/^( +) ([0-9]+) .*; (.*)/\1 '$(date +%s)' ; \3/;
+ }
+ '
+}
+
+zone_is_ok () {
+ local -r zone=$1
+ local -r domain=${zone%.zone}
+ dig $domain @localhost | grep -q "$domain.*IN.*NS"
+}
+
+failover_zone () {
+ local -r zone_file=$1
+ local -r zone=$(basename $zone_file)
+
+ # Race condition (e.g. script execution abored in the middle previous run)
+ if [ -f $zone_file.bak ]; then
+ mv $zone_file.bak $zone_file
+ fi
+
+ cat $zone_file | transform > $zone_file.new.tmp
+
+ grep -v ' ; serial' $zone_file.new.tmp > $zone_file.new.noserial.tmp
+ grep -v ' ; serial' $zone_file > $zone_file.old.noserial.tmp
+
+ echo "Has zone $zone_file changed?"
+ if diff -u $zone_file.old.noserial.tmp $zone_file.new.noserial.tmp; then
+ echo "The zone $zone_file hasn't changed"
+ rm $zone_file.*.tmp
+ return 0
+ fi
+
+ cp $zone_file $zone_file.bak
+ mv $zone_file.new.tmp $zone_file
+ rm $zone_file.*.tmp
+ echo "Reloading nsd"
+ nsd-control reload
+
+ if ! zone_is_ok $zone; then
+ echo "Rolling back $zone_file changes"
+ cp $zone_file $zone_file.invalid
+ mv $zone_file.bak $zone_file
+ echo "Reloading nsd"
+ nsd-control reload
+ zone_is_ok $zone
+ return 3
+ fi
+
+ for cleanup in invalid bak; do
+ if [ -f $zone_file.$cleanup ]; then
+ rm $zone_file.$cleanup
+ fi
+ done
+
+ echo "Failover of zone $zone to $MASTER completed"
+ return 1
+}
+
+main () {
+ determine_master_and_standby
+
+ local -i ec=0
+ for zone_file in $ZONES_DIR/*.zone; do
+ if ! failover_zone $zone_file; then
+ ec=1
+ fi
+ done
+
+ # ec other than 0: CRON will send out an E-Mail.
+ exit $ec
+}
+
+main