Repository navigation
fix: stop adding SparkApplication owner reference to executor pods - #3152
google-oss-prow[bot] merged 2 commits into
Conversation
|
🎉 Welcome to the Kubeflow Spark Operator! 🎉 Thanks for opening your first PR! We're happy to have you as part of our community 🚀 Here's what happens next:
Join the community:
Feel free to ask questions in the comments if you need any help or clarification! |
|
Round 1 self-review (AI agent operated by me; I review every revision). Marking ready for review because:
Open question for maintainers: #2670 added the reference for Kueue; if any other consumer relies on it, the alternative is an explicit executor cleanup on driver deletion. |
There was a problem hiding this comment.
🔵 Needs a closer look
The change alters Kubernetes ownership/garbage-collection semantics with cross-controller (Kueue) implications that warrant final human verification.
Pull request overview
This PR fixes a garbage-collection bug (issue #2961) where executor pods were not cascade-deleted when only the driver pod was removed (e.g. on spec.suspend=true via Kueue preemption). The root cause was a second, non-controller ownerReference pointing at the SparkApplication that the operator added to executor pod templates at submission time (introduced in #2670). Since Kubernetes GC only deletes a dependent once all owners are gone, this blocked the cascade from the driver pod. The fix removes that extra owner reference so executors rely solely on their controller reference to the driver pod.
Changes:
- Remove the block in
buildExecutorPodTemplatethat appended a non-controllerSparkApplicationowner reference to executor pod templates, replacing it with an explanatory comment. - Update
TestExecutorPodTemplateContentsandTestSubmitPodTemplatesso executor templates carry only user-supplied owner references.
File summaries
| File | Description |
|---|---|
internal/controller/sparkapplication/submission.go |
Drops the executor-template SparkApplication owner reference; driver template still gets its controller reference. |
internal/controller/sparkapplication/submission_test.go |
Removes the expected SparkApplication owner reference from executor template expectations; user-supplied refs preserved. |
internal/controller/sparkapplication/rest_submission_test.go |
Asserts executor pod template now carries no owner references. |
I verified that the slices, reflect, and metav1 imports remain in use by buildDriverPodTemplate, the appNonControllerOwnerReference test helper is still referenced by the "already has owner references" case, the webhook's addOwnerReference returns early for non-driver pods (so the reference is not re-added), and GetOwnerReference still sets Controller: true for the driver template. No issues were found.
Review details
- Files reviewed: 3/3 changed files
- Comments generated: 0
- Review effort level: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Since kubeflow#2670 executor pods carried two owners: the driver pod (controller=true, set by Spark) and the SparkApplication (non-controller, added at submission time). Kubernetes garbage collection only deletes a dependent once all owners are gone, so deleting the driver pod (manual delete, spec.suspend=true, Kueue preemption) left executor pods orphaned until the SparkApplication itself was deleted. Drop the extra owner reference so executors are cascade-deleted with the driver pod. Deleting the SparkApplication still cascades through the driver pod to the executors. Issue: kubeflow#2961 Signed-off-by: KR Ravindra <42912207+KR-Ravindra@users.noreply.github.com>
bcabf35 to
c6c3816
Compare
RobuRishabh
left a comment
There was a problem hiding this comment.
Hi @KR-Ravindra thanks for the contribution, the PR looks good to me
@tariq-hasan need a suggestion here unit tests are enough for merge but how about add a e2e test here that submits an app, deletes the driver, and asserts executors disappear would lock in the fix or do you think its over-engineering.
and a quick question if anyone has answer to it, Is there any other tool (not Kueue, not spark-operator) that depends on executors having a direct SparkApplication owner ref?
|
/ok-to-test |
|
@RobuRishabh thanks for the review. Happy to add the e2e test if @tariq-hasan wants it: a case in On the ownerRef question: executor pods keep the owner reference Spark itself sets (the driver pod, |
|
I'm thinking we might be able to add assertions here to test the change. spark-operator/test/e2e/sparkapplication_test.go Lines 456 to 461 in cfc9cba For the use cases I'm thinking we do not really have a clearly defined one: #2670 (comment). We can always revisit if we do see actual use cases that require this owner reference. @vjanelle @vikas-saxena02 Would appreciate further thoughts on this. |
Extend the spark-pi suspend/resume e2e test: wait for an executor pod to exist before suspending, then after the application reaches Suspended assert that no driver or executor pods labelled with the application name remain. With the extra SparkApplication owner reference on executors this assertion fails because the executor pods survive the driver pod deletion. Signed-off-by: KR Ravindra <42912207+KR-Ravindra@users.noreply.github.com>
|
@tariq-hasan done in 2b4fb02: the suspend/resume e2e case now waits for an executor pod to exist before suspending and, after the app reaches |
|
Thanks @KR-Ravindra for the contribution. |
Agree with dropping the reference — I think this is the right direction, not just the Executors already carry the owner reference Spark itself sets (driver pod, Worth noting the fix is wider than the reported bug: every path that removes the driver @tariq-hasan there are three things I'd like on the record, but none of them are things I
Happy to take (1) and (2) as follow-ups myself if that's useful. |
|
@vikas-saxena02 thanks, that matches my understanding of the ownership graph. On (3): agreed, the suspend assertion cannot tell a GC cascade from explicit cleanup. I can add the dedicated case (submit, wait for executors Running, delete only the driver pod, |
|
An orphan cascade delete intentionally means ownership is being broken, do
we need to handle that?
…On Wed, Sep 9, 2026 at 5:07 PM KR Ravindra ***@***.***> wrote:
*KR-Ravindra* left a comment (kubeflow/spark-operator#3152)
<#3152 (comment)>
@vikas-saxena02 <https://github.com/vikas-saxena02> thanks, that matches
my understanding of the ownership graph. On (3): agreed, the suspend
assertion cannot tell a GC cascade from explicit cleanup. I can add the
dedicated case (submit, wait for executors Running, delete only the driver
pod, Eventually assert the executors are gone) to this PR or as a
follow-up PR after this merges, whichever @tariq-hasan
<https://github.com/tariq-hasan> prefers. Taking (1) and (2) as follow-up
issues sounds right to me.
—
Reply to this email directly, view it on GitHub
<#3152?email_source=notifications&email_token=AAFTDSNA4J7NXUL6DRLKLN35OHWELA5CNFSNUABFM5UWIORPF5TWS5BNNB2WEL2JONZXKZKDN5WW2ZLOOQXTKNRRGA2TINJTG4Z2M4TFMFZW63VHNVSW45DJN5XKKZLWMVXHJLDGN5XXIZLSL5RWY2LDNM#issuecomment-5610545373>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAFTDSK5MGZGOJH2YGCMDE35OHWELAVCNFSNUABFKJSXA33TNF2G64TZHMYTCNRRGY2TCOBYHNEXG43VMU5TKMZYGEZDEMBZGUZKC5QC>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
|
@vjanelle I read it the same way. |
|
Also consider clusters with 10s of thousands of executors, if it's a one time scan maybe, but not continuous. |
|
@vjanelle agreed. If that sweep is ever built it should be a one-time pass triggered by the SparkApplication deletion (finalizer), listing by the |
I may be overthinking but it could be due user mistakes, happy to drop this if other think the same way!! |
|
@vikas-saxena02 works for me. If a real user-mistake case turns up later, the one-time label-based sweep is the fix and can go in as a follow-up. |
I actually had this at a client side when one of my guys, did so based on chatgpt advise :D |
|
@KR-Ravindra the changes look good to me |
|
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: vara-bonthu The full list of commands accepted by this bot can be found here. The pull request process is described here DetailsNeeds approval from an approver in each of these files:
Approvers can indicate their approval by writing |
* fix: preserve shell-sensitive Spark Connect configuration values (kubeflow#3051) * fix: preserve shell-sensitive Spark Connect configuration values Signed-off-by: Jay Bharadwaj <jbharadw@openai.com> * refactor: improve Spark Connect shell quoting readability Signed-off-by: Jay Bharadwaj <jbharadw@openai.com> --------- Signed-off-by: Jay Bharadwaj <jbharadw@openai.com> * Chore(Remove go card from readme) - kubeflow#3058 (kubeflow#3060) Signed-off-by: Tamir Krasna <64045253+Tankdoggo@users.noreply.github.com> * chore(deps): bump github.com/prometheus/common from 0.67.5 to 0.70.1 in /test/e2e (kubeflow#3083) Bumps [github.com/prometheus/common](https://github.com/prometheus/common) from 0.67.5 to 0.70.1. - [Release notes](https://github.com/prometheus/common/releases) - [Changelog](https://github.com/prometheus/common/blob/main/CHANGELOG.md) - [Commits](prometheus/common@v0.67.5...v0.70.1) --- updated-dependencies: - dependency-name: github.com/prometheus/common dependency-version: 0.70.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump actions/checkout from 6.0.2 to 7.0.1 (kubeflow#3086) Bumps [actions/checkout](https://github.com/actions/checkout) from 6.0.2 to 7.0.1. - [Release notes](https://github.com/actions/checkout/releases) - [Commits](actions/checkout@v6.0.2...v7.0.1) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 7.0.1 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * feat(ci): Publish Spark Operator binaries with GitHub releases (kubeflow#3078) * initial commit Signed-off-by: Vikas Saxena <Vikas.Saxena.2006@gmail.com> * feat(ci): publish operator binaries with GitHub releases Cross-build spark-operator for linux/amd64 and linux/arm64 in the draft_release job, package with checksums, and attach to the release. Closes kubeflow#3073 Signed-off-by: Vikas Saxena <Vikas.Saxena.2006@gmail.com> * fixing typo as part of my previous PR kubeflow#3056 Signed-off-by: Vikas Saxena <Vikas.Saxena.2006@gmail.com> * Update .github/workflows/release.yaml Co-authored-by: Tariq Hasan <mmtariquehsn@gmail.com> Signed-off-by: Vikas Saxena <90456542+vikas-saxena02@users.noreply.github.com> * fix(ci): stage release binaries outside the repo and harden verification Signed-off-by: Vikas Saxena <Vikas.Saxena.2006@gmail.com> * fix(ci): entrypoint was not part of tar ball so adding it Signed-off-by: Vikas Saxena <Vikas.Saxena.2006@gmail.com> * fix(build): read VERSION from file so an inherited env var cannot double the v prefix Signed-off-by: Vikas Saxena <Vikas.Saxena.2006@gmail.com> --------- Signed-off-by: Vikas Saxena <Vikas.Saxena.2006@gmail.com> Signed-off-by: Vikas Saxena <90456542+vikas-saxena02@users.noreply.github.com> Co-authored-by: Tariq Hasan <mmtariquehsn@gmail.com> * feat: garbage-collect terminated SparkApplications via operator default TTL (kubeflow#3042) * feat: add DefaultTimeToLive alpha feature gate Signed-off-by: dineshkumar181094 <dineshkumar181094@gmail.com> * feat: add EffectiveTimeToLiveSeconds TTL resolution helper Signed-off-by: dineshkumar181094 <dineshkumar181094@gmail.com> * feat: add --default-time-to-live-seconds controller flag Signed-off-by: dineshkumar181094 <dineshkumar181094@gmail.com> * feat: apply operator default TTL when reconciling terminated SparkApplications Signed-off-by: dineshkumar181094 <dineshkumar181094@gmail.com> * feat: expose default TTL via Helm chart Signed-off-by: dineshkumar181094 <dineshkumar181094@gmail.com> * refactor: unify TTL expiry logic and harden default-TTL edges Address code review feedback on the operator default-TTL feature: - Unify expiry into util.IsExpiredWithTTL, the single primitive that takes an explicit (possibly defaulted) TTL; IsExpired delegates to it. Treat a non-positive spec.timeToLiveSeconds as 'expire immediately' everywhere, so an explicit user value always wins over the operator default and behavior is unchanged from before this feature. - Move the expiry decision out of the controller into util; the reconciler now calls util.IsExpiredWithTTL with the effective TTL. - Fix a flaky controller test: drive the app into COMPLETED with a past TerminationTime unconditionally (get-or-create) so the precondition holds even when the object already exists. - Render --default-time-to-live-seconds only when the value is > 0 so a negative value no longer emits the flag; add a chart test for it. Signed-off-by: dineshkumar181094 <dineshkumar181094@gmail.com> * feat: make DefaultTimeToLive gate authoritative and consistent Address further review feedback on the operator default-TTL feature: - Gate the Helm-rendered --default-time-to-live-seconds flag on both the DefaultTimeToLive feature gate (new spark-operator.defaultTimeToLive.enabled helper, mirroring the RestSubmitter one) and a positive value, so the chart no longer emits a flag the controller would ignore at runtime. - Validate the flag at controller startup: error in PreRunE when the gate is enabled but the value is non-positive, and warn (after the logger is set up) when the value is set but the gate is disabled. - Log the operator-default provenance only when the app is actually deleted, instead of on every reconcile of a terminated app. - Make the event filter's resync guard use the effective TTL so an app expired via the operator default is re-admitted for deletion, consistent with the controller's cleanup decision; thread defaultTimeToLiveSeconds through the event filter and add coverage. Signed-off-by: dineshkumar181094 <dineshkumar181094@gmail.com> * chore: add DefaultTimeToLive feature gate to manager manifest The generated controller manifest enumerates all feature gates in its --feature-gates arg. Add DefaultTimeToLive=false so the manifest matches the registered gates and the drift check passes. Signed-off-by: dineshkumar181094 <dineshkumar181094@gmail.com> * fix: reject only negative default TTL and cover the not-yet-expired requeue path Refine the --default-time-to-live-seconds validation and add missing test coverage for the operator default TTL: - Scope the PreRunE guard to negative values only. A negative TTL is never meaningful and is now rejected regardless of the feature gate, while 0 remains the valid 'off' sentinel (even when the gate is enabled) rather than a hard startup error. Update the flag help to match. - Add a controller test for a terminated app that has not yet outlived the operator default TTL (terminated 30s ago, default 60s): assert it is not deleted and is requeued via RequeueAfter computed from the effective TTL. Signed-off-by: dineshkumar181094 <dineshkumar181094@gmail.com> * feat: render a zero default TTL as a valid Helm flag and cover it Make defaultTimeToLiveSeconds=0 a valid, explicitly-rendered value rather than a silently-omitted one: - Change the deployment template guard from 'gt ... 0' to 'ge ... 0' so a zero value renders --default-time-to-live-seconds=0 when the gate is enabled. Negative values are still omitted to avoid the binary's startup rejection. Update the chart test for the zero case accordingly. - Add a controller test proving that with the gate enabled and a zero default TTL, a terminated SparkApplication is neither deleted nor requeued (the zero value disables the default, as intended). Signed-off-by: dineshkumar181094 <dineshkumar181094@gmail.com> * refactor: normalize default TTL configuration Signed-off-by: dineshkumar181094 <dineshkumar181094@gmail.com> --------- Signed-off-by: dineshkumar181094 <dineshkumar181094@gmail.com> * chore(deps): bump github.com/onsi/ginkgo/v2 from 2.27.2 to 2.32.1 in /test/e2e (kubeflow#3095) Bumps [github.com/onsi/ginkgo/v2](https://github.com/onsi/ginkgo) from 2.27.2 to 2.32.1. - [Release notes](https://github.com/onsi/ginkgo/releases) - [Changelog](https://github.com/onsi/ginkgo/blob/master/CHANGELOG.md) - [Commits](onsi/ginkgo@v2.27.2...v2.32.1) --- updated-dependencies: - dependency-name: github.com/onsi/ginkgo/v2 dependency-version: 2.32.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * docs: document webhook failure when a service mesh sidecar is injected (kubeflow#3100) * docs: document webhook failure when a service mesh sidecar is injected Signed-off-by: Vikas Saxena <Vikas.Saxena.2006@gmail.com> * adding caveat for multiple releases Signed-off-by: Vikas Saxena <Vikas.Saxena.2006@gmail.com> --------- Signed-off-by: Vikas Saxena <Vikas.Saxena.2006@gmail.com> * fix(webhook): generate valid volume names for ConfigMaps (kubeflow#3099) Signed-off-by: immanuwell <pchpr.00@list.ru> * feat(ci): publish the operator binary extracted from the released image (kubeflow#3098) * feat(ci): publish the operator binary extracted from the released image Signed-off-by: Vikas Saxena <Vikas.Saxena.2006@gmail.com> * incoperating review comments by Tariq Signed-off-by: Vikas Saxena <Vikas.Saxena.2006@gmail.com> * incoperating review comments by Tariq - take 2 Signed-off-by: Vikas Saxena <Vikas.Saxena.2006@gmail.com> --------- Signed-off-by: Vikas Saxena <Vikas.Saxena.2006@gmail.com> * fix(sparkconnect): resolve images from selected template containers (kubeflow#3103) Signed-off-by: immanuwell <pchpr.00@list.ru> * docs: add Spark Connect user guide (kubeflow#3091) Signed-off-by: Vidyansh <ezboi2312@gmail.com> * feat(controller): add default service account fallback for SparkApplication driver (kubeflow#3092) * feat(controller): add default service account fallback for SparkApplication driver Adds a --default-service-account controller flag. When set, SparkApplications that do not specify .spec.driver.serviceAccount fall back to this value at submission time. The fallback is applied to a copy of the application so it is never persisted to the custom resource. Empty by default, so behaviour is unchanged on upgrade. Part of kubeflow#3049 Signed-off-by: Vikas Saxena <Vikas.Saxena.2006@gmail.com> * refactor(controller): move driver service account fallback to pkg/util and honour pod template Signed-off-by: Vikas Saxena <Vikas.Saxena.2006@gmail.com> * feat(controller): validate --default-service-account is a valid DNS subdomain Signed-off-by: Vikas Saxena <Vikas.Saxena.2006@gmail.com> * chore(chart): group --default-service-account with other controller defaults Signed-off-by: Vikas Saxena <Vikas.Saxena.2006@gmail.com> * docs: document the default driver service account flag Signed-off-by: Vikas Saxena <Vikas.Saxena.2006@gmail.com> --------- Signed-off-by: Vikas Saxena <Vikas.Saxena.2006@gmail.com> * fix(webhook): generate valid volume name for Prometheus ConfigMap (kubeflow#3111) A SparkApplication name may be up to 63 characters, so appending the Prometheus ConfigMap and volume suffixes overshoots the volume name limit and Kubernetes rejects every driver and executor pod of the application. Signed-off-by: rjgoyln <pt40419@gmail.com> * refactor: centralize Spark container selection (kubeflow#3115) * refactor: centralize Spark container selection Signed-off-by: rohith1X8 <rohith18p18@gmail.com> * chore: address review comments Signed-off-by: rohith1X8 <rohith18p18@gmail.com> --------- Signed-off-by: rohith1X8 <rohith18p18@gmail.com> * feat(sparkconnect): add service account fallback for Spark Connect server pod (kubeflow#3109) * feat(sparkconnect): add service account fallback for Spark Connect server pod Signed-off-by: Vikas Saxena <Vikas.Saxena.2006@gmail.com> * refactor(sparkconnect): drop server serviceAccount CRD field as asked by Tariq and clarify flag scope Signed-off-by: Vikas Saxena <Vikas.Saxena.2006@gmail.com> * refactor(sparkconnect): inline default service account fallback and add log line Signed-off-by: Vikas Saxena <Vikas.Saxena.2006@gmail.com> --------- Signed-off-by: Vikas Saxena <Vikas.Saxena.2006@gmail.com> * chore(ci): migrate vulnerability scanning to OSV-Scanner (kubeflow#3110) * chore(ci): migrate vulnerability scanning to OSV-Scanner Signed-off-by: Vikas Saxena <Vikas.Saxena.2006@gmail.com> * Update .github/workflows/osv-scanner.yaml Co-authored-by: Manabu McCloskey <manabu.mccloskey@gmail.com> Signed-off-by: Vikas Saxena <90456542+vikas-saxena02@users.noreply.github.com> * chore(ci): remove image scanning job as instructed by @nabuskey Signed-off-by: Vikas Saxena <Vikas.Saxena.2006@gmail.com> --------- Signed-off-by: Vikas Saxena <Vikas.Saxena.2006@gmail.com> Signed-off-by: Vikas Saxena <90456542+vikas-saxena02@users.noreply.github.com> Co-authored-by: Manabu McCloskey <manabu.mccloskey@gmail.com> * chore(deps): bump google.golang.org/grpc from 1.82.1 to 1.83.1 in /test/e2e (kubeflow#3136) Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.82.1 to 1.83.1. - [Release notes](https://github.com/grpc/grpc-go/releases) - [Commits](grpc/grpc-go@v1.82.1...v1.83.1) --- updated-dependencies: - dependency-name: google.golang.org/grpc dependency-version: 1.83.1 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore(deps): bump tornado from 6.5.7 to 6.5.8 in /docs/website (kubeflow#3135) Bumps [tornado](https://github.com/tornadoweb/tornado) from 6.5.7 to 6.5.8. - [Changelog](https://github.com/tornadoweb/tornado/blob/master/docs/releases.rst) - [Commits](tornadoweb/tornado@v6.5.7...v6.5.8) --- updated-dependencies: - dependency-name: tornado dependency-version: 6.5.8 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Make webhook leader election timings configurable (kubeflow#3065) * feat(webhook): add leader election parameters for lease duration, renew deadline, and retry period Signed-off-by: mosa0519 <mohanakrishna.sadhu@netcracker.com> * feat(webhook): add leader election parameters for lease duration and renew deadline Signed-off-by: mosa0519 <mohanakrishna.sadhu@netcracker.com> * feat(webhook): update leader election renew deadline and retry period durations Signed-off-by: mosa0519 <mohanakrishna.sadhu@netcracker.com> --------- Signed-off-by: mosa0519 <mohanakrishna.sadhu@netcracker.com> * fix(webhook): validate ConfigMap references in SparkApplication specs (kubeflow#3117) * fix(webhook): validate ConfigMap references in SparkApplication specs An unusable or repeated ConfigMap reference is accepted today and only surfaces in the pod the mutating webhook builds, which the API server then rejects over a name the user never chose while the application itself looks healthy. ScheduledSparkApplication carries the same spec, so it needs the same check. Signed-off-by: rjgoyln <pt40419@gmail.com> * fix(webhook): point ConfigMap validation errors at the name field Each configMaps entry carries both a name and a mount path, so an error that stops at the list index leaves the reader guessing which of the two is wrong. Signed-off-by: rjgoyln <pt40419@gmail.com> --------- Signed-off-by: rjgoyln <pt40419@gmail.com> * docs: replace Enterprise Gateway notebooks guide with Kubeflow SDK (kubeflow#3141) * docs: replace Enterprise Gateway notebooks guide with Kubeflow SDK Signed-off-by: Vikas Saxena <Vikas.Saxena.2006@gmail.com> * docs: correct Kubeflow SDK install to kubeflow[spark] Signed-off-by: Vikas Saxena <Vikas.Saxena.2006@gmail.com> * fixing unpushed commit Signed-off-by: Vikas Saxena <Vikas.Saxena.2006@gmail.com> * chore: untrack Python bytecode and ignore __pycache__ Signed-off-by: Vikas Saxena <Vikas.Saxena.2006@gmail.com> --------- Signed-off-by: Vikas Saxena <Vikas.Saxena.2006@gmail.com> * docs: add SparkConnect API reference to api-docs.md (kubeflow#3126) * docs: generate api reference for SparkConnect (v1alpha1) Add api/doc.go with 'package api' so gen-crd-api-reference-docs can parse the parent api directory. Update Makefile build-api-docs target to point at the parent api directory to capture both v1beta2 and v1alpha1 packages. Fixes kubeflow#3114 Signed-off-by: Fumer057 <fumer057@users.noreply.github.com> * chore: trigger CI to resolve network flake Signed-off-by: Fumer057 <fumer057@users.noreply.github.com> * docs: address reviewer comments for SparkConnect API reference Signed-off-by: Fumer057 <fumer057@users.noreply.github.com> * docs: fix copyright header in api/doc.go Signed-off-by: Fumer057 <fumer057@users.noreply.github.com> --------- Signed-off-by: Fumer057 <fumer057@users.noreply.github.com> Co-authored-by: Fumer057 <fumer057@users.noreply.github.com> * fix(webhook): validate ConfigMap mount-path uniqueness (kubeflow#3140) * fix(webhook): validate ConfigMap mount-path uniqueness Motivation: spec.{driver,executor}.configMaps entries with different names but the same mount path pass admission today, since the ConfigMap validator only rejected duplicate names. The mutating webhook then builds one volumeMount per entry, so two entries sharing a path produce two volumeMounts with an identical mountPath, which the API server rejects at pod creation with a generic error that gives no hint the SparkApplication spec is the cause. Conversely, mounting the same ConfigMap at two different paths was rejected outright by the duplicate-name check, even though that is a legitimate configuration: the mutating webhook just needs to build one pod volume per distinct ConfigMap and one volumeMount per entry, instead of one volume per entry. Approach: - internal/webhook/configmap_validator.go: validateConfigMapList now rejects entries whose mount Path repeats within the same driver or executor configMaps list, instead of rejecting a repeated Name. - internal/webhook/sparkpod_defaulter.go: addGeneralConfigMaps now adds each derived ConfigMap volume at most once, while still emitting a volumeMount for every entry, so the same ConfigMap can be mounted at multiple paths without the pod ending up with two volumes sharing a name. Validation: - go test ./internal/webhook/... (including the ginkgo envtest suite, run with KUBEBUILDER_ASSETS pointed at the make setup-envtest binaries) passes, including new/updated cases: a duplicate mount path is now rejected, the same ConfigMap at two distinct paths is now accepted and produces one volume with two volumeMounts, and a previously-invalid "duplicate ConfigMap name" spec is now valid as long as paths differ. - go test $(go list ./... | grep -v -e /drift -e /test/e2e) passes. - make go-vet, make go-fmt (no diff), and make go-lint (0 issues) all pass clean; go mod tidy produced no changes. - Branch is at upstream/master tip (ff244c1); upstream's own Integration Test workflow is green on recent master runs. Report: kubeflow#3134 Signed-off-by: Pujitha Paladugu <10557236+pujitha24@users.noreply.github.com> Assisted-by: claude-sonnet-5 (via Claude Code) * fix(webhook): key ConfigMap volume dedup by source name, not generated volume name Signed-off-by: Pujitha Paladugu <10557236+pujitha24@users.noreply.github.com> * fix(webhook): reject empty and reserved ConfigMap mount paths validateConfigMapList now rejects an empty configMaps[].path (which otherwise builds an invalid VolumeMount) and a path that collides with one the webhook reserves for the Spark, Hadoop, or Prometheus ConfigMap it mounts itself, mirroring the same gating logic addPrometheusConfig uses to decide whether that mount happens. Signed-off-by: Pujitha Paladugu <10557236+pujitha24@users.noreply.github.com> --------- Signed-off-by: Pujitha Paladugu <10557236+pujitha24@users.noreply.github.com> Co-authored-by: Pujitha Paladugu <10557236+pujitha24@users.noreply.github.com> * docs: add SparkConnect to the website API reference (kubeflow#3138) * docs: add SparkConnect to the website API reference The reference section documented only the two v1beta2 kinds, so SparkConnect (sparkoperator.k8s.io/v1alpha1) was missing from both the landing page card and the API reference page. make build-api-docs generates from api/v1beta2 only, so there is no generated reference to link for SparkConnect. The page points at the Go types and the Spark Connect user guide instead. Signed-off-by: Shivansh Pandey <shivanshp987@gmail.com> * docs: address review on the SparkConnect API reference - Drop the version claim from the generated-reference link and the regeneration note. kubeflow#3126 extends build-api-docs to the parent api directory, so wording that named v1beta2 would be wrong once it lands; this phrasing holds either way. - Remove the per-CRD facts table. It covered SparkConnect only, and hand-copying group, kind, resource and scope for all three would duplicate what docs/api-docs.md generates. - Update the Reference card on the landing page (docs/website/index.rst) to name all three custom resources. Signed-off-by: Shivansh Pandey <shivanshp987@gmail.com> --------- Signed-off-by: Shivansh Pandey <shivanshp987@gmail.com> * fix: stop adding SparkApplication owner reference to executor pods (kubeflow#3152) * Stop adding SparkApplication owner reference to executor pods Since kubeflow#2670 executor pods carried two owners: the driver pod (controller=true, set by Spark) and the SparkApplication (non-controller, added at submission time). Kubernetes garbage collection only deletes a dependent once all owners are gone, so deleting the driver pod (manual delete, spec.suspend=true, Kueue preemption) left executor pods orphaned until the SparkApplication itself was deleted. Drop the extra owner reference so executors are cascade-deleted with the driver pod. Deleting the SparkApplication still cascades through the driver pod to the executors. Issue: kubeflow#2961 Signed-off-by: KR Ravindra <42912207+KR-Ravindra@users.noreply.github.com> * Assert executor pods are deleted when a SparkApplication is suspended Extend the spark-pi suspend/resume e2e test: wait for an executor pod to exist before suspending, then after the application reaches Suspended assert that no driver or executor pods labelled with the application name remain. With the extra SparkApplication owner reference on executors this assertion fails because the executor pods survive the driver pod deletion. Signed-off-by: KR Ravindra <42912207+KR-Ravindra@users.noreply.github.com> --------- Signed-off-by: KR Ravindra <42912207+KR-Ravindra@users.noreply.github.com> --------- Signed-off-by: Jay Bharadwaj <jbharadw@openai.com> Signed-off-by: Tamir Krasna <64045253+Tankdoggo@users.noreply.github.com> Signed-off-by: dependabot[bot] <support@github.com> Signed-off-by: Vikas Saxena <Vikas.Saxena.2006@gmail.com> Signed-off-by: Vikas Saxena <90456542+vikas-saxena02@users.noreply.github.com> Signed-off-by: dineshkumar181094 <dineshkumar181094@gmail.com> Signed-off-by: immanuwell <pchpr.00@list.ru> Signed-off-by: Vidyansh <ezboi2312@gmail.com> Signed-off-by: rjgoyln <pt40419@gmail.com> Signed-off-by: rohith1X8 <rohith18p18@gmail.com> Signed-off-by: mosa0519 <mohanakrishna.sadhu@netcracker.com> Signed-off-by: Fumer057 <fumer057@users.noreply.github.com> Signed-off-by: Pujitha Paladugu <10557236+pujitha24@users.noreply.github.com> Signed-off-by: Shivansh Pandey <shivanshp987@gmail.com> Signed-off-by: KR Ravindra <42912207+KR-Ravindra@users.noreply.github.com> Co-authored-by: Jay Bharadwaj <jayanth86@users.noreply.github.com> Co-authored-by: Tamir Krasna <64045253+Tankdoggo@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Vikas Saxena <90456542+vikas-saxena02@users.noreply.github.com> Co-authored-by: Tariq Hasan <mmtariquehsn@gmail.com> Co-authored-by: Dinesh Kumar <36758667+dineshkumar181094@users.noreply.github.com> Co-authored-by: Immanuel Tikhonov <122638311+immanuwell@users.noreply.github.com> Co-authored-by: Vidyansh Singh <141176362+reckless-sherixx@users.noreply.github.com> Co-authored-by: rjgoyln <151457491+rjgoyln@users.noreply.github.com> Co-authored-by: Rohith Peddi <rohith18p18@gmail.com> Co-authored-by: Manabu McCloskey <manabu.mccloskey@gmail.com> Co-authored-by: mohanakrishna sadhu <43145647+AxcelBlaze003@users.noreply.github.com> Co-authored-by: Rishabh Shukla <rishabhshukla2901@gmail.com> Co-authored-by: Fumer057 <fumer057@users.noreply.github.com> Co-authored-by: Pujitha Paladugu <pujitha.rathna@gmail.com> Co-authored-by: Pujitha Paladugu <10557236+pujitha24@users.noreply.github.com> Co-authored-by: shivansh <shivanshp987@gmail.com> Co-authored-by: KR Ravindra <rajaravindra919@gmail.com>
Purpose of this PR
Proposed changes:
TestExecutorPodTemplateContentsandTestSubmitPodTemplatesso executor templates carry only user-supplied owner references; driver templates keep the controller reference to the SparkApplication (TestDriverPodTemplateContentsis unchanged).Problem
Since #2670 every executor pod has two owners: the driver pod (
controller: true, set by Spark itself) and the SparkApplication (controllerunset, added by the operator). Kubernetes garbage collection only deletes a dependent once all of its owners are gone, so deleting the driver pod (manually, or viaspec.suspend=true, e.g. when Kueue preempts the workload) leaves the executor pods behind until the SparkApplication itself is deleted. Across Kueue requeue cycles this accumulates orphaned executor pods.Root cause
internal/controller/sparkapplication/submission.go:1199-1209(buildExecutorPodTemplate) appendsutil.GetOwnerReference(app)withController/BlockOwnerDeletioncleared to the executor pod template. That extra owner is what blocks the cascade deletion from the driver pod. The webhook path (internal/webhook/sparkpod_defaulter.goaddOwnerReference) already returns early for non-driver pods, so submission is the only place that adds it.Fix
Remove the executor ownerReference block in
buildExecutorPodTemplate. Executor pods keep their controller reference to the driver pod, and the driver pod keeps its controller reference to the SparkApplication, so deleting the SparkApplication still cascades to the driver and then to the executors, while deleting only the driver now cascades to the executors as well. This follows the approach suggested in the issue discussion (drop the executor's SparkApplication reference and rely on GC cascade deletion instead of adding operator-managed deletion of executor pods).The original motivation for the extra reference was to let other controllers (e.g. Kueue) recognize executor pods as children of the SparkApplication. Kueue's ownership walk (
FindAncestorJobManagedByKueue) and itsIsOwnerManagedByKueueForObjectcheck both usemetav1.GetControllerOf, i.e. only controller references, and its SparkApplication integration identifies executor pods by thespark-rolelabel and reads readiness fromstatus.executorState, so the non-controller reference is not consumed there.How tested
Unit tests (no cluster required) plus an e2e assertion in the existing suspend/resume test.
Before the fix, with the updated expectations, three subtests fail. Two are shown below; the third,
TestSubmitPodTemplates/sends_default_templates_with_owner_ref_when_not_specified(internal/controller/sparkapplication/rest_submission_test.go:203), fails the same way because the submitted executor template still carries the SparkApplication owner reference (Emptyassertion onOwnerReferences) and is only absent from the output because of the-runfilter. The "pod template already has owner references" case is unchanged and passes both before and after, because user-supplied owner references are preserved as-is.After the fix:
gofmt -l,go vet,go build ./...andgolangci-lint run ./internal/controller/sparkapplication/...are clean.e2e (added on request of the reviewers): the
spark-pi: Suspend and Resumecase intest/e2e/sparkapplication_test.gonow waits for an executor pod to exist before suspending and, once the application reachesSuspended, asserts that no pod labelledsparkoperator.k8s.io/app-name=spark-piremains (driver or executor). Without this fix the executor pod survives the driver deletion because the SparkApplication is still an owner, so the assertion fails; with the fix the executors are cascade-deleted with the driver.gofmt -landgo vet ./...intest/e2eare clean; the CI e2e matrix runs it.Links
Change Category
Rationale
Covered above. Executor pods created by an operator built before this change keep their existing owner references; only newly submitted applications are affected.
Checklist
Additional Notes
This change was prepared with an AI agent operated by KR-Ravindra, who reviewed and tested it.