Skip to content

Connection Sweeper CLI Command - #2530

Open
evanwang9x wants to merge 9 commits into
skupperproject:mainfrom
evanwang9x:Evan/conn-sweeper
Open

Connection Sweeper CLI Command#2530
evanwang9x wants to merge 9 commits into
skupperproject:mainfrom
evanwang9x:Evan/conn-sweeper

Conversation

@evanwang9x

@evanwang9x evanwang9x commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Added a CLI command skupper debug sweep to scan through TCP connections and see how long they've been idle and if it exceeds a user set time kill it

Summary by CodeRabbit

  • New Features
    • Added a hidden skupper debug sweep command to identify idle/orphaned router TCP-adaptor connections and optionally delete them.
    • Works in both Kubernetes mode (executes per ready router pod with per-pod and overall totals) and non-Kubernetes mode (targets a local router management endpoint).
    • Introduces --idle-threshold (default 4 hours) and --execute (default off) to switch between reporting and deletion.
    • Correlates router connections with kernel TCP timing to generate “idle for …” reasons and killed/skipped/failed outcomes.

Cross-references the router's TCP adaptor connections (skmanage QUERY)
with kernel socket state (ss -tin) to get an idle-time signal more
accurate than the router's own lastDlvSeconds, which only reflects
delivery-object creation and not ongoing byte traffic on a long-lived
stream. Includes gatherdump, a standalone tool for inspecting a
Snapshot against a live router.
@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f31f52c5-056f-4a9f-a849-6b70224fc41d

📥 Commits

Reviewing files that changed from the base of the PR and between 715b7f6 and ad001d7.

📒 Files selected for processing (4)
  • internal/cmd/skupper/debug/nonkube/conn_sweeper.go
  • internal/cmd/skupper/debug/sweeper/inetdiag.go
  • internal/cmd/skupper/debug/sweeper/kill.go
  • internal/cmd/skupper/debug/sweeper/sweeper.go
🚧 Files skipped from review as they are similar to previous changes (4)
  • internal/cmd/skupper/debug/sweeper/kill.go
  • internal/cmd/skupper/debug/sweeper/inetdiag.go
  • internal/cmd/skupper/debug/sweeper/sweeper.go
  • internal/cmd/skupper/debug/nonkube/conn_sweeper.go

📝 Walkthrough

Walkthrough

Adds a hidden skupper debug sweep command that gathers router TCP and kernel socket state, identifies idle connections, optionally deletes them, and supports Kubernetes pod and non-Kubernetes router/container execution.

Changes

Connection sweeper pipeline

Layer / File(s) Summary
Router and kernel snapshot gathering
internal/cmd/skupper/debug/sweeper/gather.go, internal/cmd/skupper/debug/sweeper/inetdiag.go
Queries filtered TCP-adaptor connections, gathers socket activity through ss or an inet_diag fallback, and builds correlation maps.
Idle connection evaluation
internal/cmd/skupper/debug/sweeper/criteria.go
Matches router connections to kernel sockets and selects connections meeting the configured idle threshold.
Sweeper execution and cleanup
internal/cmd/skupper/debug/sweeper/sweeper.go, internal/cmd/skupper/debug/sweeper/kill.go
Orchestrates gathering and evaluation, supports preview output, and deletes selected connections with fallback checks.
Debug command registration
internal/cmd/skupper/common/flags.go, internal/cmd/skupper/debug/debug.go
Adds shared flags and registers the hidden sweep subcommand.
Non-Kubernetes execution
internal/cmd/skupper/debug/nonkube/conn_sweeper.go
Resolves platform-specific router URLs, TLS arguments, and container or host execution before invoking the sweeper.
Kubernetes router-pod execution
internal/cmd/skupper/debug/kube/conn_sweeper.go
Discovers ready router pods, runs sweeps in router containers with timeouts, aggregates results, and reports per-pod failures.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Operator
  participant SweepCommand
  participant Sweeper
  participant Router
  participant Kernel
  Operator->>SweepCommand: Run hidden sweep command
  SweepCommand->>Sweeper: Pass platform-specific configuration
  Sweeper->>Router: Query TCP adaptor connections
  Router-->>Sweeper: Connection JSON
  Sweeper->>Kernel: Gather socket activity
  Kernel-->>Sweeper: Socket state
  Sweeper->>Sweeper: Evaluate idle connections
  Sweeper->>Router: Delete selected connections
  Router-->>Sweeper: Deletion status
  Sweeper-->>Operator: Return sweep result
Loading

Suggested reviewers: c-kruse, jpadovano1483

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the new connection sweeper CLI command introduced by the pull request.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
internal/cmd/skupper/debug/sweeper/gather.go (1)

96-104: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider surfacing the ss error for debuggability.

gatherSockets discards the error from execFn entirely. While the comment documents the intended "no ss → empty maps" behavior, a debug tool's value is diagnosis — silently swallowing the error makes it impossible to distinguish "ss not installed" from "ss ran but found no matching sockets." Consider capturing the error in the Snapshot (e.g., an SocketsError string field) or returning it from gatherSockets so Gather can log or include it.

♻️ Optional: add error field to Snapshot
 type Snapshot struct {
 	Now      time.Time
 	TCPConns []connInfo
 	// Sockets is keyed by peer "host:port", matching an 'in' connection's
 	// Host (each client has a unique peer address).
 	Sockets map[string]socketInfo
 	// SocketsByLocal is keyed by the socket's own local "host:port",
 	// matching an 'out' connection's LocalSocket ('out' peers all share the
 	// backend's address, so only the local side is unique).
 	SocketsByLocal map[string]socketInfo
+	// SocketsError is non-empty when the kernel socket query failed (e.g.,
+	// `ss` is not installed), so the caller can distinguish a missing tool
+	// from an empty result.
+	SocketsError string
 }
 func gatherSockets(execFn Execer) (byPeer, byLocal map[string]socketInfo, errMsg string) {
 	out, err := execFn([]string{"ss", "-tin"})
 	if err != nil {
-		return map[string]socketInfo{}, map[string]socketInfo{}
+		return map[string]socketInfo{}, map[string]socketInfo{}, err.Error()
 	}
-	return socketsFromSS(out)
+	byPeer, byLocal = socketsFromSS(out)
+	return byPeer, byLocal, ""
 }
internal/cmd/skupper/debug/sweeper/gatherdump/main.go (1)

30-38: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider sorting map keys for deterministic output.

Go map iteration order is randomized, so the "sockets by peer" and "sockets by local" sections will print in a different order on each run. For a debug tool where you may diff outputs across runs, sorting by key would make comparison easier.

♻️ Proposed refactor: sort keys before printing
 import (
 	"flag"
 	"fmt"
 	"os"
+	"sort"
 
 	"github.com/skupperproject/skupper/internal/cmd/skupper/debug/sweeper"
 )
 	fmt.Println("\nsockets by peer (host:port -> lastrcv/lastsnd s):")
-	for host, s := range snap.Sockets {
+	peers := make([]string, 0, len(snap.Sockets))
+	for host := range snap.Sockets {
+		peers = append(peers, host)
+	}
+	sort.Strings(peers)
+	for _, host := range peers {
+		s := snap.Sockets[host]
 		fmt.Printf("  %-25s lastrcv=%.1fs lastsnd=%.1fs\n", host, float64(s.LastRcvMs)/1000, float64(s.LastSndMs)/1000)
 	}

 	fmt.Println("\nsockets by local (host:port -> lastrcv/lastsnd s):")
-	for host, s := range snap.SocketsByLocal {
+	locals := make([]string, 0, len(snap.SocketsByLocal))
+	for host := range snap.SocketsByLocal {
+		locals = append(locals, host)
+	}
+	sort.Strings(locals)
+	for _, host := range locals {
+		s := snap.SocketsByLocal[host]
 		fmt.Printf("  %-25s lastrcv=%.1fs lastsnd=%.1fs\n", host, float64(s.LastRcvMs)/1000, float64(s.LastSndMs)/1000)
 	}

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 4fdf3a3b-5472-4b31-877e-d125fb23a88b

📥 Commits

Reviewing files that changed from the base of the PR and between 172317c and a83615c.

📒 Files selected for processing (3)
  • internal/cmd/skupper/debug/sweeper/README.md
  • internal/cmd/skupper/debug/sweeper/gather.go
  • internal/cmd/skupper/debug/sweeper/gatherdump/main.go

@evanwang9x evanwang9x changed the title Connection Sweeper - Gather Info on TCP connections Connection Sweeper CLI Command Jul 15, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (4)
internal/cmd/skupper/debug/sweeper/criteria.go (1)

14-14: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Fix typographical error.

The word "criterias" is grammatically incorrect; the plural of "criterion" is "criteria".

♻️ Proposed fix
-// Evaluate applies all kill criterias (currently only based off of time) to all
+// Evaluate applies all kill criteria (currently only based off of time) to all

Source: Pipeline failures

internal/cmd/skupper/debug/sweeper/sweeper.go (1)

71-74: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Avoid concatenating format strings.

Concatenating raw variables into a format string can enable log injection and violates standard go vet rules for Printf formatting. Pass the timestamp as a separate format argument instead.

♻️ Proposed fix
 func logf(format string, args ...any) {
 	ts := time.Now().Format("15:04:05")
-	fmt.Printf("["+ts+"] "+format+"\n", args...)
+	fmt.Printf("[%s] %s\n", ts, fmt.Sprintf(format, args...))
 }

Source: Linters/SAST tools

internal/cmd/skupper/debug/kube/conn_sweeper.go (2)

125-129: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

Propagate command context instead of using context.TODO().

If the cobra command provides a context (e.g. cmd.CobraCmd.Context()), it is safer to pass that to the Kubernetes client instead of context.TODO(). This ensures that if the user cancels the CLI command (e.g. via Ctrl+C), the pending network request is correctly aborted.

♻️ Proposed fix
-	pods, err := cmd.KubeClient.CoreV1().Pods(cmd.Namespace).List(context.TODO(), metav1.ListOptions{LabelSelector: routerPodSelector})
+	ctx := context.Background()
+	if cmd.CobraCmd != nil && cmd.CobraCmd.Context() != nil {
+		ctx = cmd.CobraCmd.Context()
+	}
+	pods, err := cmd.KubeClient.CoreV1().Pods(cmd.Namespace).List(ctx, metav1.ListOptions{LabelSelector: routerPodSelector})

50-66: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use cli.Rest instead of rebuilding kubeconfig. client.NewClient already keeps a usable *rest.Config on KubeClient.Rest, and this method only needs that config for ExecCommandInContainer; if you need the /api/serializer tweaks isolated, copy cli.Rest first and mutate the copy.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 1333e949-f1bd-4bb6-bd88-be3419c97fe2

📥 Commits

Reviewing files that changed from the base of the PR and between a83615c and 59b631a.

📒 Files selected for processing (9)
  • internal/cmd/skupper/common/flags.go
  • internal/cmd/skupper/debug/debug.go
  • internal/cmd/skupper/debug/kube/conn_sweeper.go
  • internal/cmd/skupper/debug/nonkube/conn_sweeper.go
  • internal/cmd/skupper/debug/sweeper/criteria.go
  • internal/cmd/skupper/debug/sweeper/gather.go
  • internal/cmd/skupper/debug/sweeper/inetdiag.go
  • internal/cmd/skupper/debug/sweeper/kill.go
  • internal/cmd/skupper/debug/sweeper/sweeper.go

Comment thread internal/cmd/skupper/debug/kube/conn_sweeper.go
Comment thread internal/cmd/skupper/debug/kube/conn_sweeper.go Outdated
Comment thread internal/cmd/skupper/debug/nonkube/conn_sweeper.go

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
internal/cmd/skupper/debug/sweeper/sweeper.go (1)

71-74: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Avoid concatenating the format string.

While the current usages of logf are safe because they only pass string literals, dynamically concatenating the format argument with the timestamp defeats the go vet tool's ability to statically verify format string arguments and triggers static analysis warnings.

Consider formatting the message first to keep the layout string completely static.

♻️ Proposed refactor
 func logf(format string, args ...any) {
 	ts := time.Now().Format("15:04:05")
-	fmt.Printf("["+ts+"] "+format+"\n", args...)
+	fmt.Printf("[%s] %s\n", ts, fmt.Sprintf(format, args...))
 }

Source: Linters/SAST tools


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 185dd6c6-3a1e-4aa4-a1a5-f7a63c04a210

📥 Commits

Reviewing files that changed from the base of the PR and between 59b631a and 2c79b1a.

📒 Files selected for processing (9)
  • internal/cmd/skupper/common/flags.go
  • internal/cmd/skupper/debug/debug.go
  • internal/cmd/skupper/debug/kube/conn_sweeper.go
  • internal/cmd/skupper/debug/nonkube/conn_sweeper.go
  • internal/cmd/skupper/debug/sweeper/criteria.go
  • internal/cmd/skupper/debug/sweeper/gather.go
  • internal/cmd/skupper/debug/sweeper/inetdiag.go
  • internal/cmd/skupper/debug/sweeper/kill.go
  • internal/cmd/skupper/debug/sweeper/sweeper.go
🚧 Files skipped from review as they are similar to previous changes (7)
  • internal/cmd/skupper/debug/debug.go
  • internal/cmd/skupper/debug/sweeper/criteria.go
  • internal/cmd/skupper/debug/kube/conn_sweeper.go
  • internal/cmd/skupper/debug/nonkube/conn_sweeper.go
  • internal/cmd/skupper/debug/sweeper/kill.go
  • internal/cmd/skupper/debug/sweeper/gather.go
  • internal/cmd/skupper/debug/sweeper/inetdiag.go

@evanwang9x
evanwang9x force-pushed the Evan/conn-sweeper branch 2 times, most recently from f19fd76 to 404c992 Compare July 15, 2026 18:59
Comment thread internal/cmd/skupper/debug/debug.go
Comment thread internal/cmd/skupper/debug/debug.go Outdated
Comment thread internal/cmd/skupper/debug/kube/conn_sweeper.go Outdated
Comment thread internal/cmd/skupper/debug/kube/conn_sweeper.go Outdated
Comment thread internal/cmd/skupper/debug/kube/conn_sweeper.go Outdated
Comment thread internal/cmd/skupper/debug/kube/conn_sweeper.go Outdated
Comment thread internal/cmd/skupper/debug/kube/conn_sweeper.go Outdated
@nluaces

nluaces commented Jul 17, 2026

Copy link
Copy Markdown
Member

Thank you for all your work! I left some comments regarding the kube implementation of the command. I suggest to fix also the same issues in the non-kube implementation.

I also suggest to review all the generated comments: if they explain things in the current code that are not easy to understand, they should be kept; if not, I would suggest to delete them.

Thanks!

type CommandDebugFlags struct {
}

type CommandConnSweeperFlags struct {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The URL and skmanage should not be flags for the sub-command

Suggest following the pattern that the dump subcommand uses for getting skstat as it accounts for the three scenarios

  • k8s
  • container (e.g.)
  • systemd

We can assume skmanage is present in the router container and for systemd it can be assumed user already had to install the skupper-router binary

// back to the python netlink script when ss isn't available (e.g. inside the
// router container, which ships python3 but not iproute).
func gatherSockets(execFn Execer) (byPeer, byLocal map[string]socketInfo) {
if out, err := execFn([]string{"ss", "-tin"}); err == nil {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

iproute is lightweight and has some other useful utilities...we should look to add to the router container

@c-kruse c-kruse Jul 20, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ajssmith do i remember us somewhat recently stripping out non essential system dependencies to minimize churn from security scanners? Could be worth raising with the group to decide where our priorities are there.

EDIT: I do see that we've got a python script embedded to work around that - not ideal. I think I'd prefer anything that exercises router system dependencies (python or iproute included) live with the router codebase, get tested there, and bear some obvious sk-part-of-our-public-api name so that we don't accidentally break this debug option down the line.

URL string
Skmanage string
IdleThresholdSecs int
DryRun bool

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we use dryRun, which is false by default, causing the sweeper command to kill connections on execution.
Or change it with something like: execute bool, to prevent accidentally killling idle connections?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think execute bool is more intuitive than dryrun so I'll change it to be that.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
internal/cmd/skupper/debug/nonkube/conn_sweeper.go (2)

44-52: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Reject positional arguments to prevent user confusion.

Since skupper debug sweep does not require any positional arguments, consider explicitly rejecting them in ValidateInput. Otherwise, any extra arguments passed by mistake are silently ignored.

💡 Proposed fix
 func (cmd *CmdConnSweeper) ValidateInput(args []string) error {
 	var validationErrors []error
+	if len(args) > 0 {
+		validationErrors = append(validationErrors, fmt.Errorf("this command does not accept positional arguments"))
+	}
 	numberValidator := validator.NewNumberValidator()
 	numberValidator.IncludeZero = false

59-71: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Capture and return initialization errors instead of swallowing them.

When platformLoader.Load or runtime.GetLocalRouterAddress fails, the error is swallowed and the function returns early. This causes the command to fail later in Run() with a generic "could not determine router management address" error, masking the root cause (e.g., missing configuration, permission denied).

Consider adding an initError error field to the CmdConnSweeper struct to capture these errors in InputToOptions and bubble them up in Run().

♻️ Proposed refactoring
  1. Add the field to the struct:
 type CmdConnSweeper struct {
 	CobraCmd  *cobra.Command
 	// ...
 	exec      sweeper.Execer
+	initError error
 }
  1. Capture the errors in InputToOptions:
 	platformLoader := &nonkubecommon.NamespacePlatformLoader{}
 	platform, err := platformLoader.Load(cmd.namespace)
 	if err != nil {
+		cmd.initError = fmt.Errorf("failed to load platform: %w", err)
 		return
 	}
 	cmd.platform = platform
 
 	url, err := runtime.GetLocalRouterAddress(cmd.namespace)
 	if err != nil {
+		cmd.initError = fmt.Errorf("failed to get local router address: %w", err)
 		return
 	}
  1. Return the error in Run():
 func (cmd *CmdConnSweeper) Run() error {
+	if cmd.initError != nil {
+		return cmd.initError
+	}
 	if cmd.url == "" || cmd.skmanage == "" {

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 857447a8-d6df-47d8-92ea-bf3ed20ffb6d

📥 Commits

Reviewing files that changed from the base of the PR and between f529c33 and 850c738.

📒 Files selected for processing (8)
  • internal/cmd/skupper/common/flags.go
  • internal/cmd/skupper/debug/debug.go
  • internal/cmd/skupper/debug/kube/conn_sweeper.go
  • internal/cmd/skupper/debug/nonkube/conn_sweeper.go
  • internal/cmd/skupper/debug/sweeper/gather.go
  • internal/cmd/skupper/debug/sweeper/inetdiag.go
  • internal/cmd/skupper/debug/sweeper/kill.go
  • internal/cmd/skupper/debug/sweeper/sweeper.go
💤 Files with no reviewable changes (1)
  • internal/cmd/skupper/common/flags.go
🚧 Files skipped from review as they are similar to previous changes (5)
  • internal/cmd/skupper/debug/sweeper/kill.go
  • internal/cmd/skupper/debug/sweeper/sweeper.go
  • internal/cmd/skupper/debug/sweeper/inetdiag.go
  • internal/cmd/skupper/debug/kube/conn_sweeper.go
  • internal/cmd/skupper/debug/sweeper/gather.go

@JPadovano1483
JPadovano1483 self-requested a review July 20, 2026 18:13

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
internal/cmd/skupper/debug/sweeper/sweeper.go (2)

47-56: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Validate the idle threshold before enabling cleanup.

IdleThresholdSecs accepts unrestricted integer input, so negative values—or values that overflow time.Duration during the seconds conversion—can make the evaluator classify unintended connections as idle. Reject invalid thresholds before the --execute path can delete connections.


64-67: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Propagate connection-deletion failures to the CLI.

killAll reports failures through Result.Failed, but the Kubernetes and non-Kubernetes callers only propagate error. As a result, a sweep can fail to close connections while still exiting successfully. Return an error when deletions fail, or update both callers to fail based on Result.Failed.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2a0974cc-c7a5-4c3b-8a33-eb5be94d5a8a

📥 Commits

Reviewing files that changed from the base of the PR and between 850c738 and 5a88b14.

📒 Files selected for processing (5)
  • internal/cmd/skupper/common/flags.go
  • internal/cmd/skupper/debug/debug.go
  • internal/cmd/skupper/debug/kube/conn_sweeper.go
  • internal/cmd/skupper/debug/nonkube/conn_sweeper.go
  • internal/cmd/skupper/debug/sweeper/sweeper.go
🚧 Files skipped from review as they are similar to previous changes (3)
  • internal/cmd/skupper/debug/debug.go
  • internal/cmd/skupper/debug/kube/conn_sweeper.go
  • internal/cmd/skupper/debug/nonkube/conn_sweeper.go

@evanwang9x evanwang9x closed this Jul 21, 2026
@evanwang9x evanwang9x reopened this Jul 21, 2026
@evanwang9x

evanwang9x commented Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@skupperproject skupperproject deleted a comment from coderabbitai Bot Jul 23, 2026
@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (2)
internal/cmd/skupper/debug/kube/conn_sweeper.go (2)

1-1: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate ValidateInput logic across kube and nonkube sweeper commands. Both implementations validate IdleThreshold identically (non-zero number check + max-threshold check + errors.Join), which risks drift if the rule changes in only one place.

  • internal/cmd/skupper/debug/kube/conn_sweeper.go#L80-91: extract this validation into a shared helper (e.g. sweeper.ValidateIdleThreshold(int) error) and call it here.
  • internal/cmd/skupper/debug/nonkube/conn_sweeper.go#L44-55: call the same shared helper instead of duplicating the validator/threshold logic.

45-78: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Reuse the existing REST config for exec.

client.NewClient(...) resolves the kubeconfig once and stores a copy in kubeClient.Rest, but it does not expose that config. NewClient duplicates the same clientcmd loading rules/exec config patching, which can drift if the paths diverge. Add an exported accessor for the already-resolved *rest.Config and copy/patch it for cmd.Rest instead of reloading it.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: d211da5a-2394-4591-9b0f-0bb168eaff63

📥 Commits

Reviewing files that changed from the base of the PR and between e1fde23 and 715b7f6.

📒 Files selected for processing (9)
  • internal/cmd/skupper/common/flags.go
  • internal/cmd/skupper/debug/debug.go
  • internal/cmd/skupper/debug/kube/conn_sweeper.go
  • internal/cmd/skupper/debug/nonkube/conn_sweeper.go
  • internal/cmd/skupper/debug/sweeper/criteria.go
  • internal/cmd/skupper/debug/sweeper/gather.go
  • internal/cmd/skupper/debug/sweeper/inetdiag.go
  • internal/cmd/skupper/debug/sweeper/kill.go
  • internal/cmd/skupper/debug/sweeper/sweeper.go

Comment on lines +167 to +193
func (cmd *CmdConnSweeper) podExecer(podName string) sweeper.Execer {
return func(argv []string) ([]byte, error) {
type execResult struct {
out []byte
err error
}
done := make(chan execResult, 1)
go func() {
out, err := client.ExecCommandInContainer(argv, podName, routerContainer, cmd.Namespace, cmd.KubeClient, cmd.Rest)
if err != nil {
done <- execResult{nil, err}
return
}
done <- execResult{out.Bytes(), nil}
}()

select {
case r := <-done:
if r.err != nil {
return nil, fmt.Errorf("exec %q in pod %s failed: %w", argv[0], podName, r.err)
}
return r.out, nil
case <-time.After(podExecTimeout):
return nil, fmt.Errorf("exec %q in pod %s timed out after %s", argv[0], podName, podExecTimeout)
}
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check whether ExecCommandInContainer accepts a context for cancellation
rg -n -A 10 'func ExecCommandInContainer' internal/kube/client

Repository: skupperproject/skupper

Length of output: 1056


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '--- conn_sweeper relevant section ---\n'
sed -n '130,210p' internal/cmd/skupper/debug/kube/conn_sweeper.go

printf '\n--- kube client exec util ---\n'
sed -n '1,120p' internal/kube/client/exec_util.go

printf '\n--- all ExecCommandInContainer usages ---\n'
rg -n 'ExecCommandInContainer\(' internal/cmd internal/kube

Repository: skupperproject/skupper

Length of output: 251


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- conn_sweeper relevant section ---'
sed -n '130,210p' internal/cmd/skupper/debug/kube/conn_sweeper.go

printf '%s\n' '--- kube client exec util ---'
sed -n '1,140p' internal/kube/client/exec_util.go

printf '%s\n' '--- all ExecCommandInContainer usages ---'
rg -n 'ExecCommandInContainer\(' internal/cmd internal/kube

Repository: skupperproject/skupper

Length of output: 4365


Cancel pending pod execs on timeout.

ExecCommandInContainer does not accept a cancellation context, so when time.After returns the goroutine may still be blocked on exec.Stream(...) and only later write to the buffered channel. Change ExecCommandInContainer to accept a context and use it on the Pod(...).Get(...) / RESTClientFor(...) path(s), then cancel it from the timeout branch before returning.

Comment thread internal/cmd/skupper/debug/nonkube/conn_sweeper.go
//
// <local ip:port> <peer ip:port> <lastrcv ms> <lastsnd ms>
//
// TODO: IPv4 only; extend for IPv6.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Support IPv6 in the fallback.

Line 16 limits the only router-container fallback to AF_INET; IPv6 TCP connections are silently unmatched whenever ss is unavailable, so they can never be reported or swept. Query AF_INET6 too and normalize its address format to the router connection keys.

Comment thread internal/cmd/skupper/debug/sweeper/inetdiag.go Outdated
Comment thread internal/cmd/skupper/debug/sweeper/kill.go Outdated
Comment thread internal/cmd/skupper/debug/sweeper/sweeper.go
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants