From a38d625025a8aed36638b20f8eabf8e088d4593c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bernhard=20Rosenkr=C3=A4nzer?= Date: Mon, 17 Feb 2025 20:03:27 +0100 Subject: [PATCH] Simple functionality checks Add script to verify basic functionality (port connectivity) for all services and slightly more advanced functionality for pdns and pdnsmysql --- bin/check | 82 ++++++++++++++++++++++++++++++++++++++ lib/functions.sh | 9 ++++- lib/pdns.sh | 76 ++++++++++++++++++----------------- lib/pdnsmysql.sh | 34 ++++++++-------- services/pdns/check | 19 +++++++++ services/pdns/service | 6 +++ services/pdnsmysql/check | 14 +++++++ services/pdnsmysql/service | 4 ++ 8 files changed, 189 insertions(+), 55 deletions(-) create mode 100755 bin/check create mode 100755 services/pdns/check create mode 100644 services/pdns/service create mode 100755 services/pdnsmysql/check create mode 100644 services/pdnsmysql/service diff --git a/bin/check b/bin/check new file mode 100755 index 0000000..8bcb7f2 --- /dev/null +++ b/bin/check @@ -0,0 +1,82 @@ +#!/bin/bash +SERVICE="$1" + +. /federated/lib/functions.sh + +if [ -e /federated/services/$SERVICE/service ]; then + . /federated/services/$SERVICE/service +elif [ -d /federated/apps/$SERVICE ]; then + INTERNAL_IP="$(cat /federated/apps/$SERVICE/docker-compose.yml |grep 'ipv4_address:' |cut -d: -f2 |xargs echo)" + RELEVANT=false + while read r; do + [ -z "$r" ] && continue + if [ "$r" = "ports:" ]; then + RELEVANT=true + continue + fi + $RELEVANT || continue + if [ "$(echo $r |cut -b1)" != "-" ]; then + break + fi + P="$(echo $r |cut -b2- |xargs echo |sed -e 's,",,g')" + if echo $P |grep -q :; then + P="$(echo $P |cut -d: -f2-)" + fi + PUBLICPORTS="${PUBLICPORTS} ${P}" + done < <(cat /federated/apps/$SERVICE/docker-compose.yml) + unset RELEVANT +else + echo "Invalid service $SERVICE" >&2 + exit 1 +fi + +if [ -n "${INTERNAL_IP}" ]; then + # Make sure the container is responding + for IP in ${INTERNAL_IP} ${EXTRA_IPS}; do + if ! ping -c3 ${IP}; then + echo "$1 container not responding on ${IP}" >&2 + exit 1 + fi + done +fi + +if [ -n "${PORTS}" ]; then + # Make sure we can connect to the provided ports + for PORT in ${PORTS}; do + TRIES=5 + while ! nc -z ${INTERNAL_IP} ${PORT}; do + sleep 5s + TRIES=$((TRIES-1)) + if [ "$TRIES" = "0" ]; then + echo "$1 container fails to respond on port ${PORT}" >&2 + exit 2 + fi + done + done +fi + +if [ -n "${PUBLICPORTS}" ]; then + # Make sure we can connect to the external ports on the public IP + IP="$(get_externalip)" + for PORT in ${PUBLICPORTS}; do + TRIES=5 + if echo $PORT |grep -q '/udp$'; then + NC_OPTS="--udp" + PORT="$(echo $PORT |sed -e 's,/udp$,,')" + else + NC_OPTS="" + fi + while ! nc -z ${NC_OPTS} ${IP} ${PORT}; do + sleep 5s + TRIES=$((TRIES-1)) + if [ "$TRIES" = "0" ]; then + echo "${SERVICE} container fails to respond on public port ${PORT}" >&2 + exit 3 + fi + done + done +fi + +[ -e /federated/services/${SERVICE}/check ] && . /federated/services/${SERVICE}/check + +exit 0 diff --git a/lib/functions.sh b/lib/functions.sh index e6e6a22..3cc5684 100644 --- a/lib/functions.sh +++ b/lib/functions.sh @@ -201,8 +201,13 @@ create_password() { echo "$SECRET"; } get_externalip() { - EXTERNALIP=`dig @resolver4.opendns.com myip.opendns.com +short 2> /dev/null` - echo "$EXTERNALIP"; + EXTERNALIP="$(dig @resolver4.opendns.com myip.opendns.com +short 2> /dev/null)" + if [ -n "$EXTERNALIP" ]; then + echo "$EXTERNALIP" + else + # Try to get a reasonable response even if opendns is down + ip route list default |sed -e 's,.*src ,,;s, .*,,' + fi } start_service_convert() { SERVICE="$1" diff --git a/lib/pdns.sh b/lib/pdns.sh index 09f266b..78e5980 100644 --- a/lib/pdns.sh +++ b/lib/pdns.sh @@ -5,22 +5,24 @@ PATH=$HOME/.docker/cli-plugins:/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin config_pdns() { - echo -ne "\n* Configuring /federated/apps/pdns container.." + echo -ne "\n* Configuring /federated/apps/pdns container.." - if [ ! -d "/federated/apps/pdns" ]; then - mkdir -p /federated/apps/pdns/data/root - fi + if [ ! -d "/federated/apps/pdns" ]; then + mkdir -p /federated/apps/pdns/data/root + fi -cat > /federated/apps/pdns/docker-compose.yml < /federated/apps/pdns/docker-compose.yml < /federated/apps/pdns/.env < /federated/apps/pdns/.env < /federated/apps/pdns/data/root/createrecords.sh < /federated/apps/pdns/data/root/createrecords.sh < /dev/null" "7" + # Start service with command to make sure it's up before proceeding + start_service "pdns" "nc -z 192.168.0.11 8081 &> /dev/null" "7" - # Create DNS records for newdomain -# docker exec pdns pdnsutil create-zone $DOMAIN -# docker exec pdns pdnsutil set-kind $DOMAIN native -# docker exec pdns pdnsutil set-meta $DOMAIN SOA-EDIT-API DEFAULT + # Create DNS records for newdomain + # docker exec pdns pdnsutil create-zone $DOMAIN + # docker exec pdns pdnsutil set-kind $DOMAIN native + # docker exec pdns pdnsutil set-meta $DOMAIN SOA-EDIT-API DEFAULT -# for i in ns1 ns2 powerdns traefik mail www computer panel nextcloud collabora jitsi matrix element listmonk vaultwarden vpn wireguard baserow gitea blog documentation calcom plane; do -# docker exec pdns pdnsutil add-record $DOMAIN $i A 86400 $EXTERNALIP -# done + # for i in ns1 ns2 powerdns traefik mail www computer panel nextcloud collabora jitsi matrix element listmonk vaultwarden vpn wireguard baserow gitea blog documentation calcom plane; do + # docker exec pdns pdnsutil add-record $DOMAIN $i A 86400 $EXTERNALIP + # done -# docker exec pdns pdnsutil add-record $DOMAIN @ NS ns1.$DOMAIN_NEW -# docker exec pdns pdnsutil add-record $DOMAIN @ NS ns2.$DOMAIN_NEW -# docker exec pdns pdnsutil add-record $DOMAIN @ MX 86400 "10 mail.$DOMAIN" -# docker exec pdns pdnsutil add-record $DOMAIN @ TXT 86400 "\"v=spf1 mx a:$DOMAIN ~all\"" -# docker exec pdns pdnsutil add-record $DOMAIN \* CNAME 86400 www.$DOMAIN -# docker exec pdns pdnsutil add-record $DOMAIN @ A 86400 $EXTERNALIP + # docker exec pdns pdnsutil add-record $DOMAIN @ NS ns1.$DOMAIN_NEW + # docker exec pdns pdnsutil add-record $DOMAIN @ NS ns2.$DOMAIN_NEW + # docker exec pdns pdnsutil add-record $DOMAIN @ MX 86400 "10 mail.$DOMAIN" + # docker exec pdns pdnsutil add-record $DOMAIN @ TXT 86400 "\"v=spf1 mx a:$DOMAIN ~all\"" + # docker exec pdns pdnsutil add-record $DOMAIN \* CNAME 86400 www.$DOMAIN + # docker exec pdns pdnsutil add-record $DOMAIN @ A 86400 $EXTERNALIP - # Run createrecords.sh inside pdns container - docker exec pdns /root/createrecords.sh &> /dev/null - [ $? -ne 0 ] && fail "Couldn't run createrecords.sh in /federated/apps/pdns container" + # Run createrecords.sh inside pdns container + docker exec pdns /root/createrecords.sh &> /dev/null + [ $? -ne 0 ] && fail "Couldn't run createrecords.sh in /federated/apps/pdns container" - # Remove createrecords - rm /federated/apps/pdns/data/root/createrecords.sh + # Remove createrecords + rm /federated/apps/pdns/data/root/createrecords.sh - echo -ne "done." + echo -ne "done." } diff --git a/lib/pdnsmysql.sh b/lib/pdnsmysql.sh index 289b2e6..57043bf 100644 --- a/lib/pdnsmysql.sh +++ b/lib/pdnsmysql.sh @@ -5,22 +5,24 @@ PATH=$HOME/.docker/cli-plugins:/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin config_pdnsmysql() { - echo -ne "* Configuring pdnsmysql container.." + echo -ne "* Configuring pdnsmysql container.." - if [ ! -d "/federated/apps/pdnsmysql" ]; then - mkdir -p /federated/apps/pdnsmysql/data/var/lib/mysql - fi + . /federated/services/pdnsmysql/service -cat > /federated/apps/pdnsmysql/docker-compose.yml < /federated/apps/pdnsmysql/docker-compose.yml < /federated/apps/pdnsmysql/.env < /federated/apps/pdnsmysql/.env < /dev/null" "8" + # Start service with command to make sure it's up before proceeding + start_service "pdnsmysql" "nc -z 192.168.0.10 3306 &> /dev/null" "8" - echo -ne "done.\n" + echo -ne "done.\n" } diff --git a/services/pdns/check b/services/pdns/check new file mode 100755 index 0000000..5c69823 --- /dev/null +++ b/services/pdns/check @@ -0,0 +1,19 @@ +#!/bin/sh +. /federated/lib/functions.sh +. /federated/services/pdns/service +. /federated/apps/pdns/.env +. /etc/federated + +EXTERNAL_IP=$(get_externalip) + +# Check it is up and running and produces reasonable output +if [ "$(dig @${EXTERNAL_IP} ${DOMAIN} +short)" != "${EXTERNAL_IP}" ]; then + echo "PDNS returns invalid result for ${DOMAIN}" +fi +if [ "$(dig @${EXTERNAL_IP} pdns.${DOMAIN} +short |tail -n1)" != "${EXTERNAL_IP}" ]; then + echo "PDNS returns invalid result for federated.computer" +fi +if [ "$(dig @${EXTERNAL_IP} federated.computer +short)" != "5.161.88.87" ]; then + echo "PDNS returns invalid result for federated.computer" +fi +exit 0 diff --git a/services/pdns/service b/services/pdns/service new file mode 100644 index 0000000..c672d59 --- /dev/null +++ b/services/pdns/service @@ -0,0 +1,6 @@ +CONTAINER=pschiffe/pdns-mysql +VERSION=4.9 +DEPENDS=pdnsmysql +INTERNAL_IP=192.168.0.11 +PORTS=8081 +PUBLICPORTS="53 53/udp" diff --git a/services/pdnsmysql/check b/services/pdnsmysql/check new file mode 100755 index 0000000..bc9370e --- /dev/null +++ b/services/pdnsmysql/check @@ -0,0 +1,14 @@ +#!/bin/sh +. /federated/services/pdnsmysql/service +. /federated/apps/pdnsmysql/.env + +# Check it is up and running and produces reasonable output +TRIES=5 +while ! docker exec -ti pdnsmysql mysql -p${MYSQL_ROOT_PASSWORD} mysql -e 'SELECT User FROM user WHERE User="root";'; do + TRIES=$((TRIES-1)) + if [ "$TRIES" = 0 ]; then + echo "pdnsmysql not responding to SQL queries" >&2 + exit 2 + fi +done +exit 0 diff --git a/services/pdnsmysql/service b/services/pdnsmysql/service new file mode 100644 index 0000000..fc1c3ad --- /dev/null +++ b/services/pdnsmysql/service @@ -0,0 +1,4 @@ +CONTAINER=mariadb +VERSION=10.7.8 +INTERNAL_IP=192.168.0.10 +PORTS=3306