Effective config, hosts/addn-hosts logic, test harness status & logs

- EffectiveDnsmasqConfig: overridable single-value options (no-hosts, addn-hosts,
  flags, dhcp-leasefile, cache-size, port, etc.) from dnsmasq source/docs.
- Hosts UI: allow editing when no-hosts but SystemHostsPath is in addn-hosts;
  HostsController and Hosts.razor check pathInAddnHosts.
- Config comments: managed file ensures one addn-hosts line in our file only;
  DnsmasqOptions/validator docs for SystemHostsPath and addn-hosts.
- Test harness: dnsmasq logs to /data/dnsmasq.log (log-facility + log-queries in
  dnsmasq-test.conf); entrypoint touches log file for write access.
- dnsmasq-status.sh: simulates systemctl status output in container (ps/pgrep);
  Dockerfile copies and chmod +x; StatusShowCommand/LogsCommand use script and
  tail /data/dnsmasq.log.
- Project: Models/Config namespace, typed HTTP clients, combined DHCP+Leases
  page, ProcessRunner, shared models (PascalCase).
This commit is contained in:
2026-02-01 01:17:32 +10:00
parent 5bd9eaf55d
commit d0391ef058
64 changed files with 1184 additions and 512 deletions
+31
View File
@@ -0,0 +1,31 @@
#!/bin/sh
# Simulates "systemctl status dnsmasq" output when run in a container without systemd.
# Uses ps/pgrep so the UI looks familiar. Usage: dnsmasq-status.sh
pid=$(pgrep -x dnsmasq)
if [ -z "$pid" ]; then
echo "● dnsmasq.service - dnsmasq - A lightweight DHCP and caching DNS server"
echo " Loaded: (container, no systemd)"
echo " Active: inactive (dead)"
echo ""
exit 0
fi
# One ps + awk: parse pid,user,etime,rss,args and print systemctl-style (rss in KB -> MB)
ps -o pid=,user=,etime=,rss=,args= -p "$pid" 2>/dev/null | awk '{
pid=$1; user=$2; etime=$3; rss=$4
args=""
for (i=5;i<=NF;i++) args = args (i>5?" ":"") $i
rss_mb = (rss+0) / 1024
if (rss_mb < 0.1) rss_mb = 0.0
printf "● dnsmasq.service - dnsmasq - A lightweight DHCP and caching DNS server\n"
printf " Loaded: loaded (container, no systemd)\n"
printf " Active: active (running) since container start\n"
printf " Main PID: %s (dnsmasq)\n", pid
printf " Tasks: 1 (limit: unknown)\n"
printf " Memory: %.1fM\n", rss_mb
printf " CPU: %s\n", etime
printf " CGroup: (container)\n"
printf " └─%s %s\n", pid, args
}'
exit 0
+2
View File
@@ -2,6 +2,8 @@
# If DNSMASQ_CONF is set, run dnsmasq in the background (same container as the app).
# Container main process is the app (exec below).
if [ -n "$DNSMASQ_CONF" ]; then
# Ensure dnsmasq log file exists and is writable (dnsmasq may drop to dnsmasq user)
touch /data/dnsmasq.log 2>/dev/null && chmod a+rw /data/dnsmasq.log 2>/dev/null || true
dnsmasq -k --conf-file="$DNSMASQ_CONF" &
fi
exec dotnet DnsmasqWebUI.dll
+3 -4
View File
@@ -27,7 +27,7 @@ usage() {
echo ""
echo "Prepare the testdata mount directory and optionally start the Docker test harness"
echo "(app with dnsmasq in one container, plus a DHCP client). The mount is synced from"
echo "testdata/ by default; 'leases' is excluded so dnsmasq creates the real leases file."
echo "testdata/ by default (includes sample leases file so the harness shows leases)."
echo ""
echo "Steps:"
echo " 1. Clear mount dir (unless --no-clear), then sync source -> mount."
@@ -176,16 +176,15 @@ if [ "$NO_CLEAR" = false ]; then
fi
if command -v rsync >/dev/null 2>&1; then
rsync -a --exclude=leases "$SOURCE_DIR/" "$MOUNT_DIR/"
rsync -a "$SOURCE_DIR/" "$MOUNT_DIR/"
else
cp -r "$SOURCE_DIR/." "$MOUNT_DIR/"
rm -f "$MOUNT_DIR/leases"
fi
# Remove any leftover managed config from previous runs so dnsmasq starts clean (app will create zz-dnsmasq-webui.conf on startup).
find "$MOUNT_DIR" -name '*dnsmasq-webui*.conf' -type f -delete 2>/dev/null || true
echo "Mount directory ready: $MOUNT_DIR (source: $SOURCE_DIR, leases excluded)."
echo "Mount directory ready: $MOUNT_DIR (source: $SOURCE_DIR)."
if [ "$PREPARE_ONLY" = true ]; then
echo "To start the harness: TESTDATA_MOUNT=./$MOUNT_DIR docker compose -f $COMPOSE_FILE up -d --build"