Pull request 1779: 3290-docker-healthcheck

Merge in DNS/adguard-home from 3290-docker-healthcheck to master

Updates #3290.

Squashed commit of the following:

commit 3ac8f26c1c22855d973910fd13c096776aa8dfa6
Merge: bc17565f 0df32601
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Mon Mar 27 01:09:03 2023 +0500

    Merge branch 'master' into 3290-docker-healthcheck

commit bc17565fcb5acba68129734450fb08b4fe341771
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Sun Mar 26 18:04:08 2023 +0500

    all: fix script

commit e150fee8025dacdc5aa1d12916d1f42e89216156
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Sun Mar 26 17:18:12 2023 +0500

    all: imp naming

commit 26b6448d10af39f8363eadd962af228a9d4ae51d
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Sun Mar 26 03:13:47 2023 +0500

    all: support https web

commit b5c09ce8b2ac52d6e47a00f76125bee229f616a0
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Sat Mar 25 20:03:45 2023 +0500

    all: imp scripts fmt, naming

commit 8c3798c46974e48cc0c379c2ecc46a6d8d54164b
Merge: e33b0c5c fb7b8bba
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Sat Mar 25 00:25:38 2023 +0500

    Merge branch 'master' into 3290-docker-healthcheck

commit e33b0c5cbfe5a28b29734c9ceee046b0f82a0efe
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Fri Mar 24 16:47:26 2023 +0500

    all: fix docs

commit 57bfd898b9c468b2b72eba06294ed5e5e0226c20
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Fri Mar 24 16:44:40 2023 +0500

    dnsforward: add special-use domain handling

commit f04ae13f441a25d0b4dc1359b328552f7507fc23
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Fri Mar 24 16:05:10 2023 +0500

    all: imp code

commit 32f150f88390320d2da85b54e27f6c751eccb851
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Fri Mar 24 04:19:10 2023 +0500

    all: mv Dockerfile, log changes

commit a094a44ccfa26988f0e71f19288e08b26e255e2b
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Fri Mar 24 04:04:27 2023 +0500

    all: finish scripts, imp names

commit 4db0d0e7cb7ed69030994bc1b579534dd2c3395d
Author: Eugene Burkov <E.Burkov@AdGuard.COM>
Date:   Thu Mar 23 18:33:47 2023 +0500

    docker: add script and awk program
This commit is contained in:
Eugene Burkov 2023-03-26 23:12:24 +03:00
parent 0df32601bb
commit d58772f177
8 changed files with 167 additions and 5 deletions

View file

@ -25,6 +25,7 @@ NOTE: Add new changes BELOW THIS COMMENT.
### Added ### Added
- Docker container's healthcheck ([#3290]).
- The new HTTP API `POST /control/protection`, that updates protection state - The new HTTP API `POST /control/protection`, that updates protection state
and adds an optional pause duration ([#1333]). The format of request body and adds an optional pause duration ([#1333]). The format of request body
is described in `openapi/openapi.yaml`. The duration of this pause could is described in `openapi/openapi.yaml`. The duration of this pause could
@ -132,6 +133,7 @@ In this release, the schema version has changed from 17 to 20.
[#1163]: https://github.com/AdguardTeam/AdGuardHome/issues/1163 [#1163]: https://github.com/AdguardTeam/AdGuardHome/issues/1163
[#1333]: https://github.com/AdguardTeam/AdGuardHome/issues/1333 [#1333]: https://github.com/AdguardTeam/AdGuardHome/issues/1333
[#1472]: https://github.com/AdguardTeam/AdGuardHome/issues/1472 [#1472]: https://github.com/AdguardTeam/AdGuardHome/issues/1472
[#3290]: https://github.com/AdguardTeam/AdGuardHome/issues/3290
[#5567]: https://github.com/AdguardTeam/AdGuardHome/issues/5567 [#5567]: https://github.com/AdguardTeam/AdGuardHome/issues/5567
[#5584]: https://github.com/AdguardTeam/AdGuardHome/issues/5584 [#5584]: https://github.com/AdguardTeam/AdGuardHome/issues/5584
[#5631]: https://github.com/AdguardTeam/AdGuardHome/issues/5631 [#5631]: https://github.com/AdguardTeam/AdGuardHome/issues/5631

View file

@ -52,13 +52,20 @@ RUN setcap 'cap_net_bind_service=+eip' /opt/adguardhome/AdGuardHome
# TODO(a.garipov): Remove the old, non-standard 784 and 8853 ports for # TODO(a.garipov): Remove the old, non-standard 784 and 8853 ports for
# DNS-over-QUIC in a future release. # DNS-over-QUIC in a future release.
EXPOSE 53/tcp 53/udp 67/udp 68/udp 80/tcp 443/tcp 443/udp 784/udp\ EXPOSE 53/tcp 53/udp 67/udp 68/udp 80/tcp 443/tcp 443/udp 784/udp\
853/tcp 853/udp 3000/tcp 3000/udp 3001/tcp 3001/udp 5443/tcp\ 853/tcp 853/udp 3000/tcp 3000/udp 5443/tcp\
5443/udp 6060/tcp 8853/udp 5443/udp 6060/tcp 8853/udp
WORKDIR /opt/adguardhome/work WORKDIR /opt/adguardhome/work
# Install helpers for healthcheck.
COPY --chown=nobody:nogroup\
./${DIST_DIR}/docker/scripts\
/opt/adguardhome/scripts
ENTRYPOINT ["/opt/adguardhome/AdGuardHome"] ENTRYPOINT ["/opt/adguardhome/AdGuardHome"]
HEALTHCHECK --interval=30s --timeout=10s --retries=3 CMD [ "/opt/adguardhome/scripts/healthcheck.sh" ]
CMD [ \ CMD [ \
"--no-check-update", \ "--no-check-update", \
"-c", "/opt/adguardhome/conf/AdGuardHome.yaml", \ "-c", "/opt/adguardhome/conf/AdGuardHome.yaml", \

22
docker/dns-bind.awk Normal file
View file

@ -0,0 +1,22 @@
/^[^[:space:]]/ { is_dns = /^dns:/ }
/^[[:space:]]+bind_hosts:/ { if (is_dns) prev_line = FNR }
/^[[:space:]]+- .+/ {
if (FNR - prev_line == 1) {
addrs[addrsnum++] = $2
prev_line = FNR
}
}
/^[[:space:]]+port:/ { if (is_dns) port = $2 }
END {
for (i in addrs) {
if (match(addrs[i], ":")) {
print "[" addrs[i] "]:" port
} else {
print addrs[i] ":" port
}
}
}

83
docker/healthcheck.sh Executable file
View file

@ -0,0 +1,83 @@
#!/bin/sh
# AdGuard Home Docker healthcheck script
# Exit the script if a pipeline fails (-e), prevent accidental filename
# expansion (-f), and consider undefined variables as errors (-u).
set -e -f -u
# Function error_exit is an echo wrapper that writes to stderr and stops the
# script execution with code 1.
error_exit() {
echo "$1" 1>&2
exit 1
}
agh_dir="/opt/adguardhome"
readonly agh_dir
filename="${agh_dir}/conf/AdGuardHome.yaml"
readonly filename
if ! [ -f "$filename" ]
then
wget "http://127.0.0.1:3000" -O /dev/null -q || exit 1
exit 0
fi
help_dir="${agh_dir}/scripts"
readonly help_dir
# Parse web host
web_url="$( awk -f "${help_dir}/web-bind.awk" "$filename" )"
readonly web_url
if [ "$web_url" = '' ]
then
error_exit "no web bindings could be retrieved from $filename"
fi
# TODO(e.burkov): Deal with 0 port.
case "$web_url"
in
(*':0')
error_exit '0 in web port is not supported by healthcheck'
;;
(*)
# Go on.
;;
esac
# Parse DNS hosts
dns_hosts="$( awk -f "${help_dir}/dns-bind.awk" "$filename" )"
readonly dns_hosts
if [ "$dns_hosts" = '' ]
then
error_exit "no DNS bindings could be retrieved from $filename"
fi
# TODO(e.burkov): Deal with 0 port.
case "$( echo "$dns_hosts" | head -n 1 )"
in
(*':0')
error_exit '0 in DNS port is not supported by healthcheck'
;;
(*)
# Go on.
;;
esac
# Check
wget "$web_url" -O /dev/null -q || exit 1
echo "$dns_hosts" | while read -r host
do
nslookup -type=a healthcheck.adguardhome.test. "$host" > /dev/null ||\
error_exit "nslookup failed for $host"
done

23
docker/web-bind.awk Normal file
View file

@ -0,0 +1,23 @@
BEGIN { scheme = "http" }
/^bind_host:/ { host = $2 }
/^bind_port:/ { port = $2 }
/force_https: true$/ { scheme = "https" }
/port_https:/ { https_port = $2 }
/server_name:/ { https_host = $2 }
END {
if (scheme == "https") {
host = https_host
port = https_port
}
if (match(host, ":")) {
print scheme "://[" host "]:" port
} else {
print scheme "://" host ":" port
}
}

View file

@ -184,6 +184,21 @@ func (s *Server) processInitial(dctx *dnsContext) (rc resultCode) {
return resultCodeFinish return resultCodeFinish
} }
// Handle a reserved domain healthcheck.adguardhome.test.
//
// [Section 6.2 of RFC 6761] states that DNS Registries/Registrars must not
// grant requests to register test names in the normal way to any person or
// entity, making domain names under test. TLD free to use in internal
// purposes.
//
// [Section 6.2 of RFC 6761]: https://www.rfc-editor.org/rfc/rfc6761.html#section-6.2
if q.Name == "healthcheck.adguardhome.test." {
// Generate a NODATA negative response to make nslookup exit with 0.
pctx.Res = s.makeResponse(pctx.Req)
return resultCodeFinish
}
// Get the ClientID, if any, before getting client-specific filtering // Get the ClientID, if any, before getting client-specific filtering
// settings. // settings.
var key [8]byte var key [8]byte

View file

@ -36,8 +36,6 @@ func (s *Server) setupDNS64() {
// valid IPv4. It panics, if there are no configured DNS64 prefixes, because // valid IPv4. It panics, if there are no configured DNS64 prefixes, because
// synthesis should not be performed unless DNS64 function enabled. // synthesis should not be performed unless DNS64 function enabled.
func (s *Server) mapDNS64(ip netip.Addr) (mapped net.IP) { func (s *Server) mapDNS64(ip netip.Addr) (mapped net.IP) {
// Don't mask the address here since it should have already been masked on
// initialization stage.
pref := s.dns64Pref.Masked().Addr().As16() pref := s.dns64Pref.Masked().Addr().As16()
ipData := ip.As4() ipData := ip.As4()

View file

@ -87,7 +87,7 @@ readonly docker_image_full_name docker_tags
# Copy the binaries into a new directory under new names, so that it's easier to # Copy the binaries into a new directory under new names, so that it's easier to
# COPY them later. DO NOT remove the trailing underscores. See file # COPY them later. DO NOT remove the trailing underscores. See file
# scripts/make/Dockerfile. # docker/Dockerfile.
dist_docker="${dist_dir}/docker" dist_docker="${dist_dir}/docker"
readonly dist_docker readonly dist_docker
@ -105,6 +105,18 @@ cp "${dist_dir}/AdGuardHome_linux_arm_7/AdGuardHome/AdGuardHome"\
cp "${dist_dir}/AdGuardHome_linux_ppc64le/AdGuardHome/AdGuardHome"\ cp "${dist_dir}/AdGuardHome_linux_ppc64le/AdGuardHome/AdGuardHome"\
"${dist_docker}/AdGuardHome_linux_ppc64le_" "${dist_docker}/AdGuardHome_linux_ppc64le_"
# Copy the helper scripts. See file docker/Dockerfile.
dist_docker_scripts="${dist_docker}/scripts"
readonly dist_docker_scripts
mkdir -p "$dist_docker_scripts"
cp "./docker/dns-bind.awk"\
"${dist_docker_scripts}/dns-bind.awk"
cp "./docker/web-bind.awk"\
"${dist_docker_scripts}/web-bind.awk"
cp "./docker/healthcheck.sh"\
"${dist_docker_scripts}/healthcheck.sh"
# Don't use quotes with $docker_tags and $debug_flags because we want word # Don't use quotes with $docker_tags and $debug_flags because we want word
# splitting and or an empty space if tags are empty. # splitting and or an empty space if tags are empty.
$sudo_cmd docker\ $sudo_cmd docker\
@ -118,5 +130,5 @@ $sudo_cmd docker\
--platform "$docker_platforms"\ --platform "$docker_platforms"\
$docker_tags\ $docker_tags\
-t "$docker_image_full_name"\ -t "$docker_image_full_name"\
-f ./scripts/make/Dockerfile\ -f ./docker/Dockerfile\
. .