Files

60 lines
3.8 KiB
Bash

# The firewall that runs, if any: firewalld or ufw.
fw_on() { systemctl is-active --quiet firewalld || { command -v ufw >/dev/null && ufw status | grep -q "Status: active"; }; }
# fw_allows PORT/PROTO [SERVICE]: it lets PORT in from the lab network
# (le-host), now and permanently.
fw_allows() {
local port=$1 svc=${2:-} z p
if systemctl is-active --quiet firewalld; then
z=$(firewall-cmd --get-zone-of-interface=le-host 2>/dev/null || firewall-cmd --get-default-zone)
[ "$(firewall-cmd --permanent --zone="$z" --get-target)" = ACCEPT ] && return 0
for p in "" --permanent; do
firewall-cmd $p --zone="$z" --query-port="$port" ||
{ [ -n "$svc" ] && firewall-cmd $p --zone="$z" --query-service="$svc"; } ||
firewall-cmd $p --zone="$z" --list-rich-rules | grep -Eq "port=\"${port%/*}\"|service name=\"$svc\"|10\.99\.0\." ||
return 1
done
else
ufw status | grep ALLOW | grep -Eqiw "${port%/*}|${svc:-none}|10\.99\.0\.[0-9/]+"
fi
}
# peer_get PORT: which back end answers the peer through PORT.
peer_get() { in_peer curl -s --max-time 4 "http://10.99.0.1:$1/" | sed -n 's/^Back end \([0-9]*\)$/\1/p'; }
# seen PORT N: the back ends that answered N requests.
seen() { local i; for i in $(seq "$2"); do peer_get "$1"; done | sort -u | tr '\n' ' '; }
# nginx keeps a round-robin position per worker: ask enough times.
W=$(pgrep -c -f 'nginx: worker')
N=$(( ${W:-0} * 2 + 2 ))
[ "$N" -le 40 ] || N=40
backends() { systemctl "$1" le-backend@8081 le-backend@8082; sleep 1; }
task 1 "nginx on port 80 in front of the back end"
need "nginx is running and enabled" 'active nginx && enabled nginx'
fw_on && need "the firewall lets port 80 in, now and permanently" 'fw_allows 80/tcp http'
need "curl http://10.99.0.1/ from the peer returns a back end's page" '[ -n "$(peer_get 80)" ]'
if is_rhel && [ "$(state_get selinux)" = Enforcing ]; then
need "SELinux is still enforcing" '[ "$(getenforce)" = Enforcing ]'
fi
task 2 "Port 80 balanced over 8081 and 8082, 8083 as backup"
fw_on && need "the firewall lets port 80 in, now and permanently" 'fw_allows 80/tcp http'
need "requests to port 80 reach 8081 and 8082, not 8083" 's=$(seen 80 $N); [[ $s == *8081* && $s == *8082* && $s != *8083* ]]'
need "with 8081 and 8082 stopped, 8083 answers" 'backends stop; r=$(peer_get 80); backends start; [ "$r" = 8083 ]'
task 3 "Port 81 balanced, sticky by client address"
need "nginx's configuration has ip_hash or hash \$remote_addr" 'nginx -T 2>/dev/null | grep -Eq "^[[:space:]]*(ip_hash|hash[[:space:]]+\\\$remote_addr)"'
fw_on && need "the firewall lets port 81 in, now and permanently" 'fw_allows 81/tcp'
need "requests to port 81 from the peer always reach the same back end" 's=$(seen 81 $N); [ -n "$s" ] && [ "$(wc -w <<<"$s")" = 1 ]'
task 4 "HAProxy on port 8080 with health checks" debian
need "haproxy is running and enabled" 'active haproxy && enabled haproxy'
need "haproxy -c reports the configuration valid" 'haproxy -c -f /etc/haproxy/haproxy.cfg'
need "the servers have health checks" 'grep -Eq "^[[:space:]]*server[[:space:]].*[[:space:]]check([[:space:]]|$)" /etc/haproxy/haproxy.cfg'
fw_on && need "the firewall lets port 8080 in, now and permanently" 'fw_allows 8080/tcp'
need "requests to port 8080 reach 8081 and 8082, not 8083" 's=$(seen 8080 6); [[ $s == *8081* && $s == *8082* && $s != *8083* ]]'
need "a stopped back end leaves the rotation within a few seconds" 'systemctl stop le-backend@8081; sleep 8; s=$(for i in 1 2 3 4; do peer_get 8080 || echo x; done | tr "\n" " "); systemctl start le-backend@8081; [ "$s" = "8082 8082 8082 8082 " ]'
task 5 "The back ends behind port 80 get X-Forwarded-For"
fw_on && need "the firewall lets port 80 in, now and permanently" 'fw_allows 80/tcp http'
need "the back end gets X-Forwarded-For with the peer's address" 'rm -f /run/le-backend/*.xff; b=$(peer_get 80); [ -n "$b" ] && grep -q "10\.99\.0\.2" /run/le-backend/$b.xff'