Skip to content

fix: stage the cluster image weka CLI for drivers-builder - #2789

Merged
graphite-app[bot] merged 1 commit into
mainfrom
09-02-fix_stage_the_cluster_image_weka_cli_for_drivers-builder
Sep 3, 2026
Merged

fix: stage the cluster image weka CLI for drivers-builder#2789
graphite-app[bot] merged 1 commit into
mainfrom
09-02-fix_stage_the_cluster_image_weka_cli_for_drivers-builder

Conversation

@rugggger

@rugggger rugggger commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

The copy-cli init container staged whatever weka resolved to in the
builder image, so the driver extraction ran an old CLI pinned in
builder-ubuntu*-v1 rather than the one shipped with the cluster image
being built. Pick the CLI source the same way the loader already does,
via weka_get_copy_local_driver_files, and resolve the flag through the
populating fetch so a cold cache defers pod creation instead of
silently falling back to the builder image.

Co-Authored-By: Claude Opus 5 (1M context) noreply@anthropic.com

@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

rugggger commented Sep 2, 2026

Copy link
Copy Markdown
Contributor Author

How to use the Graphite Merge Queue

Add the label main-merge-queue to this PR to add it to the merge queue.

You must have a Graphite account in order to use the merge queue. Sign up using this link.

An organization admin has required the Graphite Merge Queue in this repository.

Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.

This stack of pull requests is managed by Graphite. Learn more about stacking.

@claude

claude Bot commented Sep 2, 2026

Copy link
Copy Markdown

Claude finished @rugggger's task in 6m 31s —— View job


Code review: stage the cluster image weka CLI for drivers-builder

The core diagnosis is right and the fix is the correct shape: copy-cli was staging whatever weka resolved to inside builder-ubuntu*-v1, and gating on WekaGetCopyLocalDriverFiles is the same signal GetLoaderImageForNode already uses. Two issues worth addressing before merge.

1. The flags and the staged CLI can describe different images — funcs_pod_ensure.go:126-133

r.GetFeatureFlags(ctx) resolves through GetFeatureFlagsForContainer, which keys on Status.LastAppliedImage and only falls back to Spec.Image when that is empty (operations/feature_flags.go:102-105). The image actually staged is container.Spec.Image.

ensurePod is gated on PodNotSet, so for an existing drivers-builder it runs precisely at pod re-creation — the one moment the two diverge during an image roll (Spec.Image already new, LastAppliedImage advanced only later at flow_active_state.go:1097). Upgrading into an image that has the flag then still resolves false from the old image and stages the builder CLI again — the original bug, on the upgrade path. The reverse direction stages a cluster CLI that cannot copy driver files at all.

GetLoaderImageForNode sidesteps this by resolving flags for an explicit image (drivers.go:69); resolving for container.Spec.Image via GetFeatureFlagsForImage would do the same here. Fix this →

2. Non-transient flag-fetch failures permanently block driver builds — funcs_pod_ensure.go:126-129

Deferring on a cold cache is the stated intent and is fine for WaitError. But every error is returned, and the step carries OnFail: r.setErrorStatus, so a hard failure (ad-hoc container not creatable/schedulable, image unpullable on that node, malformed feature_flags.json) means the builder pod is never created → drivers never built → all driver consumers on the node stuck, no self-healing. Previously this decision degraded to the builder image. Suggest propagating WaitError to defer and falling back to builderImage on other errors.

Related, flagged as a question rather than a finding: the ad-hoc fallback creates an adhoc-op-with-container pinned to the builder's node (get_feature_flags.go:257-267). If that mode is RequiresDrivers(), it waits for drivers on the node whose drivers this builder was going to produce. I couldn't verify — pkg/weka-k8s-api is an unpopulated submodule in this checkout. The cluster-creation path already spins up the same ad-hoc container early, which suggests it's driver-free, but this is the first caller sitting behind a drivers-builder.

Minor

  • GetBuilderCliImage(flags, image, builderImage) — two adjacent string params where a swap compiles and silently restores the old behavior; clusterImage would make call sites self-checking.
  • GetLoaderImageForNode and GetBuilderCliImage now state the same policy twice with different failure semantics; the loader could delegate to the new helper.
  • No test, though internal/drivers/drivers_test.go exists and the function is pure with three branches.

Checked, no issue

  • errors.Wrap vs WaitError: pkg/errors implements Unwrap(), so errors.As still matches; the SSDProxy branch just below wraps identically.
  • Passing the ImageOverrideAnnotation value through as the fallback CLI image is consistent with it being the pod image.
  • Parent PR fix: match full RHEL and Rocky product names in OS normalization #2788 is unrelated (OS-name regex) — no interaction.

No commits pushed; this is review feedback only.
· branch

Comment on lines +126 to +133
builderFlags, ffErr := r.GetFeatureFlags(ctx)
if ffErr != nil {
return errors.Wrap(ffErr, "failed to get feature flags for drivers-builder")
}

payloadBytes, _ := json.Marshal(map[string]string{ //nolint:errcheck // error return value intentionally not checked
"targetImage": container.Spec.Image,
"cliImage": image,
"cliImage": drivers.GetBuilderCliImage(builderFlags, container.Spec.Image, image),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The flags and the CLI image can refer to two different images.

r.GetFeatureFlags(ctx)operations.GetFeatureFlagsForContainer keys the lookup on container.Status.LastAppliedImage, falling back to Spec.Image only when it is empty (internal/controllers/operations/feature_flags.go:102-105). But the value handed to GetBuilderCliImage — and staged as cliImage/targetImage — is container.Spec.Image.

ensurePod is gated on PodNotSet (flow_active_state.go:319-324), so the one moment it runs for an existing drivers-builder is pod (re)creation — which is exactly when the two diverge during an image roll: Spec.Image is already the new cluster image while Status.LastAppliedImage still holds the old one (it is only advanced later, flow_active_state.go:1097).

Concrete failure: cluster upgraded from an image without WekaGetCopyLocalDriverFiles to one with it. Flags are resolved for the old image → flag false → cliImage = builder image → the driver extraction again runs the stale builder CLI against the new targetImage, i.e. the bug this PR is fixing, on the upgrade path. The mirror case is worse: old image has the flag, new one doesn't → we stage the new cluster image's CLI, which cannot copy driver files at all.

GetLoaderImageForNode avoids this by resolving flags for an explicit image (drivers.go:69). Suggest doing the same here — resolve for container.Spec.Image via operations.GetFeatureFlagsForImage with AdhocContainerParams{Image: container.Spec.Image, ...} — so the flag and the CLI it selects always describe one image.

Minor, same lines: builderFlags reads as "flags of the builder image", but these are (meant to be) the cluster image's flags. clusterFlags would be less misleading.

Comment on lines +126 to +129
builderFlags, ffErr := r.GetFeatureFlags(ctx)
if ffErr != nil {
return errors.Wrap(ffErr, "failed to get feature flags for drivers-builder")
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

A non-transient flag-fetch failure now permanently blocks driver builds.

Deferring on a cold cache is the stated intent and is fine for the WaitError case. But this returns every error, and the step carries OnFail: r.setErrorStatus (flow_active_state.go:319-324), so a hard failure (ad-hoc container can't be created/scheduled, image not pullable on that node, malformed feature_flags.json, operator-deployment lookup failure in GetAdhocContainer) means the drivers-builder pod is never created → drivers are never built → every driver consumer on that node stays stuck, with no self-healing path. Before this change that decision degraded to the builder image.

Consider splitting the two cases: propagate WaitError to defer, and on any other error log + fall back to builderImage (previous behavior). Cheap insurance for a step that sits on the critical path of all driver loading.

Two related things worth confirming rather than assuming:

  1. Cold-cache deadlock risk on a driverless node. GetFeatureFlagsOperation falls back to creating an ad-hoc adhoc-op-with-container WekaContainer pinned to the builder's node (get_feature_flags.go:257-267). If RequiresDrivers() is true for that mode, that pod waits for drivers on a node whose drivers are being built by the very builder we are blocking → deadlock. I couldn't check (pkg/weka-k8s-api is an unpopulated submodule in this checkout). The cluster-creation path already spins up the same ad-hoc container early (steps_cluster_creation.go:233), which suggests it's driver-free — but this is the first caller that runs it behind a drivers-builder, so it's worth being sure.

  2. errors.Wrap and WaitError detection. github.com/pkg/errors has implemented Unwrap() since v0.9.0, so errors.As still sees through it — matching the idiom in funcs_numa_dra_test.go:31. Only a concern if the engine type-asserts instead. The pre-existing SSDProxy branch just below (line 143-146) wraps identically, so this is consistent either way.

Comment on lines +81 to +92
// GetBuilderCliImage picks the image that supplies the weka CLI staged for the
// drivers-builder init containers. The extraction step bind-mounts over /opt/weka,
// where the cluster image keeps its CLI, so a CLI is always staged out of band;
// prefer the cluster image's own CLI when it can copy driver files itself.
func GetBuilderCliImage(flags *domain.FeatureFlags, image, builderImage string) string {
if flags != nil && flags.WekaGetCopyLocalDriverFiles {
// innovation cli --kernel-build-id etc.
return image
}

return builderImage
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Two things here:

Parameter naming invites the exact bug being fixed. GetBuilderCliImage(flags, image, builderImage) takes two adjacent string params; swapping them compiles cleanly and silently restores the old "always use the builder CLI" behavior. Rename imageclusterImage to make the call site self-checking.

The policy now lives in two places. GetLoaderImageForNode (line 68-79) expresses the identical rule with a different fallback shape. Having them drift is how the loader and the builder end up staging different CLIs for the same image. Since the new helper is the pure form of the decision, the loader can just delegate:

func GetLoaderImageForNode(ctx context.Context, node *v1.Node, image string) string {
	flags, err := services.GetFeatureFlags(ctx, image)
	if err != nil {
		flags = nil
	}
	return GetBuilderCliImage(flags, image, GetBuilderImageForNode(node))
}

That also makes the differing failure semantics explicit (loader: cache-only, silent fallback; builder: populating fetch, defer) rather than implicit in two separate bodies.

Comment thread internal/drivers/drivers.go Outdated
// drivers-builder init containers. The extraction step bind-mounts over /opt/weka,
// where the cluster image keeps its CLI, so a CLI is always staged out of band;
// prefer the cluster image's own CLI when it can copy driver files itself.
func GetBuilderCliImage(flags *domain.FeatureFlags, image, builderImage string) string {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

GetBuilderCliImage is a pure function with three branches (nil flags / flag off / flag on) and internal/drivers/drivers_test.go already exists — a small table test would pin the flags == nil fallback in particular, since that's the branch that decides behavior whenever flag resolution is unavailable.

The copy-cli init container staged whatever `weka` resolved to in the
builder image, so the driver extraction ran an old CLI pinned in
builder-ubuntu*-v1 rather than the one shipped with the cluster image
being built. Pick the CLI source via weka_get_copy_local_driver_files,
the same flag the loader already keys on, and route both callers through
one helper so the two cannot drift apart.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@rugggger
rugggger force-pushed the 09-02-fix_stage_the_cluster_image_weka_cli_for_drivers-builder branch from 7f22ad8 to f6d58f8 Compare September 2, 2026 11:47
@rugggger
rugggger marked this pull request as ready for review September 2, 2026 14:31
@rugggger
rugggger requested a review from a team as a code owner September 2, 2026 14:31
@graphite-app

graphite-app Bot commented Sep 2, 2026

Copy link
Copy Markdown

Graphite Automations

"Add anton/matt/sergey/kristina as reviwers on operator PRs" took an action on this PR • (09/02/26)

3 reviewers were added to this PR based on Anton Bykov's automation.

@graphite-app

graphite-app Bot commented Sep 3, 2026

Copy link
Copy Markdown

Merge activity

  • Sep 3, 10:50 AM UTC: rugggger added this pull request to the Graphite merge queue.
  • Sep 3, 10:51 AM UTC: CI is running for this pull request on a draft pull request (#2793) due to your merge queue CI optimization settings.
  • Sep 3, 11:22 AM UTC: The Graphite merge queue removed this pull request due to downstack failures on PR #2788.
  • Sep 3, 11:22 AM UTC: The Graphite merge queue removed this pull request due to downstack failures on PR #2788.
  • Sep 3, 3:15 PM UTC: rugggger added this pull request to the Graphite merge queue.
  • Sep 3, 3:15 PM UTC: CI is running for this pull request on a draft pull request (#2795) due to your merge queue CI optimization settings.
  • Sep 3, 4:11 PM UTC: Merged by the Graphite merge queue via draft PR: #2795.

Base automatically changed from 09-02-fix_match_full_rhel_and_rocky_product_names_in_os_normalization to main September 3, 2026 16:11
@graphite-app
graphite-app Bot merged commit f6d58f8 into main Sep 3, 2026
22 of 24 checks passed
@graphite-app
graphite-app Bot deleted the 09-02-fix_stage_the_cluster_image_weka_cli_for_drivers-builder branch September 3, 2026 16:11
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.

2 participants