fix(tailscale): готовность демона, флаги tailscaled и нейтрализация standalone-сервиса
- удалён неподдерживаемый флаг --netfilter-mode=on, вызывавший ошибку старта на OpenWrt - проба готовности парсит status --json (BackendState), а не exit-code: незалогиненный узел отвечает NeedsLogin с non-zero и раньше считался неготовым — корень «did not become ready» при первом входе - перед стартом своего tailscaled останавливается и отключается init-скрипт официального пакета: его демон держал UDP 41641, из-за чего наш умирал мгновенно - при сбое старта в лог пишется хвост tailscaled.log для диагностики
This commit is contained in:
@@ -310,12 +310,46 @@ function install_kernel_routing(section) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The official package ships its own init script; if it autostarted at boot,
|
||||||
|
// its daemon holds UDP 41641 and ours dies instantly. Neutralize it the same
|
||||||
|
// way component install does - stop + disable, idempotent.
|
||||||
|
function file_executable(path) {
|
||||||
|
let st = fs.stat(path);
|
||||||
|
return st != null && st.mode != null && (int(st.mode) & 73) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function neutralize_standalone_service() {
|
||||||
|
let init = "/etc/init.d/tailscale";
|
||||||
|
if (!file_executable(init))
|
||||||
|
return;
|
||||||
|
command_status(command_from_args([ init, "stop" ]) + " >/dev/null 2>&1");
|
||||||
|
command_status(command_from_args([ init, "disable" ]) + " >/dev/null 2>&1");
|
||||||
|
log_message("standalone tailscale service stopped and disabled", "info");
|
||||||
|
}
|
||||||
|
|
||||||
|
function log_file_tail(path) {
|
||||||
|
let data = "";
|
||||||
|
try {
|
||||||
|
data = as_string(fs.readfile(path)) || "";
|
||||||
|
} catch (e) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
let lines = split(trim(data), "\n");
|
||||||
|
let start = length(lines) > 5 ? length(lines) - 5 : 0;
|
||||||
|
let tail = [];
|
||||||
|
for (let i = start; i < length(lines); i++)
|
||||||
|
push(tail, lines[i]);
|
||||||
|
return join(" | ", tail);
|
||||||
|
}
|
||||||
|
|
||||||
function start_daemon(section) {
|
function start_daemon(section) {
|
||||||
if (running_pid(section)) {
|
if (running_pid(section)) {
|
||||||
log_message("tailscaled for " + section_name(section) + " already running", "debug");
|
log_message("tailscaled for " + section_name(section) + " already running", "debug");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
neutralize_standalone_service();
|
||||||
|
|
||||||
let runtime_dir = section_runtime_dir(section);
|
let runtime_dir = section_runtime_dir(section);
|
||||||
let socket_path = runtime_dir + "/tailscaled.sock";
|
let socket_path = runtime_dir + "/tailscaled.sock";
|
||||||
let log_file = runtime_dir + "/tailscaled.log";
|
let log_file = runtime_dir + "/tailscaled.log";
|
||||||
@@ -326,10 +360,10 @@ function start_daemon(section) {
|
|||||||
"--tun=tailscale0",
|
"--tun=tailscale0",
|
||||||
"--statedir=" + state_dir,
|
"--statedir=" + state_dir,
|
||||||
"--socket=" + socket_path,
|
"--socket=" + socket_path,
|
||||||
"--port=" + TAILSCALED_PORT,
|
"--port=" + TAILSCALED_PORT
|
||||||
"--netfilter-mode=on"
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
fs.unlink(log_file);
|
||||||
let cmdline = command_from_args(args) +
|
let cmdline = command_from_args(args) +
|
||||||
" >" + shell_quote(log_file) + " 2>&1 </dev/null & echo $!";
|
" >" + shell_quote(log_file) + " 2>&1 </dev/null & echo $!";
|
||||||
let output = trim(command_output(cmdline));
|
let output = trim(command_output(cmdline));
|
||||||
@@ -340,15 +374,24 @@ function start_daemon(section) {
|
|||||||
}
|
}
|
||||||
write_file(section_pid_file(section), as_string(pid));
|
write_file(section_pid_file(section), as_string(pid));
|
||||||
|
|
||||||
// Wait until the client socket answers before running `up`.
|
// Wait until the client socket answers before running `up`. Probe parses
|
||||||
|
// JSON instead of trusting the exit code: an unlogged-in node answers
|
||||||
|
// with BackendState=NeedsLogin and a non-zero exit code, which must still
|
||||||
|
// count as "daemon ready".
|
||||||
for (let attempt = 0; attempt < 30; attempt++) {
|
for (let attempt = 0; attempt < 30; attempt++) {
|
||||||
if (command_success_from_args([ TAILSCALE_BIN, "--socket", socket_path, "status", "--peers=false" ]))
|
let probe = command_output_from_args([ TAILSCALE_BIN, "--socket", socket_path, "status", "--json", "--peers=false" ]);
|
||||||
|
if (index(as_string(probe), "\"BackendState\"") >= 0)
|
||||||
return true;
|
return true;
|
||||||
if (!pid_alive(pid))
|
if (!pid_alive(pid))
|
||||||
break;
|
break;
|
||||||
command_success_from_args([ "sleep", "1" ]);
|
command_success_from_args([ "sleep", "1" ]);
|
||||||
}
|
}
|
||||||
log_message("tailscaled did not become ready for " + section_name(section), "warn");
|
|
||||||
|
let tail = log_file_tail(log_file);
|
||||||
|
if (!pid_alive(pid))
|
||||||
|
log_message("tailscaled for " + section_name(section) + " exited during startup; log tail: " + (tail == "" ? "<empty>" : tail), "warn");
|
||||||
|
else
|
||||||
|
log_message("tailscaled did not become ready for " + section_name(section) + "; log tail: " + (tail == "" ? "<empty>" : tail), "warn");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -89,7 +89,19 @@ run() {
|
|||||||
run installed || fail "installed must succeed with stubs present"
|
run installed || fail "installed must succeed with stubs present"
|
||||||
|
|
||||||
# --- start ------------------------------------------------------------------
|
# --- start ------------------------------------------------------------------
|
||||||
|
# Fake official init script: must be stopped+disabled before our daemon starts.
|
||||||
|
INIT_LOG="$WORK_DIR/init.log"
|
||||||
|
mkdir -p /etc/init.d
|
||||||
|
cat >"/etc/init.d/tailscale" <<EOF
|
||||||
|
#!/bin/sh
|
||||||
|
printf '%s\n' "\$*" >> '$INIT_LOG'
|
||||||
|
exit 0
|
||||||
|
EOF
|
||||||
|
chmod +x "/etc/init.d/tailscale"
|
||||||
|
|
||||||
run start-runtime || fail "start-runtime exited non-zero"
|
run start-runtime || fail "start-runtime exited non-zero"
|
||||||
|
grep -Fq "stop" "$INIT_LOG" || fail "standalone tailscale service was not stopped"
|
||||||
|
grep -Fq "disable" "$INIT_LOG" || fail "standalone tailscale service was not disabled"
|
||||||
|
|
||||||
PID_FILE="$WORK_DIR/run/ts_native/tailscaled.pid"
|
PID_FILE="$WORK_DIR/run/ts_native/tailscaled.pid"
|
||||||
[ -f "$PID_FILE" ] || fail "pid file was not written"
|
[ -f "$PID_FILE" ] || fail "pid file was not written"
|
||||||
|
|||||||
Reference in New Issue
Block a user