Skip to content

fix(cmd): use exec.LookPath in Which() so detection works without external 'which'#12651

Open
Sanjays2402 wants to merge 1 commit into1Panel-dev:dev-v2from
Sanjays2402:fix/which-fallback-arch-linux-12605
Open

fix(cmd): use exec.LookPath in Which() so detection works without external 'which'#12651
Sanjays2402 wants to merge 1 commit into1Panel-dev:dev-v2from
Sanjays2402:fix/which-fallback-arch-linux-12605

Conversation

@Sanjays2402
Copy link
Copy Markdown

What this PR does / why we need it?

Fixes #12605.

cmd.Which() previously shelled out to which <name> to determine whether a binary was on PATH. On distributions that do not ship a which package by default — Arch Linux is the canonical example, but the same applies to several minimal container images — which itself is missing from PATH, so every call to Which() returned false. As a result, 1Panel reported core dependencies (notably Docker) as not installed even when they were running normally:

GET /api/v2/containers/docker/status
{"code":200,"message":"","data":{"isActive":false,"isExist":false}}

…on a host where docker.service was active, docker version worked, and /var/run/docker.sock was reachable. The reporter confirmed that simply dropping a stub /usr/local/bin/which script restored detection.

Summary of your change

Switch the primary path to Go's exec.LookPath, which uses the process PATH directly and has no external binary dependency. The original shell-out is preserved as a fallback so any environment where the agent's PATH differs from the user's interactive shell PATH (the reason the shell-out existed in the first place) keeps working unchanged.

Both copies of the helper are updated:

  • agent/utils/cmd/cmd.go
  • core/utils/cmd/cmd.go
func Which(name string) bool {
    if _, err := exec.LookPath(name); err == nil {
        return true
    }
    // Fallback: original shell-out, preserved for compatibility.
    stdout, err := RunDefaultWithStdoutBashCf("which %s", name)
    if err != nil || (len(strings.ReplaceAll(stdout, "\\n", "")) == 0) {
        return false
    }
    return true
}

A small unit test is added to each package guarding the regression:

  • Which("sh") is true (sh is on every Unix-like host the CI runs on, regardless of whether which itself is installed).
  • Which("definitely-not-a-real-binary-xyzzy-1panel") is false.

Verification

$ cd agent && go test ./utils/cmd/ -v
=== RUN   TestWhich_ExistingBinary
--- PASS: TestWhich_ExistingBinary
=== RUN   TestWhich_MissingBinary
--- PASS: TestWhich_MissingBinary
PASS

$ cd core && go test ./utils/cmd/ -v
=== RUN   TestWhich_ExistingBinary
--- PASS: TestWhich_ExistingBinary
=== RUN   TestWhich_MissingBinary
--- PASS: TestWhich_MissingBinary
PASS

go vet and gofmt are both clean on the touched files.

Please indicate you've done the following:

  • Made sure tests are passing and test coverage is added if needed.
  • Made sure commit message follow the rule of Conventional Commits specification.
  • Considered the docs impact and opened a new docs issue or PR with docs changes if needed. (No user-facing behaviour or docs change — Which() is internal.)

…ernal 'which'

cmd.Which() previously shelled out to `which <name>` to determine whether
a binary was on PATH. On distributions that do not ship a `which` package
by default — Arch Linux is the canonical example, but the same applies to
several minimal container images — `which` itself is missing, so every
call to Which() returned false and 1Panel reported core dependencies
(notably Docker) as 'not installed' even when they were running normally.

Switch the primary path to Go's exec.LookPath, which uses the process
PATH directly and has no external dependency. The original shell-out is
preserved as a fallback so any environment where the agent's PATH
differs from the user's interactive shell PATH (the original reason the
shell-out existed) keeps working unchanged.

Both copies are updated (agent/utils/cmd/cmd.go and core/utils/cmd/cmd.go)
and a small unit test is added to each package to guard the regression.

Fixes 1Panel-dev#12605

Signed-off-by: Sanjay Santhanam <51058514+Sanjays2402@users.noreply.github.com>
@f2c-ci-robot
Copy link
Copy Markdown

f2c-ci-robot Bot commented May 3, 2026

Adding the "do-not-merge/release-note-label-needed" label because no release-note block was detected, please follow our release note process to remove it.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@f2c-ci-robot
Copy link
Copy Markdown

f2c-ci-robot Bot commented May 3, 2026

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign ssongliu for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Docker is misdetected on Arch Linux because agent cmd.Which() depends on external which

1 participant