fix(dns): preserve 127.0.0.42 during restart and add local DNS cache support
- decouple restart() from stop_impl() in lifecycle.uc to avoid premature dnsmasq_restore - keep dhcp.@dnsmasq[0].server locked to 127.0.0.42 throughout service restarts - add atomic restart_service hooks in init.d/tachyon and initd.uc - fix dns_turbo_cache path resolution to promote default cache to /etc/sing-box/cache.db - add Local DNS Cache support in dnsmasq (dns_local_cache, dns_cache_size) - add comprehensive behavioral regression test tests/service_restart_lifecycle.sh
This commit is contained in:
+274
-246
File diff suppressed because it is too large
Load Diff
+264
-248
File diff suppressed because it is too large
Load Diff
@@ -7,8 +7,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: TACHYON\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-09-17 08:13+0300\n"
|
||||
"PO-Revision-Date: 2026-09-17 08:13+0300\n"
|
||||
"POT-Creation-Date: 2026-09-17 08:45+0300\n"
|
||||
"PO-Revision-Date: 2026-09-17 08:45+0300\n"
|
||||
"Last-Translator: Dushnilin\n"
|
||||
"Language-Team: none\n"
|
||||
"Language: ru\n"
|
||||
@@ -1439,6 +1439,9 @@ msgstr "Автоподбор и бенчмарк DNS"
|
||||
msgid "DNS Blocking"
|
||||
msgstr "Блокировка DNS"
|
||||
|
||||
msgid "DNS Cache Size"
|
||||
msgstr ""
|
||||
|
||||
msgid "DNS Check Interval"
|
||||
msgstr "Интервал проверки DNS"
|
||||
|
||||
@@ -1793,6 +1796,9 @@ msgstr "Включено"
|
||||
msgid "Enabled (always prioritize)"
|
||||
msgstr "Включено (всегда повышать приоритет)"
|
||||
|
||||
msgid "Enables high-capacity local DNS caching in dnsmasq to accelerate DNS queries and absorb transient latency during service restarts."
|
||||
msgstr ""
|
||||
|
||||
msgid "Enables the background daemon that polls Telegram for commands and sends notifications."
|
||||
msgstr "Включает фоновый демон, который опрашивает Telegram на наличие команд и отправляет уведомления."
|
||||
|
||||
@@ -3095,6 +3101,9 @@ msgstr "Загрузка..."
|
||||
msgid "Local Address"
|
||||
msgstr "Локальный адрес"
|
||||
|
||||
msgid "Local DNS Cache"
|
||||
msgstr ""
|
||||
|
||||
msgid "Local SOCKS proxy desynchronizer (ciadpi)"
|
||||
msgstr "Локальный десинхронизатор SOCKS-прокси (ciadpi)"
|
||||
|
||||
@@ -3470,6 +3479,9 @@ msgstr "Уведомлять о перезапусках сервиса"
|
||||
msgid "Notify on Subscription Updates"
|
||||
msgstr "Уведомлять об обновлениях подписок"
|
||||
|
||||
msgid "Number of cached DNS domain entries in dnsmasq (default: 10000)."
|
||||
msgstr ""
|
||||
|
||||
msgid "Number of consecutive failed checks required before switching DNS servers."
|
||||
msgstr "Количество последовательных неудачных проверок до переключения DNS-серверов."
|
||||
|
||||
|
||||
@@ -476,6 +476,8 @@ export namespace Tachyon {
|
||||
smart_detect_section?: string;
|
||||
smart_detect_sections?: string | string[];
|
||||
dns_turbo_cache?: '0' | '1';
|
||||
dns_local_cache?: '0' | '1';
|
||||
dns_cache_size?: string;
|
||||
// AI Watchdog settings (introduced in AI Watchdog feature)
|
||||
ai_proxy_health_enabled?: '0' | '1';
|
||||
ai_proxy_health_interval?: string;
|
||||
|
||||
@@ -1853,6 +1853,30 @@ function createSettingsContent(section, capabilities) {
|
||||
o.default = "0";
|
||||
o.rmempty = false;
|
||||
|
||||
o = section.taboption(
|
||||
"dns",
|
||||
form.Flag,
|
||||
"dns_local_cache",
|
||||
_("Local DNS Cache"),
|
||||
_(
|
||||
"Enables high-capacity local DNS caching in dnsmasq to accelerate DNS queries and absorb transient latency during service restarts.",
|
||||
),
|
||||
);
|
||||
o.default = "0";
|
||||
o.rmempty = false;
|
||||
|
||||
o = section.taboption(
|
||||
"dns",
|
||||
form.Value,
|
||||
"dns_cache_size",
|
||||
_("DNS Cache Size"),
|
||||
_("Number of cached DNS domain entries in dnsmasq (default: 10000)."),
|
||||
);
|
||||
o.depends("dns_local_cache", "1");
|
||||
o.default = "10000";
|
||||
o.datatype = "uinteger";
|
||||
o.rmempty = true;
|
||||
|
||||
// ─── DNS Strategy ────────────────────────────────────────────────────────
|
||||
|
||||
o = section.taboption(
|
||||
|
||||
@@ -7,8 +7,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: TACHYON\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-09-17 08:13+0300\n"
|
||||
"PO-Revision-Date: 2026-09-17 08:13+0300\n"
|
||||
"POT-Creation-Date: 2026-09-17 08:45+0300\n"
|
||||
"PO-Revision-Date: 2026-09-17 08:45+0300\n"
|
||||
"Last-Translator: Dushnilin\n"
|
||||
"Language-Team: none\n"
|
||||
"Language: ru\n"
|
||||
@@ -1439,6 +1439,9 @@ msgstr "Автоподбор и бенчмарк DNS"
|
||||
msgid "DNS Blocking"
|
||||
msgstr "Блокировка DNS"
|
||||
|
||||
msgid "DNS Cache Size"
|
||||
msgstr ""
|
||||
|
||||
msgid "DNS Check Interval"
|
||||
msgstr "Интервал проверки DNS"
|
||||
|
||||
@@ -1793,6 +1796,9 @@ msgstr "Включено"
|
||||
msgid "Enabled (always prioritize)"
|
||||
msgstr "Включено (всегда повышать приоритет)"
|
||||
|
||||
msgid "Enables high-capacity local DNS caching in dnsmasq to accelerate DNS queries and absorb transient latency during service restarts."
|
||||
msgstr ""
|
||||
|
||||
msgid "Enables the background daemon that polls Telegram for commands and sends notifications."
|
||||
msgstr "Включает фоновый демон, который опрашивает Telegram на наличие команд и отправляет уведомления."
|
||||
|
||||
@@ -3095,6 +3101,9 @@ msgstr "Загрузка..."
|
||||
msgid "Local Address"
|
||||
msgstr "Локальный адрес"
|
||||
|
||||
msgid "Local DNS Cache"
|
||||
msgstr ""
|
||||
|
||||
msgid "Local SOCKS proxy desynchronizer (ciadpi)"
|
||||
msgstr "Локальный десинхронизатор SOCKS-прокси (ciadpi)"
|
||||
|
||||
@@ -3470,6 +3479,9 @@ msgstr "Уведомлять о перезапусках сервиса"
|
||||
msgid "Notify on Subscription Updates"
|
||||
msgstr "Уведомлять об обновлениях подписок"
|
||||
|
||||
msgid "Number of cached DNS domain entries in dnsmasq (default: 10000)."
|
||||
msgstr ""
|
||||
|
||||
msgid "Number of consecutive failed checks required before switching DNS servers."
|
||||
msgstr "Количество последовательных неудачных проверок до переключения DNS-серверов."
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -48,6 +48,8 @@ config settings 'settings'
|
||||
#option p2p_ports 'tcp:6881,udp:6881-6889'
|
||||
option config_path '/etc/sing-box/config.json'
|
||||
option cache_path '/tmp/sing-box/cache.db'
|
||||
option dns_local_cache '0'
|
||||
option dns_cache_size '10000'
|
||||
option log_level 'warn'
|
||||
option exclude_ntp '0'
|
||||
option shutdown_correctly '0'
|
||||
|
||||
@@ -46,6 +46,16 @@ stop_service() {
|
||||
trap - INT TERM
|
||||
}
|
||||
|
||||
restart_service() {
|
||||
trap 'exit 1' INT TERM
|
||||
initd_ucode restart-service "$$"
|
||||
trap - INT TERM
|
||||
}
|
||||
|
||||
restart() {
|
||||
restart_service "$@"
|
||||
}
|
||||
|
||||
reload_service() {
|
||||
local reason="$1"
|
||||
local result status
|
||||
|
||||
@@ -120,10 +120,18 @@ function dnsmasq_management_disabled() {
|
||||
return truthy(uci_get(CONFIG_NAME + ".settings.dont_touch_dhcp"));
|
||||
}
|
||||
|
||||
function dnsmasq_target_cachesize() {
|
||||
if (truthy(uci_get(CONFIG_NAME + ".settings.dns_local_cache"))) {
|
||||
let size = uci_get(CONFIG_NAME + ".settings.dns_cache_size");
|
||||
return (size != null && size != "") ? as_string(size) : "10000";
|
||||
}
|
||||
return "0";
|
||||
}
|
||||
|
||||
function dnsmasq_default_config_is_complete() {
|
||||
return dnsmasq_default_has_tachyon_dns() &&
|
||||
uci_get("dhcp.@dnsmasq[0].noresolv") == "1" &&
|
||||
uci_get("dhcp.@dnsmasq[0].cachesize") == "0" &&
|
||||
uci_get("dhcp.@dnsmasq[0].cachesize") == dnsmasq_target_cachesize() &&
|
||||
!dnsmasq_legacy_instance_exists();
|
||||
}
|
||||
|
||||
@@ -209,7 +217,7 @@ function dnsmasq_configure_default_instance() {
|
||||
uci_delete("dhcp.@dnsmasq[0].server");
|
||||
uci_add_list("dhcp.@dnsmasq[0].server", SB_DNS_INBOUND_ADDRESS);
|
||||
uci_set("dhcp.@dnsmasq[0].noresolv", "1");
|
||||
uci_set("dhcp.@dnsmasq[0].cachesize", "0");
|
||||
uci_set("dhcp.@dnsmasq[0].cachesize", dnsmasq_target_cachesize());
|
||||
}
|
||||
|
||||
function dnsmasq_restore_default_instance() {
|
||||
|
||||
@@ -647,6 +647,26 @@ function stop_service(owner_pid) {
|
||||
return stop_finish(job_id, status);
|
||||
}
|
||||
|
||||
function restart_service(owner_pid) {
|
||||
clear_start_retry(START_RETRY_FILE);
|
||||
cancel_scheduled_start_retry(START_RETRY_PID_FILE);
|
||||
let job_id = begin_external_service_action("restart", "initd", owner_pid);
|
||||
if (!file_executable(BIN_PATH)) {
|
||||
restore_dnsmasq_failsafe();
|
||||
finish_external_service_action("restart", job_id, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
let status = command_status_from_args([ BIN_PATH, "restart" ]);
|
||||
if (status != 0) {
|
||||
mark_start_retry(START_RETRY_FILE, "restart_failed");
|
||||
schedule_start_retry(START_RETRY_PID_FILE, START_RETRY_DELAY_SECONDS);
|
||||
command_success_from_args([ "logger", "-t", SERVICE_NAME, "[warn] Tachyon restart failed; scheduled an automatic retry" ]);
|
||||
}
|
||||
finish_external_service_action("restart", job_id, status);
|
||||
return status;
|
||||
}
|
||||
|
||||
function reload_begin_value(reason, owner_pid, runtime_running_value, service_enabled_value, active_service_action) {
|
||||
reason = as_string(reason);
|
||||
|
||||
@@ -817,6 +837,8 @@ else if (mode == "stop-finish")
|
||||
exit(stop_finish(ARGV[1], ARGV[2]));
|
||||
else if (mode == "stop-service")
|
||||
exit(stop_service(ARGV[1]));
|
||||
else if (mode == "restart-service")
|
||||
exit(restart_service(ARGV[1]));
|
||||
else if (mode == "reload-begin")
|
||||
exit(reload_begin(ARGV[1], ARGV[2], null, null));
|
||||
else if (mode == "reload-begin-fixture") {
|
||||
|
||||
@@ -1627,7 +1627,9 @@ function restart() {
|
||||
log_message("Restarting Tachyon", "info");
|
||||
|
||||
let selector_state = capture_selector_state();
|
||||
let status = stop_impl();
|
||||
invalidate_reload_hash();
|
||||
|
||||
let status = stop_main();
|
||||
if (status != 0)
|
||||
return status;
|
||||
|
||||
@@ -1637,6 +1639,17 @@ function restart() {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = module_status(STATE_UC, [
|
||||
"wait-sing-box-service-stable",
|
||||
as_string(SING_BOX_START_STABLE_MIN_AGE),
|
||||
as_string(SING_BOX_START_VERIFY_TIMEOUT)
|
||||
]);
|
||||
if (status != 0) {
|
||||
log_message("Restart verification failed after Tachyon was started; rolling back DNS changes", "fatal");
|
||||
cleanup_failed_runtime();
|
||||
return status;
|
||||
}
|
||||
|
||||
if (module_success(STATE_UC, [
|
||||
"tachyon-stably-running",
|
||||
RT_TABLE_NAME,
|
||||
|
||||
@@ -453,7 +453,9 @@ function base_config(settings, service_address, runtime_context) {
|
||||
let log_level = option(settings, "log_level", "warn");
|
||||
let rewrite_ttl = int_option(settings, "dns_rewrite_ttl", "60");
|
||||
let turbo_cache = bool_option(settings, "dns_turbo_cache", false);
|
||||
let cache_path = option(settings, "cache_path", turbo_cache ? "/etc/sing-box/cache.db" : "/tmp/sing-box/cache.db");
|
||||
let cache_path = option(settings, "cache_path", "/tmp/sing-box/cache.db");
|
||||
if (turbo_cache && (cache_path == "/tmp/sing-box/cache.db" || cache_path == ""))
|
||||
cache_path = "/etc/sing-box/cache.db";
|
||||
let cache_dir = replace(cache_path, /\/[^\/]+$/, "");
|
||||
if (cache_dir != "" && cache_dir != cache_path) {
|
||||
try { fs.mkdir(cache_dir, 0755); } catch(e) {}
|
||||
|
||||
@@ -0,0 +1,202 @@
|
||||
#!/usr/bin/env bash
|
||||
set -eo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
TACHYON_BIN="$ROOT_DIR/tachyon/files/usr/bin/tachyon"
|
||||
TACHYON_INIT="$ROOT_DIR/tachyon/files/etc/init.d/tachyon"
|
||||
LIFECYCLE_UC="$ROOT_DIR/tachyon/files/usr/lib/service/lifecycle.uc"
|
||||
INITD_UC="$ROOT_DIR/tachyon/files/usr/lib/service/initd.uc"
|
||||
APPLY_UC="$ROOT_DIR/tachyon/files/usr/lib/dns/apply.uc"
|
||||
GENERATOR_UC="$ROOT_DIR/tachyon/files/usr/lib/singbox/generator.uc"
|
||||
|
||||
fail() {
|
||||
printf 'FAIL: %s\n' "$1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# --- 1. Static assertions on lifecycle.uc restart() -------------------------
|
||||
awk '
|
||||
/function restart\(\)/ { in_restart = 1 }
|
||||
in_restart && /stop_impl\(\)/ { called_stop_impl = 1 }
|
||||
in_restart && /stop_main\(\)/ { called_stop_main = 1 }
|
||||
in_restart && /start_impl\(\)/ { called_start_impl = 1 }
|
||||
in_restart && /capture_selector_state\(\)/ { captured_selector = 1 }
|
||||
in_restart && /restore_selector_state\(selector_state\)/ { restored_selector = 1 }
|
||||
in_restart && /cleanup_failed_runtime\(\)/ { cleaned_on_failure = 1 }
|
||||
in_restart && /^}/ { done = 1; exit }
|
||||
END {
|
||||
if (!done) exit 1
|
||||
if (called_stop_impl) { print "restart() must not call stop_impl()"; exit 2 }
|
||||
if (!called_stop_main) { print "restart() must call stop_main()"; exit 3 }
|
||||
if (!called_start_impl) { print "restart() must call start_impl()"; exit 4 }
|
||||
if (!captured_selector) { print "restart() must capture selector state"; exit 5 }
|
||||
if (!restored_selector) { print "restart() must restore selector state"; exit 6 }
|
||||
if (!cleaned_on_failure) { print "restart() must call cleanup_failed_runtime on failure"; exit 7 }
|
||||
exit 0
|
||||
}
|
||||
' "$LIFECYCLE_UC" || fail "restart() in lifecycle.uc failed structural verification"
|
||||
|
||||
# Verify stop() still calls stop_impl()
|
||||
awk '
|
||||
/function stop\(\)/ { in_stop = 1 }
|
||||
in_stop && /return stop_impl\(\);/ { called_stop_impl = 1 }
|
||||
in_stop && /^}/ { done = 1; exit }
|
||||
END {
|
||||
if (!done || !called_stop_impl) exit 1
|
||||
exit 0
|
||||
}
|
||||
' "$LIFECYCLE_UC" || fail "stop() in lifecycle.uc must still call stop_impl()"
|
||||
|
||||
# --- 2. Static assertions on init.d script -----------------------------------
|
||||
grep -Fq 'restart_service()' "$TACHYON_INIT" ||
|
||||
fail "/etc/init.d/tachyon must define restart_service()"
|
||||
|
||||
grep -Fq 'initd_ucode restart-service "$$"' "$TACHYON_INIT" ||
|
||||
fail "/etc/init.d/tachyon restart_service() must invoke initd_ucode restart-service"
|
||||
|
||||
awk '
|
||||
/restart\(\)/ { in_restart = 1 }
|
||||
in_restart && /restart_service "\$@"/ { delegates = 1 }
|
||||
in_restart && /^}/ { done = 1; exit }
|
||||
END { exit (done && delegates) ? 0 : 1 }
|
||||
' "$TACHYON_INIT" || fail "/etc/init.d/tachyon restart() must delegate to restart_service"
|
||||
|
||||
# --- 3. Static assertions on initd.uc ----------------------------------------
|
||||
grep -Fq 'function restart_service(owner_pid)' "$INITD_UC" ||
|
||||
fail "initd.uc must define restart_service(owner_pid)"
|
||||
|
||||
grep -Fq 'else if (mode == "restart-service")' "$INITD_UC" ||
|
||||
fail "initd.uc must handle restart-service command"
|
||||
|
||||
awk '
|
||||
/function restart_service\(owner_pid\)/ { in_func = 1 }
|
||||
in_func && /BIN_PATH, "restart"/ { called_bin_restart = 1 }
|
||||
in_func && /^}/ { done = 1; exit }
|
||||
END { exit (done && called_bin_restart) ? 0 : 1 }
|
||||
' "$INITD_UC" || fail "initd.uc restart_service must invoke [ BIN_PATH, 'restart' ]"
|
||||
|
||||
# --- 4. Static assertions on generator.uc turbo cache ------------------------
|
||||
awk '
|
||||
/let turbo_cache = bool_option\(settings, "dns_turbo_cache", false\);/ { in_turbo = 1 }
|
||||
in_turbo && index($0, "cache_path = \"/etc/sing-box/cache.db\"") { uses_etc = 1 }
|
||||
in_turbo && index($0, "turbo_cache &&") { promotes = 1 }
|
||||
in_turbo && /cache_dir/ { done = 1; exit }
|
||||
END { exit (promotes && uses_etc) ? 0 : 1 }
|
||||
' "$GENERATOR_UC" || fail "generator.uc must promote default cache_path to /etc/sing-box/cache.db when dns_turbo_cache is enabled"
|
||||
|
||||
# --- 5. Behavioral test: dnsmasq server remains 127.0.0.42 during restart ---
|
||||
WORK_DIR="$(mktemp -d)"
|
||||
STATE="$WORK_DIR/uci.state"
|
||||
LOG="$WORK_DIR/dnsmasq_mutations.log"
|
||||
|
||||
cleanup() {
|
||||
rm -rf "$WORK_DIR"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
# Initial UCI state: Tachyon running, dnsmasq points to 127.0.0.42
|
||||
cat >"$STATE" <<'EOF_STATE'
|
||||
dhcp.@dnsmasq[0].server=127.0.0.42
|
||||
dhcp.@dnsmasq[0].noresolv=1
|
||||
dhcp.@dnsmasq[0].cachesize=0
|
||||
dhcp.@dnsmasq[0].tachyon_server=1.1.1.1 8.8.8.8
|
||||
dhcp.@dnsmasq[0].tachyon_noresolv=0
|
||||
dhcp.@dnsmasq[0].tachyon_cachesize=150
|
||||
tachyon.settings.shutdown_correctly=0
|
||||
tachyon.settings.dont_touch_dhcp=0
|
||||
EOF_STATE
|
||||
|
||||
mkdir -p "$WORK_DIR/bin"
|
||||
cat >"$WORK_DIR/bin/uci" <<'UCI'
|
||||
#!/usr/bin/env bash
|
||||
set -eo pipefail
|
||||
while [ "${1:-}" = "-q" ]; do shift; done
|
||||
cmd="${1:-}"
|
||||
shift || true
|
||||
state="${UCI_STATE:?}"
|
||||
log="${MUTATION_LOG:?}"
|
||||
|
||||
do_set() {
|
||||
local key="$1"
|
||||
local val="${key#*=}"
|
||||
local var="${key%%=*}"
|
||||
printf 'SET %s=%s\n' "$var" "$val" >> "$log"
|
||||
local tmp
|
||||
tmp="$(mktemp)"
|
||||
awk -F= -v k="$var" '$1 != k' "$state" > "$tmp"
|
||||
printf '%s=%s\n' "$var" "$val" >> "$tmp"
|
||||
mv "$tmp" "$state"
|
||||
}
|
||||
|
||||
do_del() {
|
||||
printf 'DELETE %s\n' "$1" >> "$log"
|
||||
local tmp
|
||||
tmp="$(mktemp)"
|
||||
awk -F= -v k="$1" '$1 != k' "$state" > "$tmp"
|
||||
mv "$tmp" "$state"
|
||||
}
|
||||
|
||||
case "$cmd" in
|
||||
get)
|
||||
awk -F= -v key="$1" '$1 == key { print substr($0, length($1) + 2); found = 1 } END { exit found ? 0 : 1 }' "$state"
|
||||
;;
|
||||
set)
|
||||
do_set "$1"
|
||||
;;
|
||||
delete)
|
||||
do_del "$1"
|
||||
;;
|
||||
add_list)
|
||||
printf 'ADD_LIST %s %s\n' "$1" "$2" >> "$log"
|
||||
;;
|
||||
commit)
|
||||
printf 'COMMIT %s\n' "$1" >> "$log"
|
||||
;;
|
||||
esac
|
||||
UCI
|
||||
chmod +x "$WORK_DIR/bin/uci"
|
||||
|
||||
cat >"$WORK_DIR/bin/dnsmasq_init" <<'SH'
|
||||
#!/usr/bin/env bash
|
||||
exit 0
|
||||
SH
|
||||
chmod +x "$WORK_DIR/bin/dnsmasq_init"
|
||||
export DNSMASQ_INIT="$WORK_DIR/bin/dnsmasq_init"
|
||||
|
||||
# Run dnsmasq_configure while service is active (as called by restart -> start_impl)
|
||||
export UCI_STATE="$STATE"
|
||||
export MUTATION_LOG="$LOG"
|
||||
export PATH="$WORK_DIR/bin:$PATH"
|
||||
: > "$LOG"
|
||||
|
||||
ucode -L "$ROOT_DIR/tachyon/files/usr/lib" "$APPLY_UC" configure ||
|
||||
fail "dnsmasq_configure should succeed when dnsmasq already points to sing-box"
|
||||
|
||||
# Verify that no deletion of 127.0.0.42 or restoration of 1.1.1.1 occurred
|
||||
if grep -Eq 'SET dhcp\.@dnsmasq\[0\]\.server=1\.1\.1\.1|ADD_LIST dhcp\.@dnsmasq\[0\]\.server 1\.1\.1\.1' "$LOG"; then
|
||||
fail "dnsmasq_configure reverted server to ISP DNS during restart!"
|
||||
fi
|
||||
|
||||
current_server="$(awk -F= '$1 == "dhcp.@dnsmasq[0].server" { print $2 }' "$STATE")"
|
||||
[ "$current_server" = "127.0.0.42" ] ||
|
||||
fail "dhcp.@dnsmasq[0].server must remain 127.0.0.42 throughout restart (was: $current_server)"
|
||||
|
||||
# --- 6. Behavioral test: Local DNS Cache enables 10000 entries in dnsmasq ---
|
||||
printf 'tachyon.settings.dns_local_cache=1\n' >> "$STATE"
|
||||
ucode -L "$ROOT_DIR/tachyon/files/usr/lib" "$APPLY_UC" configure force ||
|
||||
fail "dnsmasq_configure force should apply local cache"
|
||||
|
||||
cachesize="$(awk -F= '$1 == "dhcp.@dnsmasq[0].cachesize" { print $2 }' "$STATE")"
|
||||
[ "$cachesize" = "10000" ] ||
|
||||
fail "dhcp.@dnsmasq[0].cachesize should be 10000 when dns_local_cache is enabled (was: $cachesize)"
|
||||
|
||||
# --- 7. Behavioral test: Stop restores ISP DNS --------------------------------
|
||||
ucode -L "$ROOT_DIR/tachyon/files/usr/lib" "$APPLY_UC" restore force ||
|
||||
fail "dnsmasq_restore force should succeed on service stop"
|
||||
|
||||
restored_server="$(awk -F= '$1 == "dhcp.@dnsmasq[0].server" { print $2 }' "$STATE")"
|
||||
[ "$restored_server" = "1.1.1.1 8.8.8.8" ] ||
|
||||
fail "dhcp.@dnsmasq[0].server must be restored to ISP DNS on stop (was: $restored_server)"
|
||||
|
||||
printf 'service restart lifecycle checks passed\n'
|
||||
|
||||
Reference in New Issue
Block a user