Skip to content

fix(local): pin kind worker node names and select the fleet by hostname - #683

Merged
giuliocalzo merged 8 commits into
NVIDIA:mainfrom
giuliocalzo:feat/kind-control-plane-node-name
Aug 19, 2026
Merged

fix(local): pin kind worker node names and select the fleet by hostname#683
giuliocalzo merged 8 commits into
NVIDIA:mainfrom
giuliocalzo:feat/kind-control-plane-node-name

Conversation

@giuliocalzo

@giuliocalzo giuliocalzo commented Aug 19, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Pins the worker node names in local/kind/default.kind.yaml to worker-0 / worker-1 via JoinConfiguration, instead of letting them be derived from the cluster name (mokka-worker, mokka-worker2). Stable names make node-targeted commands and docs reproducible across cluster recreations.
  • Switches install_fleet() in local/nvml_mock.tiltfile to pin each per-profile release with nodeSelector.kubernetes.io/hostname=<worker>, and drops the now-redundant nvml-mock/profile worker labels. The mapping is positional: the Nth entry of FLEET_PROFILES lands on worker-N.
  • Fixes the e2e harness to discover node names from the Kubernetes API. Cluster.Nodes() previously enumerated kind get nodes, which reports docker container names, and passed them straight to kubectl — that works only while the two happen to be identical.

Why the harness change is required

Pinning nodeRegistration.name decouples the Kubernetes node name from the Kind container name. Without the harness fix, every scenario that resolves a node by name fails with Error from server (NotFound): nodes "mokka-worker" not found.

cluster.Node now carries both identities: Name (Kubernetes, for kubectl) and Container (docker, for docker exec). The container name is read from Kind's provider ID, kind://docker/<cluster>/<container>, which keeps pointing at the container after a rename. The docker exec call sites in the GPU Operator and NRI scenarios were updated to use Container. Roles now come from the node-role.kubernetes.io/control-plane label rather than a "worker" substring match, since a pinned name need not describe its role.

The control-plane node deliberately keeps its Kind-derived name: kubeadm names the bootstrap node from InitConfiguration, so a JoinConfiguration patch there is silently ignored.

Test plan

  • make test-e2e-framework and make test pass; golangci-lint --build-tags e2e ./tests/e2e/go/... reports 0 issues
  • New unit tests in cluster_test.go cover renamed nodes, label-derived roles, non-Kind provider IDs, ordering, and malformed input
  • Verified against a live Kind cluster with a renamed worker: node worker-0 resolves to container rename-probe-worker
  • Verified unchanged behaviour on a cluster without renames: names and containers match, roles correct
  • helm template renders a flat kubernetes.io/hostname: worker-0 under nodeSelector
  • tilt alpha tiltfile-result -- --multi-gpu-profile pins a100 to worker-0 and t4 to worker-1
  • Full e2e suite in CI (gpu-operator / nri / nfd / multi-node were the jobs broken by the rename)

@copy-pr-bot

copy-pr-bot Bot commented Aug 19, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@giuliocalzo giuliocalzo changed the title fix(local): pin kind node names to control-0, worker-0, worker-1 fix(local): pin kind node names and pin fleet releases by hostname Aug 19, 2026
Kind derives node names from the cluster name, so the control plane comes
up as mokka-control-plane. Pinning it via JoinConfiguration keeps node
names stable and aligned with the worker naming used by tooling and docs.

Signed-off-by: Giulio Calzolari <gcalzolari@nvidia.com>
Stable worker names make node-targeted commands and docs reproducible
across cluster recreations. Drops the nvml-mock/profile worker labels,
which are no longer used to select nodes in this cluster shape.

Signed-off-by: Giulio Calzolari <gcalzolari@nvidia.com>
The nvml-mock/profile worker labels are gone, so install_fleet() had no
node to select and --multi-gpu-profile left every release Pending. Pin
each release to a worker by kubernetes.io/hostname, which the kubeadm
JoinConfiguration patches now make stable.

Profiles map to workers positionally, so a fail() guards asking for more
profiles than the cluster has workers. The dot in kubernetes.io is
escaped because helm --set otherwise reads it as a path separator and
would nest the key instead of setting the label.

Signed-off-by: Giulio Calzolari <gcalzolari@nvidia.com>
Worker names are sequential, so the Nth profile maps to worker-N without a
parallel list to keep in sync.

Signed-off-by: Giulio Calzolari <gcalzolari@nvidia.com>
@giuliocalzo
giuliocalzo force-pushed the feat/kind-control-plane-node-name branch from 7674b4f to 7af04ba Compare August 19, 2026 11:33
@giuliocalzo giuliocalzo self-assigned this Aug 19, 2026
@giuliocalzo giuliocalzo added kind/bug Defect; per DGXC OSS policy bug template. kind/feature Feature request or enhancement. and removed kind/bug Defect; per DGXC OSS policy bug template. labels Aug 19, 2026
@giuliocalzo
giuliocalzo marked this pull request as draft August 19, 2026 11:48
kubeadm names the bootstrap node from InitConfiguration, so the
JoinConfiguration patch never applied and the node stayed
mokka-control-plane. Drop the patch rather than convert it: nothing
selects the control plane by name.

Signed-off-by: Giulio Calzolari <gcalzolari@nvidia.com>
…names

Cluster.Nodes() enumerated `kind get nodes`, which reports docker container
names, and callers passed those straight to kubectl. Once a cluster config
pins nodeRegistration.name the two diverge and every node lookup 404s.

Read nodes from the Kubernetes API instead, keeping the container name from
Kind's provider ID (kind://docker/<cluster>/<container>) so the `docker exec`
call sites in the GPU Operator and NRI scenarios still reach the right
container. Roles now come from the control-plane label rather than a "worker"
substring, since pinned names need not describe the role.

Signed-off-by: Giulio Calzolari <gcalzolari@nvidia.com>
@giuliocalzo giuliocalzo changed the title fix(local): pin kind node names and pin fleet releases by hostname fix(local): pin kind worker node names and select the fleet by hostname Aug 19, 2026
Node discovery reads a full `kubectl get nodes -o json`, which Run tees to
the Ginkgo writer. RunQuiet still captures the body for Result and CmdError,
so failures stay diagnosable without the several-hundred-line echo.

Signed-off-by: Giulio Calzolari <gcalzolari@nvidia.com>
@giuliocalzo
giuliocalzo marked this pull request as ready for review August 19, 2026 13:00

@ArangoGutierrez ArangoGutierrez left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Nothing here blocks merge.

The Name/Container split lands cleanly. Every docker exec path now takes Container and the kube-side lookups still take Name, including the one place it would have been easy to miss (nriPluginPodOnNode gets victim.Name, wedgeNRIPlugin gets victim.Container). Reading the role off node-role.kubernetes.io/control-plane rather than a substring of the name is the right move once names are pinned, and containerName's fallback keeps a non-Kind providerID from producing garbage. The helm escaping checks out too: flags reach helm_resource as argv, so the backslash in kubernetes.io is not re-read by a shell. I ran the new package tests and they pass under make test-e2e-framework, which CI does invoke.

  1. All three inputs here are already decided by the regex, so the length bound is untested: deleting len(name) == 0 || len(name) > 40 leaves the test green. A 41-character lowercase name would pin the bound the doc comment justifies. (tests/e2e/go/framework/cluster/cluster_test.go:99)

Every existing ValidateName case fails on the regex alone, so the 1..40
character check was unpinned: deleting it kept the test green. Add inputs
either side of the bound.

Signed-off-by: Giulio Calzolari <gcalzolari@nvidia.com>
@giuliocalzo

Copy link
Copy Markdown
Collaborator Author

Good catch on the untested length bound — you're right that every existing case fails on the regex alone, so len(name) == 0 || len(name) > 40 could have been deleted with the test staying green.

Fixed in 5ac2068 with cases either side of the bound: a 40-character name passes, a 41-character one fails. I verified it actually pins the check by deleting the length guard and confirming the test goes red at the 41-character assertion, then restoring it.

@roma-glushko roma-glushko 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.

I like the idea to keep consistent. I think the other cluster already has stable worker names.

@giuliocalzo
giuliocalzo merged commit 886fc73 into NVIDIA:main Aug 19, 2026
36 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kind/feature Feature request or enhancement.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants