Довёл fix20: firewall-mode, staged state, diagnostics, readiness и build-gate
This commit is contained in:
@@ -2,6 +2,31 @@ import type { RuntimeContext } from "../types/context";
|
||||
import { info } from "../lib/log";
|
||||
import { runHidden, runSecret, runVisible } from "../lib/process";
|
||||
|
||||
function parseLocalAddress(line: string): string {
|
||||
const cols = line.trim().split(/\s+/);
|
||||
return cols[3] ?? "";
|
||||
}
|
||||
|
||||
function hasTcpListener(lines: string, host: string, port: number): boolean {
|
||||
return lines
|
||||
.split("\n")
|
||||
.filter(Boolean)
|
||||
.some((line) => {
|
||||
const local = parseLocalAddress(line);
|
||||
return local === `${host}:${port}`;
|
||||
});
|
||||
}
|
||||
|
||||
function hasUdpListener(lines: string, host: string, port: number): boolean {
|
||||
return lines
|
||||
.split("\n")
|
||||
.filter(Boolean)
|
||||
.some((line) => {
|
||||
const local = parseLocalAddress(line);
|
||||
return local === `${host}:${port}`;
|
||||
});
|
||||
}
|
||||
|
||||
async function retry<T>(
|
||||
label: string,
|
||||
attempts: number,
|
||||
@@ -31,14 +56,64 @@ async function retry<T>(
|
||||
}
|
||||
|
||||
export async function smoke(context: RuntimeContext): Promise<void> {
|
||||
if (context.options.skipStart) {
|
||||
info("service start and smoke checks skipped by flag");
|
||||
if (context.options.skipServiceStart && context.options.skipSmoke) {
|
||||
info("service start and smoke checks skipped by flags");
|
||||
return;
|
||||
}
|
||||
|
||||
await runVisible`systemctl restart hysteria-server hy2xs-admin`;
|
||||
await runVisible`systemctl is-active --quiet hysteria-server`;
|
||||
await runVisible`systemctl is-active --quiet hy2xs-admin`;
|
||||
if (!context.options.skipServiceStart) {
|
||||
await runVisible`systemctl restart hysteria-server hy2xs-admin`;
|
||||
} else {
|
||||
info("service restart skipped by flag");
|
||||
}
|
||||
|
||||
await retry(
|
||||
"systemd hysteria-server active",
|
||||
15,
|
||||
1000,
|
||||
async () => runSecret`systemctl is-active hysteria-server || true`,
|
||||
(state) => state.trim() === "active",
|
||||
(state, error) => new Error(`hysteria-server is not active: ${state ?? String(error)}`),
|
||||
);
|
||||
await retry(
|
||||
"systemd hy2xs-admin active",
|
||||
15,
|
||||
1000,
|
||||
async () => runSecret`systemctl is-active hy2xs-admin || true`,
|
||||
(state) => state.trim() === "active",
|
||||
(state, error) => new Error(`hy2xs-admin is not active: ${state ?? String(error)}`),
|
||||
);
|
||||
|
||||
if (context.options.skipSmoke) {
|
||||
info("smoke checks skipped by flag");
|
||||
return;
|
||||
}
|
||||
|
||||
await retry(
|
||||
"ui tcp listener readiness",
|
||||
15,
|
||||
1000,
|
||||
async () => runSecret`ss -H -ltn`,
|
||||
(lines) => hasTcpListener(lines, context.config.uiBindHost, context.config.uiPort),
|
||||
(lines, error) => new Error(`ui listener not ready on ${context.config.uiBindHost}:${context.config.uiPort}: ${lines ?? String(error)}`),
|
||||
);
|
||||
await retry(
|
||||
"hysteria udp listener readiness",
|
||||
15,
|
||||
1000,
|
||||
async () => runSecret`ss -H -lun`,
|
||||
(lines) => hasUdpListener(lines, context.config.hysteriaBindHost, context.config.hysteriaPort),
|
||||
(lines, error) => new Error(`hysteria udp listener not ready on 0.0.0.0:${context.config.hysteriaPort}: ${lines ?? String(error)}`),
|
||||
);
|
||||
await retry(
|
||||
"admin healthz readiness",
|
||||
15,
|
||||
1000,
|
||||
async () => runSecret`curl -sS --max-time 5 http://127.0.0.1:${context.config.uiPort}/healthz`,
|
||||
(response) => /"ok"\s*:\s*true/.test(response),
|
||||
(response, error) => new Error(`admin healthz is not ready: ${response ?? String(error)}`),
|
||||
);
|
||||
|
||||
await runVisible`/usr/local/bin/hysteria version`;
|
||||
await runVisible`test -s /etc/hysteria/config.yaml`;
|
||||
await runVisible`test -s /etc/hy2xs/hy2xs.env`;
|
||||
@@ -61,11 +136,12 @@ export async function smoke(context: RuntimeContext): Promise<void> {
|
||||
await runVisible`sudo -u hy2xs-admin test ! -r /etc/hy2xs/hy2xs.env`;
|
||||
await runVisible`sudo -u hy2xs-admin test ! -r /etc/hy2xs/bootstrap-admin.secret`;
|
||||
await runVisible`sudo -u hysteria test ! -r /etc/hy2xs/bootstrap-admin.secret`;
|
||||
await runVisible`ss -H -ltn | grep -q '${context.config.uiBindHost}:${context.config.uiPort} '`;
|
||||
if (context.config.uiBindHost === "127.0.0.1") {
|
||||
await runVisible`! ss -H -ltn | grep -q '0.0.0.0:${context.config.uiPort} '`;
|
||||
const tcp = await runSecret`ss -H -ltn`;
|
||||
if (hasTcpListener(tcp, "0.0.0.0", context.config.uiPort)) {
|
||||
throw new Error(`ui listener must not be public on 0.0.0.0:${context.config.uiPort}`);
|
||||
}
|
||||
}
|
||||
await runVisible`ss -H -lun | grep -q '0.0.0.0:${context.config.hysteriaPort} '`;
|
||||
await runVisible`! ss -H -ltn | grep -q '\[::\]:${context.config.uiPort} '`;
|
||||
await runVisible`! ss -H -lun | grep -q '\[::\]:${context.config.hysteriaPort} '`;
|
||||
const invalidAuthResponse = await retry(
|
||||
|
||||
Reference in New Issue
Block a user