blob: 4042ee36e952a74af1df714744152794e8166bec (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
|
#!/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
# Based on the week of the year, we swap the master/standby roles.
# This is so that we always have up-to-date Let's Encrypt TLS certificates
# renewed on either server.
local -i week_of_the_year=$(date +%U)
if [ $(( week_of_the_year % 2 )) -ne 0 ]; then
local tmp=$master
master=$standby
standby=$tmp
fi
echo "Master is $master, standby is $standby"
MASTER_A=$(host $master | awk '/has address/ { print $(NF) }')
MASTER_AAAA=$(host $master | awk '/has IPv6 address/ { print $(NF) }')
STANDBY_A=$(host $standby | awk '/has address/ { print $(NF) }')
STANDBY_AAAA=$(host $standby | awk '/has IPv6 address/ { print $(NF) }')
}
transform () {
sed -E '
/IN A .*; Enable failover/ {
/^mirror/! {
s/^(.*) 300 IN A (.*) ; (.*)/\1 300 IN A '$MASTER_A' ; \3/;
}
/^mirror/ {
s/^(.*) 300 IN A (.*) ; (.*)/\1 300 IN A '$STANDBY_A' ; \3/;
}
}
/IN AAAA .*; Enable failover/ {
/^mirror/! {
s/^(.*) 300 IN AAAA (.*) ; (.*)/\1 300 IN AAAA '$MASTER_AAAA' ; \3/;
}
/^mirror/ {
s/^(.*) 300 IN AAAA (.*) ; (.*)/\1 300 IN AAAA '$STANDBY_AAAA' ; \3/;
}
}
/ ; serial/ {
s/^( +) ([0-9]+) .*; (.*)/\1 '"$(date +%s)"' ; \3/;
}
'
}
zone_is_ok () {
local zone=$1
local domain=${zone%.zone}
echo "Testing zone $zone (if no NS output, then doesn't work)"
dig $domain @localhost | grep "$domain.*IN.*NS"
}
failover_zone () {
local zone_file=$1
local zone=$(basename $zone_file)
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
if diff $zone_file.new.noserial.tmp $zone_file.old.noserial.tmp; then
echo "zone $zone_file hasn't changed"
rm $zone_file.*.tmp
return
fi
cp $zone_file $zone_file.bak
mv $zone_file.new.tmp $zone_file
rm $zone_file.*.tmp
nsd-control reload
if zone_is_ok $zone; then
if [ -f $zone_file.invalid ]; then
rm $zone_file.invalid
fi
echo "Failover of zone $zone completed"
return
fi
echo "Rolling back $zone_file changes"
cp $zone_file $zone_file.invalid
mv $zone_file.bak $zone_file
nsd-control reload
zone_is_ok $zone
}
main () {
determine_master_and_standby
for zone_file in $ZONES_DIR/*.zone; do
failover_zone $zone_file
done
}
main
|