Skip to content

index: resolve owner names in SQL; fix path defaulting, ls <file>, and config errors#344

Merged
sundereshwar merged 3 commits into
mainfrom
sunder/feat/index-resolver-and-ux-fixes
Jul 2, 2026
Merged

index: resolve owner names in SQL; fix path defaulting, ls <file>, and config errors#344
sundereshwar merged 3 commits into
mainfrom
sunder/feat/index-resolver-and-ux-fixes

Conversation

@sundereshwar

Copy link
Copy Markdown
Member

What does this PR do / why do we need it?

Owner/group name resolution moves into the GUFI query, plus a set of path-handling, formatting, and config-validation fixes for the beegfs index subcommands.

  • uid/gid resolution in SQL: ls/find/stat now select uidtouser(uid)/ gidtogroup(gid) in their output templates instead of resolving in Go via os/user. The CGO-disabled binary's os/user only reads /etc/passwd and /etc/group, so NSS-backed (LDAP/SSSD) names never resolved and showed as numbers (e.g. gid 5900 instead of "thinparq"). The GUFI helpers run in the index process (glibc -> NSS), so names resolve on the index host, matching how a remote index already resolves them. The Go lookupUID/ lookupGID helpers are removed. Aggregate INSERT sources stay numeric; FindAggGSelect resolves at output.

  • stat formatting: mode is rendered octal/symbolic (0644/-rw-r--r--) and uid/gid as num/name (1000/alice), matching gufi_stat. The resolved name columns are selected next to uid/gid.

  • default path for stats/info/query: an omitted path now defaults to "." (which resolves to the mount root / whole index) instead of the cwd. The cwd default failed with "not under index root" when run outside the mount, notably for a remote index where the mount-anchoring step is skipped. This matches ls/find/stat.

  • ls : a file argument is now listed from its parent directory with an exact name match (new LsTargetIsFile/LsFile), like ls(1)/gufi_ls, instead of returning nothing. File-vs-dir is detected locally with a cheap stat and, for a remote index, by probing the path's own summary row over gufi_query. The cmd also checks the parent index dir so a file path no longer trips "no index found".

  • stats median: median-leaf-* reuse GUFI's median() aggregate instead of a hand-rolled AVG over ORDER BY/LIMIT/OFFSET.

  • .beegfs.index validation: a malformed or unreadable file is now a hard error, raised once in the index command's PersistentPreRunE, naming the expected single [index] table. Previously it was logged at Warn and silently ignored, then surfaced confusingly later as "index root not set". loadDotIndex/DotIndexPath return the error; ApplyDotIndexOverrides leaves cfg unchanged on a bad file (the PreRun check has already reported it).

  • ls --skip: clarify the flag help (FILE lists directory basenames to prune, not a path to skip)

Related Issue(s)

Required when applicable.

Where should the reviewer(s) start reviewing this?

Only required for larger PRs when this may not be immediately obvious.

Are there any specific topics we should discuss before merging?

Not required.

What are the next steps after this PR?

Not required.

Checklist before merging:

Required for all PRs.

When creating a PR these are items to keep in mind that cannot be checked by GitHub actions:

  • Documentation:
    • Does developer documentation (code comments, readme, etc.) need to be added or updated?
    • Does the user documentation need to be expanded or updated for this change?
  • Testing:
    • Does this functionality require changing or adding new unit tests?
    • Does this functionality require changing or adding new integration tests?
  • Git Hygiene:

For more details refer to the Go coding standards and the pull request process.

…d config errors

  Owner/group name resolution moves into the GUFI query, plus a set of
  path-handling, formatting, and config-validation fixes for the `beegfs
  index` subcommands.

  - uid/gid resolution in SQL: ls/find/stat now select uidtouser(uid)/
    gidtogroup(gid) in their output templates instead of resolving in Go via
    os/user. The CGO-disabled binary's os/user only reads /etc/passwd and
    /etc/group, so NSS-backed (LDAP/SSSD) names never resolved and showed as
    numbers (e.g. gid 5900 instead of "thinparq"). The GUFI helpers run in
    the index process (glibc -> NSS), so names resolve on the index host,
    matching how a remote index already resolves them. The Go lookupUID/
    lookupGID helpers are removed. Aggregate INSERT sources stay numeric;
    FindAggGSelect resolves at output.

  - stat formatting: mode is rendered octal/symbolic (0644/-rw-r--r--) and
    uid/gid as num/name (1000/alice), matching gufi_stat. The resolved name
    columns are selected next to uid/gid.

  - default path for stats/info/query: an omitted path now defaults to "."
    (which resolves to the mount root / whole index) instead of the cwd. The
    cwd default failed with "not under index root" when run outside the
    mount, notably for a remote index where the mount-anchoring step is
    skipped. This matches ls/find/stat.

  - ls <file>: a file argument is now listed from its parent directory with
    an exact name match (new LsTargetIsFile/LsFile), like ls(1)/gufi_ls,
    instead of returning nothing. File-vs-dir is detected locally with a
    cheap stat and, for a remote index, by probing the path's own summary
    row over gufi_query. The cmd also checks the parent index dir so a file
    path no longer trips "no index found".

  - stats median: median-leaf-* reuse GUFI's median() aggregate instead of a
    hand-rolled AVG over ORDER BY/LIMIT/OFFSET.

  - .beegfs.index validation: a malformed or unreadable file is now a hard
    error, raised once in the index command's PersistentPreRunE, naming the
    expected single [index] table. Previously it was logged at Warn and
    silently ignored, then surfaced confusingly later as "index root not
    set". loadDotIndex/DotIndexPath return the error; ApplyDotIndexOverrides
    leaves cfg unchanged on a bad file (the PreRun check has already
    reported it).

  - ls --skip: clarify the flag help (FILE lists directory basenames to
    prune, not a path to skip)
@sundereshwar sundereshwar self-assigned this Jun 29, 2026
@sundereshwar
sundereshwar requested a review from a team as a code owner June 29, 2026 15:13
…d info gaps

  Three changes from the resolver-branch review.

  1. Selective owner-name resolution (find/ls). The templates selected
     uidtouser(uid)/gidtogroup(gid) in every query, but GUFI resolves those
     with an uncached getpwuid_r/getgrgid_r per row while the user/group
     columns are displayed only with -l/--columns/debug. A default listing of
     a large tree therefore ran a name lookup per row and discarded it. The
     templates now take an owner-column fragment (ownerCols) that is numeric
     by default and resolved only when the column will actually be shown
     (ownerNamesRequested honors -l, --columns, and debug). Resolution still
     happens in SQL on the index host, so it stays correct for a remote index.
     stat is unchanged (single row, always shows id/name).

  2. Remote stat no longer masks failures. The directory-summary branch
     discarded the row-stream wait error and fell through to the file spec
     whenever it was non-nil, so a genuine ssh/SQL/parse error was reported as
     a confusing "no index entry found". A non-directory path exits cleanly
     with no rows, so only an empty result falls through now; a real error is
     returned.

  3. index info flags a missing tree summary. When no summary row exists
     (e.g. --skip-treesummary) the stats columns render "-" instead of blank
     cells, distinguishing "not computed" from zero.
…ns all

  Two output fixes to the index CLI:

  - ls of a nonexistent path exited 0 silently instead of erroring. The
    ls <file> support routes a file/name target through LsFile, but a typo'd
    or deleted path takes that same path and matches no rows; with no
    not-found check the command printed nothing and returned success. Error
    when a file target (isFile) matches zero rows, mirroring stat. An empty
    directory takes the Ls path (isFile==false) and still lists as before.

  - --columns all displayed numeric uid/gid. ownerNamesRequested enabled name
    resolution only for an explicit "user"/"group" column, but cmdfmt expands
    "all" to every column, so the owner columns were shown yet left numeric.
    Treat "all" as requesting owner names.

@iamjoemccormick iamjoemccormick left a comment

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.

Just one sticking point, otherwise this LGTM.

Comment thread ctl/pkg/ctl/index/find.go
Comment thread ctl/pkg/ctl/index/find.go

@iamjoemccormick iamjoemccormick left a comment

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.

LGTM as long as the one open question isn't a valid concern.

@manishasalve manishasalve 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.

Looks good to me.

@sundereshwar
sundereshwar merged commit 623295a into main Jul 2, 2026
7 checks passed
@sundereshwar
sundereshwar deleted the sunder/feat/index-resolver-and-ux-fixes branch July 2, 2026 11:43
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.

3 participants