feat(tailscale): add socket option for userspace tailscaled
This commit is contained in:
parent
c6cdbb630c
commit
036bb842fd
@ -75,6 +75,8 @@ export type GatewayTailscaleConfig = {
|
||||
mode?: GatewayTailscaleMode;
|
||||
/** Reset serve/funnel configuration on shutdown. */
|
||||
resetOnExit?: boolean;
|
||||
/** Path to tailscaled socket (for userspace Tailscale). */
|
||||
socket?: string;
|
||||
};
|
||||
|
||||
export type GatewayRemoteConfig = {
|
||||
|
||||
@ -329,6 +329,7 @@ export const ClawdbotSchema = z
|
||||
.object({
|
||||
mode: z.union([z.literal("off"), z.literal("serve"), z.literal("funnel")]).optional(),
|
||||
resetOnExit: z.boolean().optional(),
|
||||
socket: z.string().optional(),
|
||||
})
|
||||
.strict()
|
||||
.optional(),
|
||||
|
||||
@ -9,6 +9,7 @@ import {
|
||||
export async function startGatewayTailscaleExposure(params: {
|
||||
tailscaleMode: "off" | "serve" | "funnel";
|
||||
resetOnExit?: boolean;
|
||||
socket?: string;
|
||||
port: number;
|
||||
controlUiBasePath?: string;
|
||||
logTailscale: { info: (msg: string) => void; warn: (msg: string) => void };
|
||||
@ -17,13 +18,15 @@ export async function startGatewayTailscaleExposure(params: {
|
||||
return null;
|
||||
}
|
||||
|
||||
const socketOpts = params.socket ? { socket: params.socket } : undefined;
|
||||
|
||||
try {
|
||||
if (params.tailscaleMode === "serve") {
|
||||
await enableTailscaleServe(params.port);
|
||||
await enableTailscaleServe(params.port, undefined, socketOpts);
|
||||
} else {
|
||||
await enableTailscaleFunnel(params.port);
|
||||
await enableTailscaleFunnel(params.port, undefined, socketOpts);
|
||||
}
|
||||
const host = await getTailnetHostname().catch(() => null);
|
||||
const host = await getTailnetHostname(undefined, undefined, socketOpts).catch(() => null);
|
||||
if (host) {
|
||||
const uiPath = params.controlUiBasePath ? `${params.controlUiBasePath}/` : "/";
|
||||
params.logTailscale.info(
|
||||
@ -45,9 +48,9 @@ export async function startGatewayTailscaleExposure(params: {
|
||||
return async () => {
|
||||
try {
|
||||
if (params.tailscaleMode === "serve") {
|
||||
await disableTailscaleServe();
|
||||
await disableTailscaleServe(undefined, socketOpts);
|
||||
} else {
|
||||
await disableTailscaleFunnel();
|
||||
await disableTailscaleFunnel(undefined, socketOpts);
|
||||
}
|
||||
} catch (err) {
|
||||
params.logTailscale.warn(
|
||||
|
||||
@ -477,6 +477,7 @@ export async function startGatewayServer(
|
||||
const tailscaleCleanup = await startGatewayTailscaleExposure({
|
||||
tailscaleMode,
|
||||
resetOnExit: tailscaleConfig.resetOnExit,
|
||||
socket: tailscaleConfig.socket,
|
||||
port,
|
||||
controlUiBasePath,
|
||||
logTailscale,
|
||||
|
||||
@ -101,7 +101,11 @@ export async function findTailscaleBinary(): Promise<string | null> {
|
||||
return null;
|
||||
}
|
||||
|
||||
export async function getTailnetHostname(exec: typeof runExec = runExec, detectedBinary?: string) {
|
||||
export async function getTailnetHostname(
|
||||
exec: typeof runExec = runExec,
|
||||
detectedBinary?: string,
|
||||
opts?: { socket?: string },
|
||||
) {
|
||||
// Derive tailnet hostname (or IP fallback) from tailscale status JSON.
|
||||
const candidates = detectedBinary
|
||||
? [detectedBinary]
|
||||
@ -111,7 +115,10 @@ export async function getTailnetHostname(exec: typeof runExec = runExec, detecte
|
||||
for (const candidate of candidates) {
|
||||
if (candidate.startsWith("/") && !existsSync(candidate)) continue;
|
||||
try {
|
||||
const { stdout } = await exec(candidate, ["status", "--json"], {
|
||||
const args = opts?.socket
|
||||
? ["--socket", opts.socket, "status", "--json"]
|
||||
: ["status", "--json"];
|
||||
const { stdout } = await exec(candidate, args, {
|
||||
timeoutMs: 5000,
|
||||
maxBuffer: 400_000,
|
||||
});
|
||||
@ -350,33 +357,55 @@ export async function ensureFunnel(
|
||||
}
|
||||
}
|
||||
|
||||
export async function enableTailscaleServe(port: number, exec: typeof runExec = runExec) {
|
||||
export async function enableTailscaleServe(
|
||||
port: number,
|
||||
exec: typeof runExec = runExec,
|
||||
opts?: { socket?: string },
|
||||
) {
|
||||
const tailscaleBin = await getTailscaleBinary();
|
||||
await execWithSudoFallback(exec, tailscaleBin, ["serve", "--bg", "--yes", `${port}`], {
|
||||
const args = opts?.socket
|
||||
? ["--socket", opts.socket, "serve", "--bg", "--yes", `${port}`]
|
||||
: ["serve", "--bg", "--yes", `${port}`];
|
||||
await execWithSudoFallback(exec, tailscaleBin, args, {
|
||||
maxBuffer: 200_000,
|
||||
timeoutMs: 15_000,
|
||||
});
|
||||
}
|
||||
|
||||
export async function disableTailscaleServe(exec: typeof runExec = runExec) {
|
||||
export async function disableTailscaleServe(
|
||||
exec: typeof runExec = runExec,
|
||||
opts?: { socket?: string },
|
||||
) {
|
||||
const tailscaleBin = await getTailscaleBinary();
|
||||
await execWithSudoFallback(exec, tailscaleBin, ["serve", "reset"], {
|
||||
const args = opts?.socket ? ["--socket", opts.socket, "serve", "reset"] : ["serve", "reset"];
|
||||
await execWithSudoFallback(exec, tailscaleBin, args, {
|
||||
maxBuffer: 200_000,
|
||||
timeoutMs: 15_000,
|
||||
});
|
||||
}
|
||||
|
||||
export async function enableTailscaleFunnel(port: number, exec: typeof runExec = runExec) {
|
||||
export async function enableTailscaleFunnel(
|
||||
port: number,
|
||||
exec: typeof runExec = runExec,
|
||||
opts?: { socket?: string },
|
||||
) {
|
||||
const tailscaleBin = await getTailscaleBinary();
|
||||
await execWithSudoFallback(exec, tailscaleBin, ["funnel", "--bg", "--yes", `${port}`], {
|
||||
const args = opts?.socket
|
||||
? ["--socket", opts.socket, "funnel", "--bg", "--yes", `${port}`]
|
||||
: ["funnel", "--bg", "--yes", `${port}`];
|
||||
await execWithSudoFallback(exec, tailscaleBin, args, {
|
||||
maxBuffer: 200_000,
|
||||
timeoutMs: 15_000,
|
||||
});
|
||||
}
|
||||
|
||||
export async function disableTailscaleFunnel(exec: typeof runExec = runExec) {
|
||||
export async function disableTailscaleFunnel(
|
||||
exec: typeof runExec = runExec,
|
||||
opts?: { socket?: string },
|
||||
) {
|
||||
const tailscaleBin = await getTailscaleBinary();
|
||||
await execWithSudoFallback(exec, tailscaleBin, ["funnel", "reset"], {
|
||||
const args = opts?.socket ? ["--socket", opts.socket, "funnel", "reset"] : ["funnel", "reset"];
|
||||
await execWithSudoFallback(exec, tailscaleBin, args, {
|
||||
maxBuffer: 200_000,
|
||||
timeoutMs: 15_000,
|
||||
});
|
||||
|
||||
Loading…
Reference in New Issue
Block a user