kubectl Explain Completion And Describe Output Fixes


kubernetes/kubectl took four commits on 18 September 2026: 12 files, 839 insertions, 95 deletions. Shell completion for kubectl explain is the piece operators will use. Two kubectl describe fixes correct node resource percentages and a bogus endpoints suffix.

The explain completion commit adds pkg/cmd/explain/completion.go and hooks it from pkg/cmd/explain/explain.go:

ValidArgsFunction: resourceFieldCompletionFunc(f, func() string { return flags.APIVersion }),

The callback reads --api-version after flags are parsed. The helper receives the value directly.

With no dot, completion lists resource names, appends a dot, and tells the shell not to insert a space. Names come from CompGetResourceList in pkg/util/completion/completion.go. The helper is now exported, and the verb filter is variadic. Get style completion still passes "get". Explain passes none, so resources that do not support get still complete. The apiresources call sets Cached to true and still has no 5 second request timeout.

A token with a dot is parsed the same way Run parses it. An empty --api-version uses SplitAndParseResourceRequestWithMatchingPrefix and can offer deployments.apps. when that name resolves to itself. A set flag uses SplitAndParseResourceRequest, then overwrites group and version from the flag. deployments.spec with --api-version=apps/v1 completes the apps/v1 fields the flag names. The RESTMapper preferred version is used only when the flag is empty. pkg/cmd/explain/completion_test.go serves autoscaling in two versions to cover a pin that is not the preferred one. An unknown or malformed version returns nothing.

Field names come from the OpenAPI v3 document. fieldNamesForGVR resolves the kind, loads the group version spec through k8s.io/client-go/openapi3, and walks #/components/schemas/. resolveToObject follows $ref, the single element allOf Kubernetes emits when a description sits beside a reference, and array items. Maps and primitives stay leaves, matching the v2 walker this replaces. Expandable names are suggested with a trailing dot and no space. Leaves get a space. A second argument, a .. segment, or a mapper error returns nothing and disables file completion.

The v2 path tried the group’s preferred version when the mapper version was missing from that document. v3 documents and discovery come from the same source, so that fallback is gone. A pinned version the apiserver does not serve completes nothing. The commit message points at kubernetes issue 141455, the proposal to stop serving v2.

The same commit also moves k8s.io/api, k8s.io/apimachinery, k8s.io/client-go, k8s.io/component-helpers, and the k8s.io/code-generator replace to pseudo versions from 16 and 17 September. 583 lines added, 18 removed. Each field tab calls the apiserver. There is no local cache of field names.

The node percentage commit edits describeNodeResource in pkg/describe/describe.go. Per pod rows in Non-terminated Pods divided CPU and memory by allocatable with no zero check. The Allocated resources block already returned 0 in that case. On a node with no status yet, a Node created by hand, or some virtual nodes, the division produced +Inf or NaN, and the int64 conversion printed -9223372036854775808% on every pod.

percentOf is the guard. Totals, ephemeral storage, and hugepage rows use it too:

func percentOf(value, total int64) int64 {
    if total == 0 {
        return 0
    }
    return int64(float64(value) / float64(total) * 100)
}

The cast still truncates toward zero. Limits can still print over 100 percent. The header already says the totals may be overcommitted.

The rows and the totals also disagreed during an in place resize. Rows already called PodRequests and PodLimits with UseStatusResources: true. getPodsTotalRequestsAndLimits used the pod spec only. A spec that still requests 100m, with container status already at 500m, printed 500m (50%) on the row and 100m (10%) in the totals on a 1 CPU node. Both paths now pass UseStatusResources: true and keep SkipPodLevelResources: false.

TestDescribeNodeResource in pkg/describe/describe_test.go covers a normal node (250m is 25 percent of 1 CPU), an empty allocatable (0%), and the resize case (row and CPU total both 500m (50%)). The commit adds 109 lines and removes 36.

The endpoints commit changes formatEndpointSlices in the same file. Describe prints at most three ready endpoints, then + N more.... The old code set a more flag when it visited a fourth endpoint, before the readiness check, and only counted ready ones. Three ready endpoints followed by any that are not ready printed:

Endpoints:  10.0.0.1:80,10.0.0.2:80,10.0.0.3:80 + 0 more...

The not ready address flipped the flag and was then skipped. The headless branch, slices with no ports, did the same with bare addresses.

The flag is gone. A ready endpoint is appended while len(list) < 3, and every ready endpoint increments count. The suffix is printed only when count > 3. A nil Ready condition still counts as ready. An explicit false is still omitted. TestFormatEndpointSlices expects + 1 more... for a fourth ready endpoint, including the headless form, and expects no suffix when the extras are not ready. Traffic is unchanged. The commit adds 81 lines and removes 10.

The dependency commit is titled depencencies: bump to Gomega v1.43.1 and Ginkgo v2.33.0, typo included. Ginkgo moves from v2.32.0 to v2.33.0. Gomega moves from v1.40.0 to v1.43.1. The message cites two upstream reasons: Gomega’s newer go.yaml.in/yaml/v3 drops gopkg.in/check.v1, and Ginkgo can emit JUnit for testgrid in the main kubernetes repository (pull request 141859 there).

The commit object is not what master builds. Its replace block points at sibling staging paths (../api, ../client-go, and the rest). That layout exists inside kubernetes/kubernetes, not in a standalone checkout of this repo. The publishing bot merge onto master keeps the published pseudo versions. go.mod changes by the two require lines, and go.sum changes by the matching hashes. After that merge, gopkg.in/check.v1 is still in go.sum, and go.yaml.in/yaml/v3 is still v3.0.5. No kubectl command changes.

Build from master. Checking out the dependency commit makes go look for sibling directories this repository does not contain. The raw commit is 66 insertions and 31 deletions. The merge that reached master keeps 6 and 6.

  • Field completion needs a reachable apiserver and a v3 schema that actually lists the fields. Pin --api-version to a version the cluster does not serve and the list is empty on purpose.
  • Scrapers of describe text will see the garbage percentage and the + 0 more... suffix disappear. Allocated resources follows container status during an in place resize. SkipPodLevelResources stays false, so pod level resources remain in the total.
  • The Ginkgo pin is not in the kubectl binary. Follow the JUnit work in the main repository if testgrid is the point. Ignore the relative replace lines on the dependency commit when you build.