@@ 1,87 @@
+#!/bin/sh
+#
+# Dynamic failover tools v0.1
+#
+# Calls to this script should be made on crontab
+# on primary host:
+# */1 * * * * . $HOME/.profile; dynfail failover
+# */5 * * * * . $HOME/.profile; dynfail sync_ip
+# on secondary host:
+# */1 * * * * . $HOME/.profile; dynfail recover
+# */5 * * * * . $HOME/.profile; dynfail sync_ip
+#
+# Requirements:
+# - sudo with access to the postgres user
+# - dig (bind9-dnsutils/bind-tools)
+# - nc
+# - linode-cli (don't follow me, use nsupdate instead)
+# - PGLR https://git.hacktivista.org/pglr
+#
+# Copyright 2021 Felix Freeman <libsys@hacktivista.org>
+#
+# This software is licensed under the 'MIT No Attribution' license terms. I
+# don't want attribution nor exclusive rights over it, but I'd love that you
+# free your software too.
+
+if [ $# -ne 1 ]; then
+ echo "Usage: $0 <sync_ip|failover|recover>"
+ exit 1
+fi
+
+domain_id=$DYNFAIL_DOMAIN_ID
+root_record_id=$DYNFAIL_ROOT_RECORD_ID
+root_host=$DYNFAIL_ROOT_HOST
+primary_ip=$DYNFAIL_PRIMARY_IP
+this_host=$DYNFAIL_THIS_HOST
+this_record_id=$DYNFAIL_THIS_RECORD_ID
+this_replica=$DYNFAIL_THIS_REPLICA
+replicas=$DYNFAIL_REPLICAS
+databases=$DYNFAIL_DATABASES # string list divided by space
+
+update_root_ip () {
+ target_ip=$(dig -4 +short "$1")
+ linode-cli domains records-update "$domain_id" "$root_record_id" \
+ --target "$target_ip"
+}
+
+sync_ip () {
+ last_ip=$(dig -4 +short "$this_host")
+ current_ip="$(dig -4 +short myip.opendns.com @resolver1.opendns.com)"
+ if [ "$last_ip" != "$current_ip" ]; then
+ linode-cli domains records-update "$domain_id" "$this_record_id" \
+ --target="$current_ip"
+ update_root_ip "$this_host"
+ fi
+}
+
+failover () {
+ # if primary host postgres can't be reached
+ # and failover has not been executed yet
+ if \
+ ! nc -w 5 -z "$primary_ip" 5432 \
+ && [ "$(dig -4 +short "$root_host")" != "$(dig -4 +short "$this_host")" ]
+ then
+ update_root_ip "$this_host"
+ for database in $databases; do
+ sudo -u postgres -- psql "$database" \
+ -c "CALL pglr_seq_sync($replicas, $this_replica)"
+ done
+ fi
+}
+
+recover () {
+ # if root is assigned to other host
+ # and this (primary) host has connectivity
+ if \
+ [ "$(dig -4 +short "$root_host")" != "$(dig -4 +short "$this_host")" ] \
+ && nc -w 5 -z 1.1.1.1 80
+ then
+ update_root_ip "$this_host"
+ for database in $databases; do
+ sudo -u postgres -- psql "$database" \
+ -c "CALL pglr_seq_sync($replicas, $this_replica)"
+ done
+ fi
+}
+
+$1