From 2845db336573412d1666087562e37d342a3051f1 Mon Sep 17 00:00:00 2001 From: Codex Date: Mon, 1 Jun 2026 14:42:42 +0000 Subject: [PATCH] fix: support k3s log selector --- docs/reference/cli.md | 1 + scripts/src/help.ts | 1 + scripts/src/ssh.ts | 27 +++++++++++++++++++++++---- 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/docs/reference/cli.md b/docs/reference/cli.md index 7a5db581..3de7ae0c 100644 --- a/docs/reference/cli.md +++ b/docs/reference/cli.md @@ -322,6 +322,7 @@ bun scripts/cli.ts ssh G14:k3s kubectl get pipelineruns -n hwlab-ci printf 'kubectl get deploy -n hwlab-dev\n' | bun scripts/cli.ts ssh D601:k3s script bun scripts/cli.ts ssh D601:k3s:hwlab-dev:hwlab-cloud-api logs --tail 80 bun scripts/cli.ts ssh G14:k3s logs --namespace=devops-infra --deployment=git-mirror-http --tail=80 +bun scripts/cli.ts ssh G14:k3s logs -n agentrun-ci -l tekton.dev/pipelineRun=agentrun-v01-ci-xxxx --tail=120 bun scripts/cli.ts ssh D601:k3s:hwlab-dev:hwlab-cloud-api node -e 'console.log(process.version)' bun scripts/cli.ts ssh D601:k3s:hwlab-dev:hwlab-cloud-api/app pwd printf 'printf "pod=%s\n" "$HOSTNAME"\n' | bun scripts/cli.ts ssh D601:k3s:hwlab-dev:hwlab-cloud-api script diff --git a/scripts/src/help.ts b/scripts/src/help.ts index 03719fd8..aaf5e9fd 100644 --- a/scripts/src/help.ts +++ b/scripts/src/help.ts @@ -185,6 +185,7 @@ export function sshHelp(): unknown { "bun scripts/cli.ts ssh D601:k3s:hwlab-dev:hwlab-cloud-api node -e 'console.log(process.version)'", "bun scripts/cli.ts ssh D601:k3s:hwlab-dev:hwlab-cloud-api script <<'SCRIPT'", "bun scripts/cli.ts ssh D601:k3s:hwlab-dev:hwlab-cloud-api logs --tail 80", + "bun scripts/cli.ts ssh G14:k3s logs -n agentrun-ci -l tekton.dev/pipelineRun= --tail 120", ], notes: [ "ssh --help and ssh --help print this JSON help and never open an interactive session.", diff --git a/scripts/src/ssh.ts b/scripts/src/ssh.ts index 01ecfc9b..27dd2a45 100644 --- a/scripts/src/ssh.ts +++ b/scripts/src/ssh.ts @@ -1518,6 +1518,7 @@ function buildK3sGuardCommand(providerId: string): string { interface K3sTargetOptions { namespace: string | null; resource: string | null; + selector: string | null; container: string | null; workspace: string | null; stdin: boolean; @@ -1531,11 +1532,13 @@ interface ParseK3sTargetOptionsOptions { requireCommand: boolean; allowCommand?: boolean; allowShell?: boolean; + allowSelector?: boolean; } function buildK3sExecCommand(args: string[]): string { const parsed = parseK3sTargetOptions(args, "ssh k3s exec", { requireCommand: true }); if (parsed.namespace === null) throw new Error("ssh k3s exec requires --namespace "); + if (parsed.selector !== null) throw new Error("ssh k3s exec does not support --selector"); if (parsed.resource === null) throw new Error("ssh k3s exec requires --deployment , --pod or --resource "); const kubectlArgs = [ "exec", @@ -1562,6 +1565,7 @@ function buildK3sScriptOperation(args: string[]): ParsedSshArgs { function buildK3sStdinScriptCommand(parsed: K3sTargetOptions): string { if (parsed.namespace === null && parsed.resource === null) return buildK3sHostScriptCommand(parsed); if (parsed.namespace === null) throw new Error("ssh k3s script target requires --namespace "); + if (parsed.selector !== null) throw new Error("ssh k3s script does not support --selector"); if (parsed.resource === null) throw new Error("ssh k3s script target requires --deployment , --pod or --resource "); if (parsed.tty) throw new Error("ssh k3s script does not support --tty; stdin is reserved for the script body"); const shell = parsed.shell ?? "sh"; @@ -1580,6 +1584,7 @@ function buildK3sStdinScriptCommand(parsed: K3sTargetOptions): string { function buildK3sInlineScriptCommand(parsed: K3sTargetOptions): string { if (parsed.command.length === 0) throw new Error("ssh k3s script -- requires a command"); + if (parsed.selector !== null) throw new Error("ssh k3s script -- does not support --selector"); if (parsed.tty) throw new Error("ssh k3s script does not support --tty; stdin is reserved for the script body"); if (parsed.stdin) throw new Error("ssh k3s script -- does not accept --stdin"); const command = parsed.command.length === 1 ? ["sh", "-c", shellScriptWithCompatibility(parsed.command[0] ?? "")] : parsed.command; @@ -1661,15 +1666,16 @@ function parseShellStringOperationArgs(args: string[], commandName: string): { s } function buildK3sLogsCommand(args: string[]): string { - const parsed = parseK3sTargetOptions(args, "ssh k3s logs", { requireCommand: false }); + const parsed = parseK3sTargetOptions(args, "ssh k3s logs", { requireCommand: false, allowSelector: true }); if (parsed.namespace === null) throw new Error("ssh k3s logs requires --namespace "); - if (parsed.resource === null) throw new Error("ssh k3s logs requires --deployment , --pod or --resource "); + if (parsed.resource === null && parsed.selector === null) throw new Error("ssh k3s logs requires --deployment , --pod , --resource or --selector "); + if (parsed.resource !== null && parsed.selector !== null) throw new Error("ssh k3s logs accepts either a resource or --selector, not both"); if (parsed.stdin || parsed.tty) throw new Error("ssh k3s logs does not support --stdin or --tty"); if (parsed.workspace !== null) throw new Error("ssh k3s logs does not accept --workdir"); const kubectlArgs = [ "logs", "-n", parsed.namespace, - parsed.resource, + ...(parsed.selector === null ? [parsed.resource ?? ""] : ["-l", parsed.selector]), ...(parsed.container === null ? [] : ["-c", parsed.container]), ...parsed.kubectlOptions, ]; @@ -1679,6 +1685,7 @@ function buildK3sLogsCommand(args: string[]): string { function parseK3sTargetOptions(args: string[], commandName: string, options: ParseK3sTargetOptionsOptions): K3sTargetOptions { let namespace: string | null = null; let resource: string | null = null; + let selector: string | null = null; let container: string | null = null; let workspace: string | null = null; let stdin = false; @@ -1738,6 +1745,18 @@ function parseK3sTargetOptions(args: string[], commandName: string, options: Par resource = normalizeK3sResource(resourceValue); continue; } + if (arg === "--selector" || arg === "-l") { + if (options.allowSelector !== true) throw new Error(`${commandName} does not support ${arg}`); + selector = k3sOptionValue(args, index, `${commandName} ${arg}`); + index += 1; + continue; + } + const selectorValue = k3sEqualsOptionValue(arg, "--selector", commandName) ?? k3sEqualsOptionValue(arg, "-l", commandName); + if (selectorValue !== null) { + if (options.allowSelector !== true) throw new Error(`${commandName} does not support ${arg.split("=", 1)[0]}`); + selector = selectorValue; + continue; + } if (arg === "--container" || arg === "-c") { container = k3sOptionValue(args, index, `${commandName} ${arg}`); index += 1; @@ -1819,7 +1838,7 @@ function parseK3sTargetOptions(args: string[], commandName: string, options: Par if (options.requireCommand && command.length === 0) throw new Error(`${commandName} requires -- [args...]`); if (!options.requireCommand && options.allowCommand !== true && command.length > 0) throw new Error(`${commandName} does not accept a command after --`); - return { namespace, resource, container, workspace, stdin, tty, shell, command, kubectlOptions }; + return { namespace, resource, selector, container, workspace, stdin, tty, shell, command, kubectlOptions }; } function k3sEqualsOptionValue(arg: string, option: string, commandName: string): string | null {