├── VERSION
├── charts
└── spark-operator-chart
│ ├── ci
│ ├── ci-values.yaml
│ └── kind-config.yaml
│ ├── .helmignore
│ ├── templates
│ ├── prometheus
│ │ ├── _helpers.tpl
│ │ └── podmonitor.yaml
│ ├── certmanager
│ │ ├── _helpers.tpl
│ │ ├── issuer.yaml
│ │ └── certificate.yaml
│ ├── hook
│ │ ├── serviceaccount.yaml
│ │ ├── cluster_role_binding.yaml
│ │ ├── cluster_role.yaml
│ │ ├── job.yaml
│ │ └── _helpers.tpl
│ ├── webhook
│ │ ├── service.yaml
│ │ ├── serviceaccount.yaml
│ │ └── poddisruptionbudget.yaml
│ ├── controller
│ │ ├── service.yaml
│ │ ├── serviceaccount.yaml
│ │ └── poddisruptionbudget.yaml
│ └── spark
│ │ ├── serviceaccount.yaml
│ │ ├── _helpers.tpl
│ │ └── rbac.yaml
│ ├── Chart.yaml
│ └── tests
│ ├── hook
│ ├── serviceaccount_test.yaml
│ ├── cluster_role_test.yaml
│ ├── cluster_role_binding_test.yaml
│ └── job_test.yaml
│ ├── controller
│ ├── service_test.yaml
│ ├── serviceaccount_test.yaml
│ └── poddisruptionbudget_test.yaml
│ └── webhook
│ └── service_test.yaml
├── .dockerignore
├── .gitignore
├── config
├── certmanager
│ ├── kustomization.yaml
│ ├── kustomizeconfig.yaml
│ └── certificate.yaml
├── webhook
│ ├── kustomization.yaml
│ ├── service.yaml
│ └── kustomizeconfig.yaml
├── samples
│ ├── kustomization.yaml
│ ├── v1beta2_sparkapplication.yaml
│ └── v1beta2_scheduledsparkapplication.yaml
├── crd
│ ├── patches
│ │ ├── cainjection_in_sparkapplications.yaml
│ │ └── webhook_in_sparkapplications.yaml
│ ├── kustomizeconfig.yaml
│ └── kustomization.yaml
├── rbac
│ ├── sparkapplication_viewer_role.yaml
│ ├── scheduledsparkapplication_viewer_role.yaml
│ ├── sparkapplication_editor_role.yaml
│ ├── scheduledsparkapplication_editor_role.yaml
│ ├── spark-application-rbac.yaml
│ └── role.yaml
└── default
│ ├── manager_webhook_patch.yaml
│ └── webhookcainjection_patch.yaml
├── hack
├── api-docs
│ ├── template
│ │ ├── placeholder.go
│ │ ├── pkg.tpl
│ │ ├── members.tpl
│ │ └── type.tpl
│ └── config.json
├── README.md
├── boilerplate.go.txt
├── install_packages.sh
├── verify-codegen.sh
└── update-codegen.sh
├── OWNERS
├── CODE_OF_CONDUCT.md
├── proposals
└── README.md
├── .pre-commit-config.yaml
├── .github
├── dependabot.yml
├── ISSUE_TEMPLATE
│ ├── config.yaml
│ ├── question.yaml
│ ├── bug_report.yaml
│ └── feature_request.yaml
├── workflows
│ ├── trivy-image-scanning.yaml
│ ├── stale.yaml
│ └── check-release.yaml
└── PULL_REQUEST_TEMPLATE.md
├── api
├── v1beta2
│ ├── pod_webhook.go
│ ├── types.go
│ ├── doc.go
│ ├── register.go
│ └── groupversion_info.go
└── v1alpha1
│ ├── defaults.go
│ ├── doc.go
│ ├── register.go
│ └── groupversion_info.go
├── pkg
├── certificate
│ ├── doc.go
│ └── util_test.go
├── util
│ ├── doc.go
│ ├── workqueue.go
│ ├── metrics.go
│ ├── suite_test.go
│ ├── resourcequota.go
│ └── sparkpod.go
├── common
│ ├── kueue.go
│ ├── volcano.go
│ ├── doc.go
│ ├── constants.go
│ ├── metrics.go
│ └── event.go
├── client
│ ├── clientset
│ │ └── versioned
│ │ │ ├── fake
│ │ │ ├── doc.go
│ │ │ └── register.go
│ │ │ ├── typed
│ │ │ └── api
│ │ │ │ └── v1beta2
│ │ │ │ ├── fake
│ │ │ │ ├── doc.go
│ │ │ │ ├── fake_api_client.go
│ │ │ │ ├── fake_sparkapplication.go
│ │ │ │ └── fake_scheduledsparkapplication.go
│ │ │ │ ├── doc.go
│ │ │ │ └── generated_expansion.go
│ │ │ └── scheme
│ │ │ ├── doc.go
│ │ │ └── register.go
│ ├── listers
│ │ └── api
│ │ │ └── v1beta2
│ │ │ └── expansion_generated.go
│ └── informers
│ │ └── externalversions
│ │ ├── internalinterfaces
│ │ └── factory_interfaces.go
│ │ └── api
│ │ ├── interface.go
│ │ └── v1beta2
│ │ └── interface.go
└── scheme
│ └── scheme.go
├── internal
├── metrics
│ └── metrcis.go
├── scheduler
│ ├── volcano
│ │ └── util.go
│ ├── kubescheduler
│ │ └── util.go
│ ├── yunikorn
│ │ └── resourceusage
│ │ │ ├── memory_test.go
│ │ │ ├── resource_usage_test.go
│ │ │ ├── java.go
│ │ │ ├── java_test.go
│ │ │ └── resource_usage.go
│ ├── scheduler.go
│ └── registry.go
├── webhook
│ ├── doc.go
│ ├── webhook.go
│ ├── resourcequota_test.go
│ └── scheduledsparkapplication_defaulter.go
└── controller
│ ├── sparkapplication
│ └── validator.go
│ ├── mutatingwebhookconfiguration
│ └── event_filter.go
│ ├── validatingwebhookconfiguration
│ └── event_filter.go
│ └── doc.go
├── CONTRIBUTING.md
├── spark-docker
├── conf
│ └── metrics.properties
├── README.md
└── Dockerfile
├── cmd
└── operator
│ ├── webhook
│ └── root.go
│ ├── controller
│ └── root.go
│ ├── version
│ └── root.go
│ └── main.go
├── ROADMAP.md
├── entrypoint.sh
├── PROJECT
├── docker
└── Dockerfile.kubectl
├── test
└── e2e
│ └── bad_examples
│ ├── fail-application.yaml
│ └── fail-submission.yaml
├── examples
├── spark-pi-python.yaml
├── spark-pi-ttl.yaml
├── spark-pi-volcano.yaml
├── spark-pi-kube-scheduler.yaml
├── spark-pi-yunikorn.yaml
├── spark-pi.yaml
├── spark-pi-custom-resource.yaml
├── spark-pi-dynamic-allocation.yaml
├── spark-pi-scheduled.yaml
├── spark-pi-configmap.yaml
├── spark-pi-prometheus.yaml
└── sparkconnect
│ └── spark-connect.yaml
├── Dockerfile
└── .golangci.yaml
/VERSION:
--------------------------------------------------------------------------------
1 | v2.3.0
2 |
--------------------------------------------------------------------------------
/charts/spark-operator-chart/ci/ci-values.yaml:
--------------------------------------------------------------------------------
1 | image:
2 | tag: local
3 |
--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | .vscode/
3 | bin/
4 | codecov.yaml
5 | cover.out
6 | .DS_Store
7 | *.iml
8 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | .vscode/
3 | bin/
4 | codecov.yaml
5 | cover.out
6 | cover.html
7 | .DS_Store
8 | *.iml
9 |
--------------------------------------------------------------------------------
/config/certmanager/kustomization.yaml:
--------------------------------------------------------------------------------
1 | resources:
2 | - certificate.yaml
3 |
4 | configurations:
5 | - kustomizeconfig.yaml
6 |
--------------------------------------------------------------------------------
/hack/api-docs/template/placeholder.go:
--------------------------------------------------------------------------------
1 | // Placeholder file to make Go vendor this directory properly.
2 | package template
3 |
--------------------------------------------------------------------------------
/config/webhook/kustomization.yaml:
--------------------------------------------------------------------------------
1 | resources:
2 | - manifests.yaml
3 | - service.yaml
4 |
5 | configurations:
6 | - kustomizeconfig.yaml
7 |
--------------------------------------------------------------------------------
/charts/spark-operator-chart/ci/kind-config.yaml:
--------------------------------------------------------------------------------
1 | kind: Cluster
2 | apiVersion: kind.x-k8s.io/v1alpha4
3 | nodes:
4 | - role: control-plane
5 | - role: worker
6 |
--------------------------------------------------------------------------------
/OWNERS:
--------------------------------------------------------------------------------
1 | approvers:
2 | - andreyvelich
3 | - ChenYi015
4 | - jacobsalway
5 | - mwielgus
6 | - vara-bonthu
7 | - yuchaoran2011
8 | reviewers:
9 | - ImpSy
10 | - nabuskey
11 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Code of Conduct
2 |
3 | For the code of conduct, please refer to the [Kubeflow Community Code of Conduct](https://www.kubeflow.org/docs/about/contributing/#follow-the-code-of-conduct).
4 |
--------------------------------------------------------------------------------
/config/samples/kustomization.yaml:
--------------------------------------------------------------------------------
1 | ## Append samples of your project ##
2 | resources:
3 | - v1beta2_sparkapplication.yaml
4 | - v1beta2_scheduledsparkapplication.yaml
5 | # +kubebuilder:scaffold:manifestskustomizesamples
6 |
--------------------------------------------------------------------------------
/config/certmanager/kustomizeconfig.yaml:
--------------------------------------------------------------------------------
1 | # This configuration is for teaching kustomize how to update name ref substitution
2 | nameReference:
3 | - kind: Issuer
4 | group: cert-manager.io
5 | fieldSpecs:
6 | - kind: Certificate
7 | group: cert-manager.io
8 | path: spec/issuerRef/name
9 |
--------------------------------------------------------------------------------
/proposals/README.md:
--------------------------------------------------------------------------------
1 | # Proposals
2 |
3 | Kubeflow uses the KEP process to document large scale changes to the project.
4 |
5 | Details on the process (including the KEP template, recommendations, etc.) can be found at
6 | [kubeflow/community/proposals](https://github.com/kubeflow/community/blob/master/proposals/README.md)
7 |
--------------------------------------------------------------------------------
/config/crd/patches/cainjection_in_sparkapplications.yaml:
--------------------------------------------------------------------------------
1 | # The following patch adds a directive for certmanager to inject CA into the CRD
2 | apiVersion: apiextensions.k8s.io/v1
3 | kind: CustomResourceDefinition
4 | metadata:
5 | annotations:
6 | cert-manager.io/inject-ca-from: CERTIFICATE_NAMESPACE/CERTIFICATE_NAME
7 | name: sparkapplications.sparkoperator.k8s.io
8 |
--------------------------------------------------------------------------------
/.pre-commit-config.yaml:
--------------------------------------------------------------------------------
1 | repos:
2 | - repo: https://github.com/norwoodj/helm-docs
3 | rev: "v1.13.1"
4 | hooks:
5 | - id: helm-docs
6 | args:
7 | # Make the tool search for charts only under the `charts` directory
8 | - --chart-search-root=charts
9 | - --template-files=README.md.gotmpl
10 | - --sort-values-order=file
11 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: "gomod"
4 | directory: "/"
5 | schedule:
6 | interval: "weekly"
7 |
8 | - package-ecosystem: "docker"
9 | directory: "/"
10 | schedule:
11 | interval: "weekly"
12 |
13 | - package-ecosystem: "github-actions"
14 | directory: "/"
15 | schedule:
16 | interval: "weekly"
17 |
--------------------------------------------------------------------------------
/config/webhook/service.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Service
3 | metadata:
4 | labels:
5 | app.kubernetes.io/name: spark-operator
6 | app.kubernetes.io/managed-by: kustomize
7 | name: webhook-service
8 | namespace: system
9 | spec:
10 | ports:
11 | - port: 443
12 | protocol: TCP
13 | targetPort: 9443
14 | selector:
15 | control-plane: controller-manager
16 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yaml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: true
2 |
3 | contact_links:
4 | - name: Spark Operator Documentation
5 | url: https://www.kubeflow.org/docs/components/spark-operator
6 | about: Much help can be found in the docs
7 | - name: Spark Operator Slack Channel
8 | url: https://app.slack.com/client/T08PSQ7BQ/C074588U7EG
9 | about: Ask questions about the Spark Operator
10 |
--------------------------------------------------------------------------------
/hack/README.md:
--------------------------------------------------------------------------------
1 | ## Updating [client-go](../client-go) directory
2 | [client-go](../client-go) directory contains clientset, informers, and listers generated by [kubernetes/code-generator](https://github.com/kubernetes/code-generator).
3 |
4 | ### Update files in [client-go](../client-go) directory
5 | ```bash
6 | ./hack/update-codegen.sh
7 | ```
8 |
9 | ### Verify changes to files in [client-go](../client-go) directory
10 | ```bash
11 | ./hack/verify-codegen.sh
12 | ```
13 |
--------------------------------------------------------------------------------
/config/crd/patches/webhook_in_sparkapplications.yaml:
--------------------------------------------------------------------------------
1 | # The following patch enables a conversion webhook for the CRD
2 | apiVersion: apiextensions.k8s.io/v1
3 | kind: CustomResourceDefinition
4 | metadata:
5 | name: sparkapplications.sparkoperator.k8s.io
6 | spec:
7 | conversion:
8 | strategy: Webhook
9 | webhook:
10 | clientConfig:
11 | service:
12 | namespace: system
13 | name: webhook-service
14 | path: /convert
15 | conversionReviewVersions:
16 | - v1
17 |
--------------------------------------------------------------------------------
/config/crd/kustomizeconfig.yaml:
--------------------------------------------------------------------------------
1 | # This file is for teaching kustomize how to substitute name and namespace reference in CRD
2 | nameReference:
3 | - kind: Service
4 | version: v1
5 | fieldSpecs:
6 | - kind: CustomResourceDefinition
7 | version: v1
8 | group: apiextensions.k8s.io
9 | path: spec/conversion/webhook/clientConfig/service/name
10 |
11 | namespace:
12 | - kind: CustomResourceDefinition
13 | version: v1
14 | group: apiextensions.k8s.io
15 | path: spec/conversion/webhook/clientConfig/service/namespace
16 | create: false
17 |
18 | varReference:
19 | - path: metadata/annotations
20 |
--------------------------------------------------------------------------------
/config/rbac/sparkapplication_viewer_role.yaml:
--------------------------------------------------------------------------------
1 | # permissions for end users to view sparkapplications.
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRole
4 | metadata:
5 | labels:
6 | app.kubernetes.io/name: spark-operator
7 | app.kubernetes.io/managed-by: kustomize
8 | name: sparkapplication-viewer-role
9 | rules:
10 | - apiGroups:
11 | - sparkoperator.k8s.io
12 | resources:
13 | - sparkapplications
14 | verbs:
15 | - get
16 | - list
17 | - watch
18 | - apiGroups:
19 | - sparkoperator.k8s.io
20 | resources:
21 | - sparkapplications/status
22 | verbs:
23 | - get
24 |
--------------------------------------------------------------------------------
/hack/boilerplate.go.txt:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2025 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
--------------------------------------------------------------------------------
/config/default/manager_webhook_patch.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: controller-manager
5 | namespace: system
6 | spec:
7 | template:
8 | spec:
9 | containers:
10 | - name: manager
11 | ports:
12 | - containerPort: 9443
13 | name: webhook-server
14 | protocol: TCP
15 | volumeMounts:
16 | - mountPath: /tmp/k8s-webhook-server/serving-certs
17 | name: cert
18 | readOnly: true
19 | volumes:
20 | - name: cert
21 | secret:
22 | defaultMode: 420
23 | secretName: webhook-server-cert
24 |
--------------------------------------------------------------------------------
/config/rbac/scheduledsparkapplication_viewer_role.yaml:
--------------------------------------------------------------------------------
1 | # permissions for end users to view scheduledsparkapplications.
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRole
4 | metadata:
5 | labels:
6 | app.kubernetes.io/name: spark-operator
7 | app.kubernetes.io/managed-by: kustomize
8 | name: scheduledsparkapplication-viewer-role
9 | rules:
10 | - apiGroups:
11 | - sparkoperator.k8s.io
12 | resources:
13 | - scheduledsparkapplications
14 | verbs:
15 | - get
16 | - list
17 | - watch
18 | - apiGroups:
19 | - sparkoperator.k8s.io
20 | resources:
21 | - scheduledsparkapplications/status
22 | verbs:
23 | - get
24 |
--------------------------------------------------------------------------------
/charts/spark-operator-chart/.helmignore:
--------------------------------------------------------------------------------
1 | # Patterns to ignore when building packages.
2 | # This supports shell glob matching, relative path matching, and
3 | # negation (prefixed with !). Only one pattern per line.
4 |
5 | ci/
6 | .helmignore
7 |
8 | # Common VCS dirs
9 | .git/
10 | .gitignore
11 | .bzr/
12 | .bzrignore
13 | .hg/
14 | .hgignore
15 | .svn/
16 |
17 | # Common backup files
18 | *.swp
19 | *.bak
20 | *.tmp
21 | *.orig
22 | *~
23 |
24 | # Various IDEs
25 | *.tmproj
26 | .project
27 | .idea/
28 | .vscode/
29 |
30 | # MacOS
31 | .DS_Store
32 |
33 | # helm-unittest
34 | tests
35 | .debug
36 | __snapshot__
37 |
38 | # helm-docs
39 | README.md.gotmpl
40 |
--------------------------------------------------------------------------------
/api/v1beta2/pod_webhook.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2024 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package v1beta2
18 |
--------------------------------------------------------------------------------
/config/rbac/sparkapplication_editor_role.yaml:
--------------------------------------------------------------------------------
1 | # permissions for end users to edit sparkapplications.
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRole
4 | metadata:
5 | labels:
6 | app.kubernetes.io/name: spark-operator
7 | app.kubernetes.io/managed-by: kustomize
8 | name: sparkapplication-editor-role
9 | rules:
10 | - apiGroups:
11 | - sparkoperator.k8s.io
12 | resources:
13 | - sparkapplications
14 | verbs:
15 | - create
16 | - delete
17 | - get
18 | - list
19 | - patch
20 | - update
21 | - watch
22 | - apiGroups:
23 | - sparkoperator.k8s.io
24 | resources:
25 | - sparkapplications/status
26 | verbs:
27 | - get
28 |
--------------------------------------------------------------------------------
/pkg/certificate/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2024 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package certificate
18 |
--------------------------------------------------------------------------------
/config/rbac/scheduledsparkapplication_editor_role.yaml:
--------------------------------------------------------------------------------
1 | # permissions for end users to edit scheduledsparkapplications.
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRole
4 | metadata:
5 | labels:
6 | app.kubernetes.io/name: spark-operator
7 | app.kubernetes.io/managed-by: kustomize
8 | name: scheduledsparkapplication-editor-role
9 | rules:
10 | - apiGroups:
11 | - sparkoperator.k8s.io
12 | resources:
13 | - scheduledsparkapplications
14 | verbs:
15 | - create
16 | - delete
17 | - get
18 | - list
19 | - patch
20 | - update
21 | - watch
22 | - apiGroups:
23 | - sparkoperator.k8s.io
24 | resources:
25 | - scheduledsparkapplications/status
26 | verbs:
27 | - get
28 |
--------------------------------------------------------------------------------
/pkg/util/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2017 Google LLC
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package util
18 |
19 | // Package util contains utility code shared by other packages.
20 |
--------------------------------------------------------------------------------
/config/samples/v1beta2_sparkapplication.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: sparkoperator.k8s.io/v1beta2
2 | kind: SparkApplication
3 | metadata:
4 | labels:
5 | app.kubernetes.io/name: spark-operator
6 | app.kubernetes.io/managed-by: kustomize
7 | name: sparkapplication-sample
8 | spec:
9 | type: Scala
10 | mode: cluster
11 | image: docker.io/library/spark:4.0.0
12 | imagePullPolicy: IfNotPresent
13 | mainClass: org.apache.spark.examples.SparkPi
14 | mainApplicationFile: local:///opt/spark/examples/jars/spark-examples.jar
15 | sparkVersion: 4.0.0
16 | driver:
17 | labels:
18 | version: 4.0.0
19 | serviceAccount: spark-operator-spark
20 | executor:
21 | labels:
22 | version: 4.0.0
23 | instances: 1
24 |
--------------------------------------------------------------------------------
/pkg/common/kueue.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2024 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package common
18 |
19 | const (
20 | KueueLabelPrefix = "kueue.x-k8s.io/"
21 | )
22 |
--------------------------------------------------------------------------------
/internal/metrics/metrcis.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2024 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package metrics
18 |
19 | import "sigs.k8s.io/controller-runtime/pkg/log"
20 |
21 | var (
22 | logger = log.Log.WithName("")
23 | )
24 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to Kubeflow Spark Operator
2 |
3 | Welcome to the Kubeflow Spark Operator project. We'd love to accept your patches and contributions to this project. For detailed information about how to contribute to Kubeflow, please refer to [Contributing to Kubeflow](https://www.kubeflow.org/docs/about/contributing/).
4 |
5 | ## Developer Guide
6 |
7 | For how to develope with spark operator, please refer to [Developer Guide](https://www.kubeflow.org/docs/components/spark-operator/developer-guide/).
8 |
9 | ## Code Reviews
10 |
11 | All submissions, including submissions by project members, require review. We use GitHub pull requests for this purpose. Consult [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more information on using pull requests.
12 |
--------------------------------------------------------------------------------
/pkg/common/volcano.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2024 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package common
18 |
19 | const (
20 | VolcanoSchedulerName = "volcano"
21 |
22 | VolcanoPodGroupName = "podgroups.scheduling.volcano.sh"
23 | )
24 |
--------------------------------------------------------------------------------
/pkg/client/clientset/versioned/fake/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2025 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 | // Code generated by client-gen. DO NOT EDIT.
17 |
18 | // This package has the automatically generated fake clientset.
19 | package fake
20 |
--------------------------------------------------------------------------------
/pkg/client/clientset/versioned/typed/api/v1beta2/fake/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2025 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 | // Code generated by client-gen. DO NOT EDIT.
17 |
18 | // Package fake has the automatically generated clients.
19 | package fake
20 |
--------------------------------------------------------------------------------
/pkg/util/workqueue.go:
--------------------------------------------------------------------------------
1 | package util
2 |
3 | import (
4 | "time"
5 |
6 | "golang.org/x/time/rate"
7 | "k8s.io/client-go/util/workqueue"
8 | )
9 |
10 | // This allow to create a new rate limiter while tuning the BucketRateLimiter parameters
11 | // This also prevent a "bug" in the BucketRateLimiter due to the fact that a BucketRateLimiter does not have a maxDelay parameter
12 | func NewRateLimiter[T comparable](qps int, bucketSize int, maxDelay time.Duration) workqueue.TypedRateLimiter[T] {
13 | return workqueue.NewTypedWithMaxWaitRateLimiter(
14 | workqueue.NewTypedMaxOfRateLimiter(
15 | workqueue.NewTypedItemExponentialFailureRateLimiter[T](5*time.Millisecond, 1000*time.Second),
16 | &workqueue.TypedBucketRateLimiter[T]{Limiter: rate.NewLimiter(rate.Limit(qps), bucketSize)},
17 | ), maxDelay)
18 | }
19 |
--------------------------------------------------------------------------------
/api/v1beta2/types.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2025 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | /*
18 | This file is needed for kubernetes/code-generator/kube_codegen.sh script used in hack/update-codegen.sh.
19 | */
20 |
21 | package v1beta2
22 |
23 | //+genclient
24 |
--------------------------------------------------------------------------------
/pkg/client/clientset/versioned/typed/api/v1beta2/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2025 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 | // Code generated by client-gen. DO NOT EDIT.
17 |
18 | // This package has the automatically generated typed clients.
19 | package v1beta2
20 |
--------------------------------------------------------------------------------
/pkg/client/clientset/versioned/scheme/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2025 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 | // Code generated by client-gen. DO NOT EDIT.
17 |
18 | // This package contains the scheme of the automatically generated clientset.
19 | package scheme
20 |
--------------------------------------------------------------------------------
/api/v1alpha1/defaults.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2025 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package v1alpha1
18 |
19 | // SetSparkConnectDefaults sets default values for certain fields of a SparkConnect.
20 | func SetSparkConnectDefaults(conn *SparkConnect) {
21 | }
22 |
--------------------------------------------------------------------------------
/api/v1beta2/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2017 Google LLC
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | // +k8s:deepcopy-gen=package,register
18 |
19 | // Package v1beta2 is the v1beta2 version of the API.
20 | // +groupName=sparkoperator.k8s.io
21 | // +versionName=v1beta2
22 | package v1beta2
23 |
--------------------------------------------------------------------------------
/pkg/common/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2017 Google LLC
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package common
18 |
19 | // Package common contains code that deals with configuration of Spark driver and executor pods, e.g., mounting
20 | // user-specified ConfigMaps, volumes, secrets, etc.
21 |
--------------------------------------------------------------------------------
/api/v1alpha1/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2025 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | // +k8s:deepcopy-gen=package,register
18 |
19 | // Package v1alpha1 is the v1alpha1 version of the API.
20 | // +groupName=sparkoperator.k8s.io
21 | // +versionName=v1alpha1
22 | package v1alpha1
23 |
--------------------------------------------------------------------------------
/config/webhook/kustomizeconfig.yaml:
--------------------------------------------------------------------------------
1 | # the following config is for teaching kustomize where to look at when substituting nameReference.
2 | # It requires kustomize v2.1.0 or newer to work properly.
3 | nameReference:
4 | - kind: Service
5 | version: v1
6 | fieldSpecs:
7 | - kind: MutatingWebhookConfiguration
8 | group: admissionregistration.k8s.io
9 | path: webhooks/clientConfig/service/name
10 | - kind: ValidatingWebhookConfiguration
11 | group: admissionregistration.k8s.io
12 | path: webhooks/clientConfig/service/name
13 |
14 | namespace:
15 | - kind: MutatingWebhookConfiguration
16 | group: admissionregistration.k8s.io
17 | path: webhooks/clientConfig/service/namespace
18 | create: true
19 | - kind: ValidatingWebhookConfiguration
20 | group: admissionregistration.k8s.io
21 | path: webhooks/clientConfig/service/namespace
22 | create: true
23 |
--------------------------------------------------------------------------------
/spark-docker/conf/metrics.properties:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright 2018 Google LLC
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # https://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 | #
16 |
17 | *.sink.jmx.class=org.apache.spark.metrics.sink.JmxSink
18 | driver.source.jvm.class=org.apache.spark.metrics.source.JvmSource
19 | executor.source.jvm.class=org.apache.spark.metrics.source.JvmSource
20 |
--------------------------------------------------------------------------------
/charts/spark-operator-chart/templates/prometheus/_helpers.tpl:
--------------------------------------------------------------------------------
1 | {{/*
2 | Copyright 2024 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */}}
16 |
17 | {{/*
18 | Create the name of pod monitor
19 | */}}
20 | {{- define "spark-operator.prometheus.podMonitorName" -}}
21 | {{- include "spark-operator.fullname" . }}-podmonitor
22 | {{- end -}}
23 |
--------------------------------------------------------------------------------
/pkg/client/clientset/versioned/typed/api/v1beta2/generated_expansion.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2025 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 | // Code generated by client-gen. DO NOT EDIT.
17 |
18 | package v1beta2
19 |
20 | type ScheduledSparkApplicationExpansion interface{}
21 |
22 | type SparkApplicationExpansion interface{}
23 |
--------------------------------------------------------------------------------
/pkg/util/metrics.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2018 Google LLC
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package util
18 |
19 | import (
20 | "strings"
21 | )
22 |
23 | func CreateValidMetricNameLabel(prefix, name string) string {
24 | // "-" is not a valid character for prometheus metric names or labels.
25 | return strings.ReplaceAll(prefix+name, "-", "_")
26 | }
27 |
--------------------------------------------------------------------------------
/internal/scheduler/volcano/util.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2024 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package volcano
18 |
19 | import (
20 | "fmt"
21 |
22 | "github.com/kubeflow/spark-operator/v2/api/v1beta2"
23 | )
24 |
25 | func getPodGroupName(app *v1beta2.SparkApplication) string {
26 | return fmt.Sprintf("spark-%s-pg", app.Name)
27 | }
28 |
--------------------------------------------------------------------------------
/internal/scheduler/kubescheduler/util.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2024 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package kubescheduler
18 |
19 | import (
20 | "fmt"
21 |
22 | "github.com/kubeflow/spark-operator/v2/api/v1beta2"
23 | )
24 |
25 | func getPodGroupName(app *v1beta2.SparkApplication) string {
26 | return fmt.Sprintf("%s-pg", app.Name)
27 | }
28 |
--------------------------------------------------------------------------------
/internal/webhook/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2018 Google LLC
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package webhook
18 |
19 | // Package webhook implements a mutating admission webhook for patching Spark driver and executor pods.
20 | // The webhook supports mutations that are not supported by Spark on Kubernetes itself, e.g., adding an
21 | // OwnerReference to the driver pod for the owning SparkApplications or setting the SecurityContext.
22 |
--------------------------------------------------------------------------------
/cmd/operator/webhook/root.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2024 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package webhook
18 |
19 | import (
20 | "github.com/spf13/cobra"
21 | )
22 |
23 | func NewCommand() *cobra.Command {
24 | command := &cobra.Command{
25 | Use: "webhook",
26 | Short: "Spark operator webhook",
27 | RunE: func(cmd *cobra.Command, _ []string) error {
28 | return cmd.Help()
29 | },
30 | }
31 | command.AddCommand(NewStartCommand())
32 | return command
33 | }
34 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/question.yaml:
--------------------------------------------------------------------------------
1 | name: Question
2 | description: Ask question about the Spark operator.
3 | labels:
4 | - kind/question
5 | - lifecycle/needs-triage
6 | body:
7 | - type: markdown
8 | attributes:
9 | value: |
10 | Thanks for taking the time to fill out this question!
11 | - type: textarea
12 | id: feature
13 | attributes:
14 | label: What question do you want to ask?
15 | description: |
16 | A clear and concise description of what you want to ask about the Spark operator.
17 | value: |
18 | - [ ] ✋ I have searched the open/closed issues and my issue is not listed.
19 | validations:
20 | required: true
21 | - type: textarea
22 | id: rationale
23 | attributes:
24 | label: Additional context
25 | description: Add any other context or screenshots about the question here.
26 | - type: input
27 | id: votes
28 | attributes:
29 | label: Have the same question?
30 | value: Give it a 👍 We prioritize the question with most 👍
31 |
--------------------------------------------------------------------------------
/cmd/operator/controller/root.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2024 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package controller
18 |
19 | import (
20 | "github.com/spf13/cobra"
21 | )
22 |
23 | func NewCommand() *cobra.Command {
24 | command := &cobra.Command{
25 | Use: "controller",
26 | Short: "Spark operator controller",
27 | RunE: func(cmd *cobra.Command, _ []string) error {
28 | return cmd.Help()
29 | },
30 | }
31 | command.AddCommand(NewStartCommand())
32 | return command
33 | }
34 |
--------------------------------------------------------------------------------
/config/samples/v1beta2_scheduledsparkapplication.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: sparkoperator.k8s.io/v1beta2
2 | kind: ScheduledSparkApplication
3 | metadata:
4 | labels:
5 | app.kubernetes.io/name: spark-operator
6 | app.kubernetes.io/managed-by: kustomize
7 | name: scheduledsparkapplication-sample
8 | spec:
9 | schedule: "@every 3m"
10 | concurrencyPolicy: Allow
11 | template:
12 | type: Scala
13 | mode: cluster
14 | image: docker.io/library/spark:4.0.0
15 | imagePullPolicy: IfNotPresent
16 | mainClass: org.apache.spark.examples.SparkPi
17 | mainApplicationFile: local:///opt/spark/examples/jars/spark-examples.jar
18 | sparkVersion: 4.0.0
19 | restartPolicy:
20 | type: Never
21 | driver:
22 | labels:
23 | version: 4.0.0
24 | cores: 1
25 | coreLimit: 1200m
26 | memory: 512m
27 | serviceAccount: spark-operator-spark
28 | executor:
29 | labels:
30 | version: 4.0.0
31 | instances: 1
32 | cores: 1
33 | coreLimit: 1200m
34 | memory: 512m
35 |
--------------------------------------------------------------------------------
/hack/api-docs/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "hideMemberFields": [
3 | "TypeMeta"
4 | ],
5 | "hideTypePatterns": [
6 | "ParseError$",
7 | "List$"
8 | ],
9 | "externalPackages": [
10 | {
11 | "typeMatchPrefix": "^k8s\\.io/apimachinery/pkg/apis/meta/v1\\.Duration$",
12 | "docsURLTemplate": "https://pkg.go.dev/k8s.io/apimachinery/pkg/apis/meta/v1#Duration"
13 | },
14 | {
15 | "typeMatchPrefix": "^k8s\\.io/(api|apimachinery/pkg/apis)/",
16 | "docsURLTemplate": "https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.24/#{{lower .TypeIdentifier}}-{{arrIndex .PackageSegments -1}}-{{arrIndex .PackageSegments -2}}"
17 | },
18 | {
19 | "typeMatchPrefix": "^github\\.com/knative/pkg/apis/duck/",
20 | "docsURLTemplate": "https://pkg.go.dev/github.com/knative/pkg/apis/duck/{{arrIndex .PackageSegments -1}}#{{.TypeIdentifier}}"
21 | }
22 | ],
23 | "typeDisplayNamePrefixOverrides": {
24 | "k8s.io/api/": "Kubernetes ",
25 | "k8s.io/apimachinery/pkg/apis/": "Kubernetes "
26 | },
27 | "markdownDisabled": false
28 | }
--------------------------------------------------------------------------------
/hack/install_packages.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | #
3 | # Copyright 2019 The Kubernetes Authors.
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License");
6 | # you may not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS,
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | # See the License for the specific language governing permissions and
15 | # limitations under the License.
16 | set -e
17 | arg1=$(head -2 /opt/spark/credentials | tail -1)
18 | arg2=$(head -3 /opt/spark/credentials | tail -1)
19 | arg3=$(head -1 /opt/spark/credentials | tail -1)
20 |
21 | subscription-manager register --username=$arg1 --password=$arg2 --name=docker
22 | subscription-manager attach --pool=$arg3 && yum install -y openssl
23 | subscription-manager remove --all
24 | subscription-manager unregister
25 | subscription-manager clean
26 |
--------------------------------------------------------------------------------
/config/default/webhookcainjection_patch.yaml:
--------------------------------------------------------------------------------
1 | # This patch add annotation to admission webhook config and
2 | # CERTIFICATE_NAMESPACE and CERTIFICATE_NAME will be substituted by kustomize
3 | apiVersion: admissionregistration.k8s.io/v1
4 | kind: MutatingWebhookConfiguration
5 | metadata:
6 | labels:
7 | app.kubernetes.io/name: spark-operator
8 | app.kubernetes.io/managed-by: kustomize
9 | name: mutating-webhook-configuration
10 | annotations:
11 | cert-manager.io/inject-ca-from: CERTIFICATE_NAMESPACE/CERTIFICATE_NAME
12 | ---
13 | apiVersion: admissionregistration.k8s.io/v1
14 | kind: ValidatingWebhookConfiguration
15 | metadata:
16 | labels:
17 | app.kubernetes.io/name: validatingwebhookconfiguration
18 | app.kubernetes.io/instance: validating-webhook-configuration
19 | app.kubernetes.io/component: webhook
20 | app.kubernetes.io/created-by: spark-operator
21 | app.kubernetes.io/part-of: spark-operator
22 | app.kubernetes.io/managed-by: kustomize
23 | name: validating-webhook-configuration
24 | annotations:
25 | cert-manager.io/inject-ca-from: CERTIFICATE_NAMESPACE/CERTIFICATE_NAME
26 |
--------------------------------------------------------------------------------
/pkg/util/suite_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2024 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package util_test
18 |
19 | import (
20 | "testing"
21 |
22 | . "github.com/onsi/ginkgo/v2"
23 | . "github.com/onsi/gomega"
24 |
25 | "sigs.k8s.io/controller-runtime/pkg/log"
26 | "sigs.k8s.io/controller-runtime/pkg/log/zap"
27 | )
28 |
29 | func TestUtil(t *testing.T) {
30 | RegisterFailHandler(Fail)
31 |
32 | RunSpecs(t, "Util Suite")
33 | }
34 |
35 | var _ = BeforeSuite(func() {
36 | log.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
37 | })
38 |
--------------------------------------------------------------------------------
/.github/workflows/trivy-image-scanning.yaml:
--------------------------------------------------------------------------------
1 | name: Trivy image scanning
2 | on:
3 | workflow_dispatch:
4 | schedule:
5 | - cron: '0 0 * * 1' # Every Monday at 00:00
6 |
7 | jobs:
8 | image-scanning:
9 | runs-on: ubuntu-latest
10 |
11 | permissions:
12 | contents: read
13 | security-events: write
14 |
15 | steps:
16 | - name: Checkout code
17 | uses: actions/checkout@v5.0.0
18 |
19 | - name: Add image to environment
20 | run: make print-IMAGE >> $GITHUB_ENV
21 |
22 | - name: trivy scan for github security tab
23 | uses: aquasecurity/trivy-action@0.33.1
24 | with:
25 | image-ref: '${{ env.IMAGE }}'
26 | format: 'sarif'
27 | ignore-unfixed: true
28 | vuln-type: 'os,library'
29 | severity: 'CRITICAL,HIGH'
30 | output: 'trivy-results.sarif'
31 | timeout: 30m0s
32 |
33 | - name: Upload Trivy scan results to GitHub Security tab
34 | uses: github/codeql-action/upload-sarif@v4.31.2
35 | if: always()
36 | with:
37 | sarif_file: 'trivy-results.sarif'
38 |
--------------------------------------------------------------------------------
/charts/spark-operator-chart/templates/certmanager/_helpers.tpl:
--------------------------------------------------------------------------------
1 | {{- /*
2 | Copyright 2025 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */ -}}
16 |
17 | {{/*
18 | Create the name of the webhook certificate issuer.
19 | */}}
20 | {{- define "spark-operator.certManager.issuer.name" -}}
21 | {{ include "spark-operator.name" . }}-self-signed-issuer
22 | {{- end -}}
23 |
24 | {{/*
25 | Create the name of the certificate to be used by webhook.
26 | */}}
27 | {{- define "spark-operator.certManager.certificate.name" -}}
28 | {{ include "spark-operator.name" . }}-certificate
29 | {{- end -}}
30 |
--------------------------------------------------------------------------------
/ROADMAP.md:
--------------------------------------------------------------------------------
1 | # Spark Operator ROADMAP
2 |
3 | ## 2025
4 |
5 | - [x] A new CR to support Spark Connect ([#2569](https://github.com/kubeflow/spark-operator/pull/2569))
6 | - [x] Cert manger support ([#1178](https://github.com/kubeflow/spark-operator/issues/1178))
7 | - [ ] Improve controller performance
8 | - [ ] Notebooks integration
9 | - [ ] [Kubeflow SDK](https://github.com/kubeflow/sdk) integration
10 | - [ ] Rest API for submitting jobs
11 | - [ ] Deprecation of webhook by moving all functionality into the pod template ([#2502](https://github.com/kubeflow/spark-operator/issues/2502))
12 | - [ ] Watching namespaces based on labels
13 | - [ ] A web UI for visibility into currently running applications
14 | - [ ] Doc improvement
15 |
16 | ## 2024
17 |
18 | - [x] Pod template support ([#2101](https://github.com/kubeflow/spark-operator/issues/2101))
19 | - [x] Spark Connect Support ([#1801](https://github.com/kubeflow/spark-operator/issues/1801))
20 | - [x] Support Yunikorn as a batch scheduler ([#2107](https://github.com/kubeflow/spark-operator/pull/2107))
21 | - [x] Improve test coverage to improve the confidence in releases, particularly with e2e tests
22 |
--------------------------------------------------------------------------------
/entrypoint.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # echo commands to the terminal output
4 | set -ex
5 |
6 | # Check whether there is a passwd entry for the container UID
7 | myuid="$(id -u)"
8 | # If there is no passwd entry for the container UID, attempt to fake one
9 | # You can also refer to the https://github.com/docker-library/official-images/pull/13089#issuecomment-1534706523
10 | # It's to resolve OpenShift random UID case.
11 | # See also: https://github.com/docker-library/postgres/pull/448
12 | if ! getent passwd "$myuid" &> /dev/null; then
13 | for wrapper in {/usr,}/lib{/*,}/libnss_wrapper.so; do
14 | if [ -s "$wrapper" ]; then
15 | NSS_WRAPPER_PASSWD="$(mktemp)"
16 | NSS_WRAPPER_GROUP="$(mktemp)"
17 | export LD_PRELOAD="$wrapper" NSS_WRAPPER_PASSWD NSS_WRAPPER_GROUP
18 | mygid="$(id -g)"
19 | printf 'spark:x:%s:%s:%s:%s:/bin/false\n' "$myuid" "$mygid" "${SPARK_USER_NAME:-anonymous uid}" "$SPARK_HOME" > "$NSS_WRAPPER_PASSWD"
20 | printf 'spark:x:%s:\n' "$mygid" > "$NSS_WRAPPER_GROUP"
21 | break
22 | fi
23 | done
24 | fi
25 |
26 | exec /usr/bin/tini -s -- /usr/bin/spark-operator "$@"
27 |
--------------------------------------------------------------------------------
/pkg/util/resourcequota.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2024 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package util
18 |
19 | import (
20 | corev1 "k8s.io/api/core/v1"
21 | )
22 |
23 | // SumResourceList sums the resource list.
24 | func SumResourceList(lists []corev1.ResourceList) corev1.ResourceList {
25 | total := corev1.ResourceList{}
26 | for _, list := range lists {
27 | for name, quantity := range list {
28 | if value, ok := total[name]; !ok {
29 | total[name] = quantity.DeepCopy()
30 | } else {
31 | value.Add(quantity)
32 | total[name] = value
33 | }
34 | }
35 | }
36 | return total
37 | }
38 |
--------------------------------------------------------------------------------
/charts/spark-operator-chart/templates/hook/serviceaccount.yaml:
--------------------------------------------------------------------------------
1 | {{- /*
2 | Copyright 2025 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */ -}}
16 |
17 | {{- if .Values.hook.upgradeCrd }}
18 | apiVersion: v1
19 | kind: ServiceAccount
20 | metadata:
21 | name: {{ include "spark-operator.hook.serviceAccount.name" . }}
22 | namespace: {{ .Release.Namespace }}
23 | labels:
24 | {{- include "spark-operator.hook.labels" . | nindent 4 }}
25 | annotations:
26 | helm.sh/hook: pre-install,pre-upgrade
27 | helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded,hook-failed
28 | helm.sh/hook-weight: "1"
29 | {{- end }}
30 |
--------------------------------------------------------------------------------
/hack/api-docs/template/pkg.tpl:
--------------------------------------------------------------------------------
1 | {{ define "packages" }}
2 |
3 | {{ with .packages}}
4 |
Packages:
5 |
12 | {{ end}}
13 |
14 | {{ range .packages }}
15 |
16 | {{- packageDisplayName . -}}
17 |
18 |
19 | {{ with (index .GoPackages 0 )}}
20 | {{ with .DocComments }}
21 |
22 | {{ safe (renderComments .) }}
23 |
24 | {{ end }}
25 | {{ end }}
26 |
27 | Resource Types:
28 |
29 | {{- range (visibleTypes (sortedTypes .Types)) -}}
30 | {{ if isExportedType . -}}
31 | -
32 | {{ typeDisplayName . }}
33 |
34 | {{- end }}
35 | {{- end -}}
36 |
37 |
38 | {{ range (visibleTypes (sortedTypes .Types))}}
39 | {{ template "type" . }}
40 | {{ end }}
41 |
42 | {{ end }}
43 |
44 |
45 | Generated with gen-crd-api-reference-docs.
46 |
47 |
48 | {{ end }}
--------------------------------------------------------------------------------
/charts/spark-operator-chart/Chart.yaml:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright 2024 The Kubeflow authors.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # https://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 | #
16 |
17 | apiVersion: v2
18 |
19 | name: spark-operator
20 |
21 | description: A Helm chart for Spark on Kubernetes operator.
22 |
23 | version: 2.3.0
24 |
25 | appVersion: 2.3.0
26 |
27 | keywords:
28 | - apache spark
29 | - big data
30 |
31 | home: https://github.com/kubeflow/spark-operator
32 |
33 | maintainers:
34 | - name: yuchaoran2011
35 | email: yuchaoran2011@gmail.com
36 | url: https://github.com/yuchaoran2011
37 | - name: ChenYi015
38 | email: github@chenyicn.net
39 | url: https://github.com/ChenYi015
40 |
--------------------------------------------------------------------------------
/internal/scheduler/yunikorn/resourceusage/memory_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2024 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package resourceusage
18 |
19 | import (
20 | "testing"
21 |
22 | "github.com/stretchr/testify/assert"
23 | )
24 |
25 | func TestBytesToMi(t *testing.T) {
26 | testCases := []struct {
27 | input int64
28 | expected string
29 | }{
30 | {(2 * 1024 * 1024) - 1, "1Mi"},
31 | {2 * 1024 * 1024, "2Mi"},
32 | {(1024 * 1024 * 1024) - 1, "1023Mi"},
33 | {1024 * 1024 * 1024, "1024Mi"},
34 | }
35 |
36 | for _, tc := range testCases {
37 | assert.Equal(t, tc.expected, bytesToMi(tc.input))
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/charts/spark-operator-chart/templates/webhook/service.yaml:
--------------------------------------------------------------------------------
1 | {{/*
2 | Copyright 2024 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */}}
16 |
17 | {{- if .Values.webhook.enable }}
18 | apiVersion: v1
19 | kind: Service
20 | metadata:
21 | name: {{ include "spark-operator.webhook.serviceName" . }}
22 | labels:
23 | {{- include "spark-operator.webhook.labels" . | nindent 4 }}
24 | spec:
25 | selector:
26 | {{- include "spark-operator.webhook.selectorLabels" . | nindent 4 }}
27 | ports:
28 | - port: {{ .Values.webhook.port }}
29 | targetPort: {{ .Values.webhook.portName | quote }}
30 | name: {{ .Values.webhook.portName }}
31 | {{- end }}
32 |
--------------------------------------------------------------------------------
/api/v1beta2/register.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2024 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package v1beta2
18 |
19 | import (
20 | "k8s.io/apimachinery/pkg/runtime/schema"
21 | )
22 |
23 | const (
24 | Group = "sparkoperator.k8s.io"
25 | Version = "v1beta2"
26 | )
27 |
28 | // SchemeGroupVersion is the group version used to register these objects.
29 | var SchemeGroupVersion = schema.GroupVersion{Group: Group, Version: Version}
30 |
31 | // Resource takes an unqualified resource and returns a Group-qualified GroupResource.
32 | func Resource(resource string) schema.GroupResource {
33 | return SchemeGroupVersion.WithResource(resource).GroupResource()
34 | }
35 |
--------------------------------------------------------------------------------
/api/v1alpha1/register.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2025 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package v1alpha1
18 |
19 | import (
20 | "k8s.io/apimachinery/pkg/runtime/schema"
21 | )
22 |
23 | const (
24 | Group = "sparkoperator.k8s.io"
25 | Version = "v1alpha1"
26 | )
27 |
28 | // SchemeGroupVersion is the group version used to register these objects.
29 | var SchemeGroupVersion = schema.GroupVersion{Group: Group, Version: Version}
30 |
31 | // Resource takes an unqualified resource and returns a Group-qualified GroupResource.
32 | func Resource(resource string) schema.GroupResource {
33 | return SchemeGroupVersion.WithResource(resource).GroupResource()
34 | }
35 |
--------------------------------------------------------------------------------
/cmd/operator/version/root.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2024 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package version
18 |
19 | import (
20 | "github.com/spf13/cobra"
21 |
22 | sparkoperator "github.com/kubeflow/spark-operator/v2"
23 | )
24 |
25 | var (
26 | short bool
27 | )
28 |
29 | func NewCommand() *cobra.Command {
30 | command := &cobra.Command{
31 | Use: "version",
32 | Short: "Print version information",
33 | RunE: func(cmd *cobra.Command, args []string) error {
34 | sparkoperator.PrintVersion(short)
35 | return nil
36 | },
37 | }
38 | command.Flags().BoolVar(&short, "short", false, "Print just the version string.")
39 | return command
40 | }
41 |
--------------------------------------------------------------------------------
/internal/webhook/webhook.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2024 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package webhook
18 |
19 | import (
20 | ctrl "sigs.k8s.io/controller-runtime"
21 | )
22 |
23 | var (
24 | logger = ctrl.Log.WithName("")
25 | )
26 |
27 | type Options struct {
28 | SparkJobNamespaces []string
29 | WebhookName string
30 | WebhookPort int
31 | WebhookSecretName string
32 | WebhookSecretNamespace string
33 | WebhookServiceName string
34 | WebhookServiceNamespace string
35 | WebhookMetricsBindAddress string
36 | EnableResourceQuotaEnforcement bool
37 | }
38 |
--------------------------------------------------------------------------------
/charts/spark-operator-chart/templates/controller/service.yaml:
--------------------------------------------------------------------------------
1 | {{/*
2 | Copyright 2024 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */}}
16 |
17 | {{- if .Values.controller.pprof.enable }}
18 | apiVersion: v1
19 | kind: Service
20 | metadata:
21 | name: {{ include "spark-operator.controller.serviceName" . }}
22 | labels:
23 | {{- include "spark-operator.controller.labels" . | nindent 4 }}
24 | spec:
25 | selector:
26 | {{- include "spark-operator.controller.selectorLabels" . | nindent 4 }}
27 | ports:
28 | - port: {{ .Values.controller.pprof.port }}
29 | targetPort: {{ .Values.controller.pprof.portName | quote }}
30 | name: {{ .Values.controller.pprof.portName }}
31 | {{- end }}
32 |
--------------------------------------------------------------------------------
/PROJECT:
--------------------------------------------------------------------------------
1 | # Code generated by tool. DO NOT EDIT.
2 | # This file is used to track the info used to scaffold your project
3 | # and allow the plugins properly work.
4 | # More info: https://book.kubebuilder.io/reference/project-config.html
5 | domain: sparkoperator.k8s.io
6 | layout:
7 | - go.kubebuilder.io/v4
8 | projectName: spark-operator
9 | repo: github.com/kubeflow/spark-operator
10 | resources:
11 | - api:
12 | crdVersion: v1
13 | namespaced: true
14 | controller: true
15 | domain: sparkoperator.k8s.io
16 | kind: SparkConnect
17 | path: github.com/kubeflow/spark-operator/api/v1alpha1
18 | version: v1alpha1
19 | - api:
20 | crdVersion: v1
21 | namespaced: true
22 | controller: true
23 | domain: sparkoperator.k8s.io
24 | kind: SparkApplication
25 | path: github.com/kubeflow/spark-operator/api/v1beta2
26 | version: v1beta2
27 | webhooks:
28 | defaulting: true
29 | validation: true
30 | webhookVersion: v1
31 | - api:
32 | crdVersion: v1
33 | namespaced: true
34 | controller: true
35 | domain: sparkoperator.k8s.io
36 | kind: ScheduledSparkApplication
37 | path: github.com/kubeflow/spark-operator/api/v1beta2
38 | version: v1beta2
39 | version: "3"
40 |
--------------------------------------------------------------------------------
/charts/spark-operator-chart/templates/controller/serviceaccount.yaml:
--------------------------------------------------------------------------------
1 | {{/*
2 | Copyright 2024 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */}}
16 |
17 | {{- if .Values.controller.serviceAccount.create }}
18 | apiVersion: v1
19 | kind: ServiceAccount
20 | automountServiceAccountToken: {{ .Values.controller.serviceAccount.automountServiceAccountToken }}
21 | metadata:
22 | name: {{ include "spark-operator.controller.serviceAccountName" . }}
23 | namespace: {{ .Release.Namespace }}
24 | labels:
25 | {{- include "spark-operator.controller.labels" . | nindent 4 }}
26 | {{- with .Values.controller.serviceAccount.annotations }}
27 | annotations:
28 | {{- toYaml . | nindent 4 }}
29 | {{- end }}
30 | {{- end }}
31 |
--------------------------------------------------------------------------------
/config/crd/kustomization.yaml:
--------------------------------------------------------------------------------
1 | # This kustomization.yaml is not intended to be run by itself,
2 | # since it depends on service name and namespace that are out of this kustomize package.
3 | # It should be run by config/default
4 | resources:
5 | - bases/sparkoperator.k8s.io_scheduledsparkapplications.yaml
6 | - bases/sparkoperator.k8s.io_sparkapplications.yaml
7 | # +kubebuilder:scaffold:crdkustomizeresource
8 |
9 | patches:
10 | # [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix.
11 | # patches here are for enabling the conversion webhook for each CRD
12 | - path: patches/webhook_in_sparkapplications.yaml
13 | - path: patches/webhook_in_sparkapplications.yaml
14 | # +kubebuilder:scaffold:crdkustomizewebhookpatch
15 |
16 | # [CERTMANAGER] To enable cert-manager, uncomment all the sections with [CERTMANAGER] prefix.
17 | # patches here are for enabling the CA injection for each CRD
18 | #- path: patches/cainjection_in_scheduledsparkapplications.yaml
19 | #- path: patches/cainjection_in_sparkapplications.yaml
20 | # +kubebuilder:scaffold:crdkustomizecainjectionpatch
21 |
22 | # [WEBHOOK] To enable webhook, uncomment the following section
23 | # the following config is for teaching kustomize how to do kustomization for CRDs.
24 |
25 | configurations:
26 | - kustomizeconfig.yaml
27 |
--------------------------------------------------------------------------------
/charts/spark-operator-chart/templates/webhook/serviceaccount.yaml:
--------------------------------------------------------------------------------
1 | {{/*
2 | Copyright 2024 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */}}
16 |
17 | {{- if .Values.webhook.enable }}
18 | {{- if .Values.webhook.serviceAccount.create -}}
19 | apiVersion: v1
20 | kind: ServiceAccount
21 | automountServiceAccountToken: {{ .Values.webhook.serviceAccount.automountServiceAccountToken }}
22 | metadata:
23 | name: {{ include "spark-operator.webhook.serviceAccountName" . }}
24 | namespace: {{ .Release.Namespace }}
25 | labels:
26 | {{- include "spark-operator.webhook.labels" . | nindent 4 }}
27 | {{- with .Values.webhook.serviceAccount.annotations }}
28 | annotations:
29 | {{- toYaml . | nindent 4 }}
30 | {{- end }}
31 | {{- end }}
32 | {{- end }}
33 |
--------------------------------------------------------------------------------
/hack/api-docs/template/members.tpl:
--------------------------------------------------------------------------------
1 | {{ define "members" }}
2 |
3 | {{ range .Members }}
4 | {{ if not (hiddenMember .)}}
5 |
6 |
7 | {{ fieldName . }}
8 |
9 | {{ if linkForType .Type }}
10 |
11 | {{ typeDisplayName .Type }}
12 |
13 | {{ else }}
14 | {{ typeDisplayName .Type }}
15 | {{ end }}
16 |
17 | |
18 |
19 | {{ if fieldEmbedded . }}
20 |
21 | (Members of {{ fieldName . }} are embedded into this type.)
22 |
23 | {{ end}}
24 |
25 | {{ if isOptionalMember .}}
26 | (Optional)
27 | {{ end }}
28 |
29 | {{ safe (renderComments .CommentLines) }}
30 |
31 | {{ if and (eq (.Type.Name.Name) "ObjectMeta") }}
32 | Refer to the Kubernetes API documentation for the fields of the
33 | metadata field.
34 | {{ end }}
35 |
36 | {{ if or (eq (fieldName .) "spec") }}
37 |
38 |
39 |
40 | {{ template "members" .Type }}
41 |
42 | {{ end }}
43 | |
44 |
45 | {{ end }}
46 | {{ end }}
47 |
48 | {{ end }}
--------------------------------------------------------------------------------
/charts/spark-operator-chart/templates/certmanager/issuer.yaml:
--------------------------------------------------------------------------------
1 | {{- /*
2 | Copyright 2025 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */ -}}
16 |
17 | {{- if .Values.webhook.enable }}
18 | {{- if .Values.certManager.enable }}
19 | {{- if not .Values.certManager.issuerRef }}
20 | {{- if not (.Capabilities.APIVersions.Has "cert-manager.io/v1/Issuer") }}
21 | {{- fail "The cluster does not support the required API version `cert-manager.io/v1` for `Issuer`." }}
22 | {{- end }}
23 | apiVersion: cert-manager.io/v1
24 | kind: Issuer
25 | metadata:
26 | name: {{ include "spark-operator.certManager.issuer.name" . }}
27 | namespace: {{ .Release.Namespace }}
28 | labels:
29 | {{- include "spark-operator.labels" . | nindent 4 }}
30 | spec:
31 | selfSigned: {}
32 | {{- end }}
33 | {{- end }}
34 | {{- end }}
35 |
--------------------------------------------------------------------------------
/internal/webhook/resourcequota_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2024 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package webhook
18 |
19 | import (
20 | "testing"
21 | )
22 |
23 | func assertMemory(memoryString string, expectedBytes int64, t *testing.T) {
24 | m, err := parseJavaMemoryString(memoryString)
25 | if err != nil {
26 | t.Error(err)
27 | return
28 | }
29 | if m != expectedBytes {
30 | t.Errorf("%s: expected %v bytes, got %v bytes", memoryString, expectedBytes, m)
31 | return
32 | }
33 | }
34 |
35 | func TestJavaMemoryString(t *testing.T) {
36 | assertMemory("1b", 1, t)
37 | assertMemory("100k", 100*1024, t)
38 | assertMemory("1gb", 1024*1024*1024, t)
39 | assertMemory("10TB", 10*1024*1024*1024*1024, t)
40 | assertMemory("10PB", 10*1024*1024*1024*1024*1024, t)
41 | }
42 |
--------------------------------------------------------------------------------
/charts/spark-operator-chart/tests/hook/serviceaccount_test.yaml:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright 2024 The Kubeflow authors.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # https://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 | #
16 |
17 | suite: Test hook service account
18 |
19 | templates:
20 | - hook/serviceaccount.yaml
21 |
22 | release:
23 | name: spark-operator
24 | namespace: spark-operator
25 |
26 | tests:
27 | - it: Should not create hook service account if `hook.upgradeCrd` is false
28 | set:
29 | hook:
30 | upgradeCrd: false
31 | asserts:
32 | - hasDocuments:
33 | count: 0
34 |
35 | - it: Should create hook service account if `hook.upgradeCrd` is true
36 | set:
37 | hook:
38 | upgradeCrd: true
39 | asserts:
40 | - containsDocument:
41 | apiVersion: v1
42 | kind: ServiceAccount
43 | name: spark-operator-hook
44 |
--------------------------------------------------------------------------------
/internal/scheduler/scheduler.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019 Google LLC
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package scheduler
18 |
19 | import (
20 | "sigs.k8s.io/controller-runtime/pkg/log"
21 |
22 | "github.com/kubeflow/spark-operator/v2/api/v1beta2"
23 | )
24 |
25 | var (
26 | logger = log.Log.WithName("")
27 | )
28 |
29 | // Interface defines the interface of a batch scheduler.
30 | type Interface interface {
31 | Name() string
32 | ShouldSchedule(app *v1beta2.SparkApplication) bool
33 | Schedule(app *v1beta2.SparkApplication) error
34 | Cleanup(app *v1beta2.SparkApplication) error
35 | }
36 |
37 | // Config defines the configuration of a batch scheduler.
38 | type Config interface{}
39 |
40 | // Factory defines the factory of a batch scheduler.
41 | type Factory func(config Config) (Interface, error)
42 |
--------------------------------------------------------------------------------
/charts/spark-operator-chart/templates/spark/serviceaccount.yaml:
--------------------------------------------------------------------------------
1 | {{/*
2 | Copyright 2024 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */}}
16 |
17 | {{- if .Values.spark.serviceAccount.create }}
18 | {{- range $jobNamespace := .Values.spark.jobNamespaces | default list }}
19 | {{- if ne $jobNamespace "" }}
20 |
21 | ---
22 | apiVersion: v1
23 | kind: ServiceAccount
24 | automountServiceAccountToken: {{ $.Values.spark.serviceAccount.automountServiceAccountToken }}
25 | metadata:
26 | name: {{ include "spark-operator.spark.serviceAccountName" $ }}
27 | namespace: {{ $jobNamespace }}
28 | labels: {{ include "spark-operator.labels" $ | nindent 4 }}
29 | {{- with $.Values.spark.serviceAccount.annotations }}
30 | annotations: {{ toYaml . | nindent 4 }}
31 | {{- end }}
32 | {{- end }}
33 | {{- end }}
34 | {{- end }}
35 |
--------------------------------------------------------------------------------
/docker/Dockerfile.kubectl:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright 2025 The Kubeflow authors.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # https://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 | #
16 |
17 | ARG BASE_IMAGE=docker.io/library/alpine:3.22.0
18 |
19 | FROM ${BASE_IMAGE} AS builder
20 |
21 | ARG TARGETARCH
22 |
23 | ARG KUBECTL_VERSION=1.33.2
24 |
25 | WORKDIR /workspace
26 |
27 | RUN apk add --update --no-cache curl \
28 | && curl -LO https://dl.k8s.io/release/v${KUBECTL_VERSION}/bin/linux/${TARGETARCH}/kubectl \
29 | && curl -LO https://dl.k8s.io/release/v${KUBECTL_VERSION}/bin/linux/${TARGETARCH}/kubectl.sha256 \
30 | && echo "$(cat kubectl.sha256) kubectl" | sha256sum -cs \
31 | && chmod 0755 kubectl
32 |
33 | FROM ${BASE_IMAGE}
34 |
35 | COPY charts/spark-operator-chart/crds /etc/spark-operator/crds
36 |
37 | COPY --from=builder /workspace/kubectl /usr/bin/kubectl
38 |
39 | ENTRYPOINT ["/usr/bin/kubectl"]
40 |
--------------------------------------------------------------------------------
/test/e2e/bad_examples/fail-application.yaml:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright 2024 The Kubeflow authors.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | apiVersion: sparkoperator.k8s.io/v1beta2
17 | kind: SparkApplication
18 | metadata:
19 | name: fail-submission
20 | namespace: default
21 | spec:
22 | type: Scala
23 | mode: cluster
24 | image: spark:4.0.0
25 | imagePullPolicy: IfNotPresent
26 | mainClass: non-existent
27 | mainApplicationFile: local:///non-existent.jar
28 | sparkVersion: 4.0.0
29 | restartPolicy:
30 | type: OnFailure
31 | onFailureRetries: 3
32 | onFailureRetryInterval: 1
33 | driver:
34 | labels:
35 | version: 4.0.0
36 | cores: 1
37 | memory: 512m
38 | serviceAccount: spark-operator-spark
39 | executor:
40 | labels:
41 | version: 4.0.0
42 | instances: 1
43 | cores: 1
44 | memory: 512m
45 |
--------------------------------------------------------------------------------
/charts/spark-operator-chart/tests/controller/service_test.yaml:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright 2024 The Kubeflow authors.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # https://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 | #
16 |
17 | suite: Test controller deployment
18 |
19 | templates:
20 | - controller/service.yaml
21 |
22 | release:
23 | name: spark-operator
24 | namespace: spark-operator
25 |
26 | tests:
27 | - it: Should create the pprof service correctly
28 | set:
29 | controller:
30 | pprof:
31 | enable: true
32 | port: 12345
33 | portName: pprof-test
34 | asserts:
35 | - containsDocument:
36 | apiVersion: v1
37 | kind: Service
38 | name: spark-operator-controller-svc
39 | - equal:
40 | path: spec.ports[0]
41 | value:
42 | port: 12345
43 | targetPort: pprof-test
44 | name: pprof-test
--------------------------------------------------------------------------------
/api/v1alpha1/groupversion_info.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2025 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | // Package v1alpha1 contains API Schema definitions for the v1alpha1 API group
18 | // +kubebuilder:object:generate=true
19 | // +groupName=sparkoperator.k8s.io
20 | package v1alpha1
21 |
22 | import (
23 | "k8s.io/apimachinery/pkg/runtime/schema"
24 | "sigs.k8s.io/controller-runtime/pkg/scheme"
25 | )
26 |
27 | var (
28 | // GroupVersion is group version used to register these objects.
29 | GroupVersion = schema.GroupVersion{Group: "sparkoperator.k8s.io", Version: "v1alpha1"}
30 |
31 | // SchemeBuilder is used to add go types to the GroupVersionKind scheme.
32 | SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
33 |
34 | // AddToScheme adds the types in this group-version to the given scheme.
35 | AddToScheme = SchemeBuilder.AddToScheme
36 | )
37 |
--------------------------------------------------------------------------------
/charts/spark-operator-chart/templates/controller/poddisruptionbudget.yaml:
--------------------------------------------------------------------------------
1 | {{/*
2 | Copyright 2024 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */}}
16 |
17 | {{- if .Values.controller.podDisruptionBudget.enable }}
18 | {{- if le (int .Values.controller.replicas) 1 }}
19 | {{- fail "controller.replicas must be greater than 1 to enable pod disruption budget for controller" }}
20 | {{- end -}}
21 | apiVersion: policy/v1
22 | kind: PodDisruptionBudget
23 | metadata:
24 | name: {{ include "spark-operator.controller.podDisruptionBudgetName" . }}
25 | labels:
26 | {{- include "spark-operator.controller.labels" . | nindent 4 }}
27 | spec:
28 | selector:
29 | matchLabels:
30 | {{- include "spark-operator.controller.selectorLabels" . | nindent 6 }}
31 | {{- with .Values.controller.podDisruptionBudget.minAvailable }}
32 | minAvailable: {{ . }}
33 | {{- end }}
34 | {{- end }}
35 |
--------------------------------------------------------------------------------
/config/certmanager/certificate.yaml:
--------------------------------------------------------------------------------
1 | # The following manifests contain a self-signed issuer CR and a certificate CR.
2 | # More document can be found at https://docs.cert-manager.io
3 | # WARNING: Targets CertManager v1.0. Check https://cert-manager.io/docs/installation/upgrading/ for breaking changes.
4 | apiVersion: cert-manager.io/v1
5 | kind: Issuer
6 | metadata:
7 | labels:
8 | app.kubernetes.io/name: spark-operator
9 | app.kubernetes.io/managed-by: kustomize
10 | name: selfsigned-issuer
11 | namespace: system
12 | spec:
13 | selfSigned: {}
14 | ---
15 | apiVersion: cert-manager.io/v1
16 | kind: Certificate
17 | metadata:
18 | labels:
19 | app.kubernetes.io/name: certificate
20 | app.kubernetes.io/instance: serving-cert
21 | app.kubernetes.io/component: certificate
22 | app.kubernetes.io/created-by: spark-operator
23 | app.kubernetes.io/part-of: spark-operator
24 | app.kubernetes.io/managed-by: kustomize
25 | name: serving-cert # this name should match the one appeared in kustomizeconfig.yaml
26 | namespace: system
27 | spec:
28 | # SERVICE_NAME and SERVICE_NAMESPACE will be substituted by kustomize
29 | dnsNames:
30 | - SERVICE_NAME.SERVICE_NAMESPACE.svc
31 | - SERVICE_NAME.SERVICE_NAMESPACE.svc.cluster.local
32 | issuerRef:
33 | kind: Issuer
34 | name: selfsigned-issuer
35 | secretName: webhook-server-cert # this secret will not be prefixed, since it's not managed by kustomize
36 |
--------------------------------------------------------------------------------
/charts/spark-operator-chart/templates/webhook/poddisruptionbudget.yaml:
--------------------------------------------------------------------------------
1 | {{/*
2 | Copyright 2024 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */}}
16 |
17 | {{- if .Values.webhook.enable }}
18 | {{- if .Values.webhook.podDisruptionBudget.enable }}
19 | {{- if le (int .Values.webhook.replicas) 1 }}
20 | {{- fail "webhook.replicas must be greater than 1 to enable pod disruption budget for webhook" }}
21 | {{- end -}}
22 | apiVersion: policy/v1
23 | kind: PodDisruptionBudget
24 | metadata:
25 | name: {{ include "spark-operator.webhook.podDisruptionBudgetName" . }}
26 | labels:
27 | {{- include "spark-operator.webhook.labels" . | nindent 4 }}
28 | spec:
29 | selector:
30 | matchLabels:
31 | {{- include "spark-operator.webhook.selectorLabels" . | nindent 6 }}
32 | {{- with .Values.webhook.podDisruptionBudget.minAvailable }}
33 | minAvailable: {{ . }}
34 | {{- end }}
35 | {{- end }}
36 | {{- end }}
37 |
--------------------------------------------------------------------------------
/test/e2e/bad_examples/fail-submission.yaml:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright 2024 The Kubeflow authors.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | apiVersion: sparkoperator.k8s.io/v1beta2
17 | kind: SparkApplication
18 | metadata:
19 | name: fail-submission
20 | namespace: default
21 | spec:
22 | type: Scala
23 | mode: cluster
24 | image: spark:4.0.0
25 | imagePullPolicy: IfNotPresent
26 | mainClass: dummy
27 | mainApplicationFile: local:///dummy.jar
28 | sparkVersion: 4.0.0
29 | restartPolicy:
30 | type: OnFailure
31 | onSubmissionFailureRetries: 3
32 | onSubmissionFailureRetryInterval: 1
33 | driver:
34 | labels:
35 | version: 4.0.0
36 | cores: 1
37 | memory: 512m
38 | serviceAccount: non-existent # This is the important part that causes submission to fail.
39 | executor:
40 | labels:
41 | version: 4.0.0
42 | instances: 1
43 | cores: 1
44 | memory: 512m
45 |
--------------------------------------------------------------------------------
/hack/verify-codegen.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Copyright 2017 The Kubernetes Authors.
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License");
6 | # you may not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS,
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | # See the License for the specific language governing permissions and
15 | # limitations under the License.
16 |
17 | set -o errexit
18 | set -o nounset
19 | set -o pipefail
20 |
21 | SCRIPT_ROOT=$(dirname "${BASH_SOURCE}")/..
22 |
23 | DIFFROOT="${SCRIPT_ROOT}/pkg"
24 | TMP_DIFFROOT="${SCRIPT_ROOT}/_tmp/pkg"
25 | _tmp="${SCRIPT_ROOT}/_tmp"
26 |
27 | cleanup() {
28 | rm -rf "${_tmp}"
29 | }
30 | trap "cleanup" EXIT SIGINT
31 |
32 | cleanup
33 |
34 | mkdir -p "${TMP_DIFFROOT}"
35 | cp -a "${DIFFROOT}"/* "${TMP_DIFFROOT}"
36 |
37 | "${SCRIPT_ROOT}/hack/update-codegen.sh"
38 | echo "diffing ${DIFFROOT} against freshly generated codegen"
39 | ret=0
40 | diff -Naupr "${DIFFROOT}" "${TMP_DIFFROOT}" || ret=$?
41 | cp -a "${TMP_DIFFROOT}"/* "${DIFFROOT}"
42 | if [[ $ret -eq 0 ]]
43 | then
44 | echo "${DIFFROOT} up to date."
45 | else
46 | echo "${DIFFROOT} is out of date. Please run hack/update-codegen.sh"
47 | exit 1
48 | fi
49 |
--------------------------------------------------------------------------------
/cmd/operator/main.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2024 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package main
18 |
19 | import (
20 | "fmt"
21 | "os"
22 |
23 | "github.com/spf13/cobra"
24 |
25 | "github.com/kubeflow/spark-operator/v2/cmd/operator/controller"
26 | "github.com/kubeflow/spark-operator/v2/cmd/operator/version"
27 | "github.com/kubeflow/spark-operator/v2/cmd/operator/webhook"
28 | )
29 |
30 | func NewCommand() *cobra.Command {
31 | command := &cobra.Command{
32 | Use: "spark-operator",
33 | Short: "Spark operator",
34 | RunE: func(cmd *cobra.Command, _ []string) error {
35 | return cmd.Help()
36 | },
37 | }
38 | command.AddCommand(controller.NewCommand())
39 | command.AddCommand(webhook.NewCommand())
40 | command.AddCommand(version.NewCommand())
41 | return command
42 | }
43 |
44 | func main() {
45 | if err := NewCommand().Execute(); err != nil {
46 | fmt.Fprintf(os.Stderr, "%v\n", err)
47 | os.Exit(1)
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/pkg/client/listers/api/v1beta2/expansion_generated.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2025 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 | // Code generated by lister-gen. DO NOT EDIT.
17 |
18 | package v1beta2
19 |
20 | // ScheduledSparkApplicationListerExpansion allows custom methods to be added to
21 | // ScheduledSparkApplicationLister.
22 | type ScheduledSparkApplicationListerExpansion interface{}
23 |
24 | // ScheduledSparkApplicationNamespaceListerExpansion allows custom methods to be added to
25 | // ScheduledSparkApplicationNamespaceLister.
26 | type ScheduledSparkApplicationNamespaceListerExpansion interface{}
27 |
28 | // SparkApplicationListerExpansion allows custom methods to be added to
29 | // SparkApplicationLister.
30 | type SparkApplicationListerExpansion interface{}
31 |
32 | // SparkApplicationNamespaceListerExpansion allows custom methods to be added to
33 | // SparkApplicationNamespaceLister.
34 | type SparkApplicationNamespaceListerExpansion interface{}
35 |
--------------------------------------------------------------------------------
/charts/spark-operator-chart/templates/hook/cluster_role_binding.yaml:
--------------------------------------------------------------------------------
1 | {{- /*
2 | Copyright 2025 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */ -}}
16 |
17 | {{- if .Values.hook.upgradeCrd -}}
18 | apiVersion: rbac.authorization.k8s.io/v1
19 | kind: ClusterRoleBinding
20 | metadata:
21 | name: {{ include "spark-operator.hook.clusterRoleBinding.name" . }}
22 | namespace: {{ .Release.Namespace }}
23 | labels:
24 | {{- include "spark-operator.hook.labels" . | nindent 4 }}
25 | annotations:
26 | helm.sh/hook: pre-install,pre-upgrade
27 | helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded,hook-failed
28 | helm.sh/hook-weight: "3"
29 | roleRef:
30 | apiGroup: rbac.authorization.k8s.io
31 | kind: ClusterRole
32 | name: {{ include "spark-operator.hook.clusterRole.name" . }}
33 | subjects:
34 | - kind: ServiceAccount
35 | name: {{ include "spark-operator.hook.serviceAccount.name" . }}
36 | namespace: {{ .Release.Namespace }}
37 | {{- end }}
38 |
--------------------------------------------------------------------------------
/charts/spark-operator-chart/templates/hook/cluster_role.yaml:
--------------------------------------------------------------------------------
1 | {{- /*
2 | Copyright 2025 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */ -}}
16 |
17 | {{- if .Values.hook.upgradeCrd -}}
18 | apiVersion: rbac.authorization.k8s.io/v1
19 | kind: ClusterRole
20 | metadata:
21 | name: {{ include "spark-operator.hook.clusterRole.name" . }}
22 | namespace: {{ .Release.Namespace }}
23 | labels:
24 | {{- include "spark-operator.hook.labels" . | nindent 4 }}
25 | annotations:
26 | helm.sh/hook: pre-install,pre-upgrade
27 | helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded,hook-failed
28 | helm.sh/hook-weight: "2"
29 | rules:
30 | - apiGroups:
31 | - apiextensions.k8s.io
32 | resources:
33 | - customresourcedefinitions
34 | resourceNames:
35 | - sparkapplications.sparkoperator.k8s.io
36 | - sparkconnects.sparkoperator.k8s.io
37 | - scheduledsparkapplications.sparkoperator.k8s.io
38 | verbs:
39 | - get
40 | - patch
41 | - create
42 | {{- end }}
43 |
--------------------------------------------------------------------------------
/charts/spark-operator-chart/tests/webhook/service_test.yaml:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright 2024 The Kubeflow authors.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # https://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 | #
16 |
17 | suite: Test webhook service
18 |
19 | templates:
20 | - webhook/service.yaml
21 |
22 | release:
23 | name: spark-operator
24 | namespace: spark-operator
25 |
26 | tests:
27 | - it: Should not create webhook service if `webhook.enable` is `false`
28 | set:
29 | webhook:
30 | enable: false
31 | asserts:
32 | - hasDocuments:
33 | count: 0
34 |
35 | - it: Should create the webhook service correctly
36 | set:
37 | webhook:
38 | portName: webhook
39 | asserts:
40 | - containsDocument:
41 | apiVersion: v1
42 | kind: Service
43 | name: spark-operator-webhook-svc
44 | - equal:
45 | path: spec.ports[0]
46 | value:
47 | port: 9443
48 | targetPort: webhook
49 | name: webhook
50 |
--------------------------------------------------------------------------------
/hack/update-codegen.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Copyright 2017 The Kubernetes Authors.
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License");
6 | # you may not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS,
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | # See the License for the specific language governing permissions and
15 | # limitations under the License.
16 |
17 | set -o errexit
18 | set -o nounset
19 | set -o pipefail
20 |
21 | GO_CMD=${1:-go}
22 | SCRIPT_DIR="$(dirname "${BASH_SOURCE[0]}")"
23 | SCRIPT_ROOT="${SCRIPT_DIR}/.."
24 | CODEGEN_PKG="$($GO_CMD list -m -mod=readonly -f "{{.Dir}}" k8s.io/code-generator)"
25 | SPARK_OPERATOR_PKG="github.com/kubeflow/spark-operator/v2"
26 |
27 | source "${CODEGEN_PKG}/kube_codegen.sh"
28 |
29 | # Generate register code
30 | kube::codegen::gen_register \
31 | --boilerplate "${SCRIPT_ROOT}/hack/boilerplate.go.txt" \
32 | "${SCRIPT_ROOT}"
33 |
34 | # Generate client code: client, lister, informer in client-go directory
35 | kube::codegen::gen_client \
36 | --with-watch \
37 | --output-dir "${SCRIPT_ROOT}/pkg/client" \
38 | --output-pkg "${SPARK_OPERATOR_PKG}/pkg/client" \
39 | --boilerplate "${SCRIPT_ROOT}/hack/boilerplate.go.txt" \
40 | "${SCRIPT_ROOT}"
41 |
--------------------------------------------------------------------------------
/config/rbac/spark-application-rbac.yaml:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright 2024 The Kubeflow authors.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # https://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 | #
16 | apiVersion: v1
17 | kind: ServiceAccount
18 | metadata:
19 | name: spark-operator-spark
20 | namespace: default
21 | ---
22 | apiVersion: rbac.authorization.k8s.io/v1
23 | kind: Role
24 | metadata:
25 | namespace: default
26 | name: spark-role
27 | rules:
28 | - apiGroups:
29 | - ""
30 | resources:
31 | - pods
32 | - configmaps
33 | - persistentvolumeclaims
34 | - services
35 | verbs:
36 | - get
37 | - list
38 | - watch
39 | - create
40 | - update
41 | - patch
42 | - delete
43 | - deletecollection
44 | ---
45 | apiVersion: rbac.authorization.k8s.io/v1
46 | kind: RoleBinding
47 | metadata:
48 | name: spark-role-binding
49 | namespace: default
50 | subjects:
51 | - kind: ServiceAccount
52 | name: spark-operator-spark
53 | namespace: default
54 | roleRef:
55 | kind: Role
56 | name: spark-role
57 | apiGroup: rbac.authorization.k8s.io
58 |
--------------------------------------------------------------------------------
/internal/scheduler/yunikorn/resourceusage/resource_usage_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2024 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package resourceusage
18 |
19 | import (
20 | "testing"
21 |
22 | "github.com/stretchr/testify/assert"
23 | "k8s.io/utils/ptr"
24 | )
25 |
26 | func TestCpuRequest(t *testing.T) {
27 | testCases := []struct {
28 | cores *int32
29 | coreRequest *string
30 | expected string
31 | }{
32 | {nil, nil, "1"},
33 | {ptr.To[int32](1), nil, "1"},
34 | {nil, ptr.To("1"), "1"},
35 | {ptr.To[int32](1), ptr.To("500m"), "500m"},
36 | }
37 |
38 | for _, tc := range testCases {
39 | actual, err := cpuRequest(tc.cores, tc.coreRequest)
40 | assert.Nil(t, err)
41 | assert.Equal(t, tc.expected, actual)
42 | }
43 | }
44 |
45 | func TestCpuRequestInvalid(t *testing.T) {
46 | invalidInputs := []string{
47 | "",
48 | "asd",
49 | "Random 500m",
50 | }
51 |
52 | for _, input := range invalidInputs {
53 | _, err := cpuRequest(nil, &input)
54 | assert.NotNil(t, err)
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/.github/workflows/stale.yaml:
--------------------------------------------------------------------------------
1 | name: Mark stale issues and pull requests
2 |
3 | on:
4 | schedule:
5 | - cron: "0 */2 * * *"
6 |
7 | jobs:
8 | stale:
9 | runs-on: ubuntu-latest
10 |
11 | permissions:
12 | issues: write
13 | pull-requests: write
14 |
15 | steps:
16 | - uses: actions/stale@v10
17 | with:
18 | repo-token: ${{ secrets.GITHUB_TOKEN }}
19 | days-before-stale: 90
20 | days-before-close: 20
21 | operations-per-run: 200
22 | stale-issue-message: >
23 | This issue has been automatically marked as stale because it has not had
24 | recent activity. It will be closed if no further activity occurs. Thank you
25 | for your contributions.
26 | close-issue-message: >
27 | This issue has been automatically closed because it has not had recent
28 | activity. Please comment "/reopen" to reopen it.
29 | stale-issue-label: lifecycle/stale
30 | exempt-issue-labels: lifecycle/frozen
31 | stale-pr-message: >
32 | This pull request has been automatically marked as stale because it has not had
33 | recent activity. It will be closed if no further activity occurs. Thank you
34 | for your contributions.
35 | close-pr-message: >
36 | This pull request has been automatically closed because it has not had recent
37 | activity. Please comment "/reopen" to reopen it.
38 | stale-pr-label: lifecycle/stale
39 | exempt-pr-labels: lifecycle/frozen
40 |
--------------------------------------------------------------------------------
/internal/controller/sparkapplication/validator.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2024 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package sparkapplication
18 |
19 | import (
20 | "context"
21 |
22 | "k8s.io/apimachinery/pkg/runtime"
23 | "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
24 | )
25 |
26 | type Validator struct{}
27 |
28 | // Validator implements admission.CustomValidator.
29 | var _ admission.CustomValidator = &Validator{}
30 |
31 | // ValidateCreate implements admission.CustomValidator.
32 | func (s *Validator) ValidateCreate(_ context.Context, _ runtime.Object) (admission.Warnings, error) {
33 | return nil, nil
34 | }
35 |
36 | // ValidateDelete implements admission.CustomValidator.
37 | func (s *Validator) ValidateDelete(_ context.Context, _ runtime.Object) (admission.Warnings, error) {
38 | return nil, nil
39 | }
40 |
41 | // ValidateUpdate implements admission.CustomValidator.
42 | func (s *Validator) ValidateUpdate(_ context.Context, _ runtime.Object, _ runtime.Object) (admission.Warnings, error) {
43 | return nil, nil
44 | }
45 |
--------------------------------------------------------------------------------
/internal/scheduler/yunikorn/resourceusage/java.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2024 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package resourceusage
18 |
19 | import (
20 | "fmt"
21 | "regexp"
22 | "strconv"
23 | "strings"
24 | )
25 |
26 | var (
27 | javaStringSuffixes = map[string]int64{
28 | "b": 1,
29 | "kb": 1 << 10,
30 | "k": 1 << 10,
31 | "mb": 1 << 20,
32 | "m": 1 << 20,
33 | "gb": 1 << 30,
34 | "g": 1 << 30,
35 | "tb": 1 << 40,
36 | "t": 1 << 40,
37 | "pb": 1 << 50,
38 | "p": 1 << 50,
39 | }
40 |
41 | javaStringPattern = regexp.MustCompile(`^([0-9]+)([a-z]+)?$`)
42 | )
43 |
44 | func byteStringAsBytes(byteString string) (int64, error) {
45 | matches := javaStringPattern.FindStringSubmatch(strings.ToLower(byteString))
46 | if matches != nil {
47 | value, err := strconv.ParseInt(matches[1], 10, 64)
48 | if err != nil {
49 | return 0, err
50 | }
51 | if multiplier, present := javaStringSuffixes[matches[2]]; present {
52 | return value * multiplier, nil
53 | }
54 | }
55 | return 0, fmt.Errorf("unable to parse byte string: %s", byteString)
56 | }
57 |
--------------------------------------------------------------------------------
/pkg/common/constants.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2024 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package common
18 |
19 | const (
20 | ErrorCodePodAlreadyExists = "code=409"
21 | )
22 |
23 | const (
24 | SparkApplicationFinalizerName = "sparkoperator.k8s.io/finalizer"
25 | ScheduledSparkApplicationFinalizerName = "sparkoperator.k8s.io/finalizer"
26 | )
27 |
28 | const (
29 | RSAKeySize = 2048
30 | )
31 |
32 | const (
33 | // Internal Cert
34 | CAKeyPem = "ca-key.pem"
35 | CACertPem = "ca-cert.pem"
36 | ServerKeyPem = "server-key.pem"
37 | ServerCertPem = "server-cert.pem"
38 |
39 | // Cert Manager
40 | CACert = "ca.crt"
41 | TLSCert = "tls.crt"
42 | TLSKey = "tls.key"
43 | )
44 |
45 | // Kubernetes volume types.
46 | const (
47 | VolumeTypeEmptyDir = "emptyDir"
48 | VolumeTypeHostPath = "hostPath"
49 | VolumeTypeNFS = "nfs"
50 | VolumeTypePersistentVolumeClaim = "persistentVolumeClaim"
51 | )
52 |
53 | const (
54 | // Epsilon is a small number used to compare 64 bit floating point numbers.
55 | Epsilon = 1e-9
56 | )
57 |
--------------------------------------------------------------------------------
/pkg/client/clientset/versioned/typed/api/v1beta2/fake/fake_api_client.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2025 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 | // Code generated by client-gen. DO NOT EDIT.
17 |
18 | package fake
19 |
20 | import (
21 | v1beta2 "github.com/kubeflow/spark-operator/v2/pkg/client/clientset/versioned/typed/api/v1beta2"
22 | rest "k8s.io/client-go/rest"
23 | testing "k8s.io/client-go/testing"
24 | )
25 |
26 | type FakeSparkoperatorV1beta2 struct {
27 | *testing.Fake
28 | }
29 |
30 | func (c *FakeSparkoperatorV1beta2) ScheduledSparkApplications(namespace string) v1beta2.ScheduledSparkApplicationInterface {
31 | return newFakeScheduledSparkApplications(c, namespace)
32 | }
33 |
34 | func (c *FakeSparkoperatorV1beta2) SparkApplications(namespace string) v1beta2.SparkApplicationInterface {
35 | return newFakeSparkApplications(c, namespace)
36 | }
37 |
38 | // RESTClient returns a RESTClient that is used to communicate
39 | // with API server by this client implementation.
40 | func (c *FakeSparkoperatorV1beta2) RESTClient() rest.Interface {
41 | var ret *rest.RESTClient
42 | return ret
43 | }
44 |
--------------------------------------------------------------------------------
/pkg/client/informers/externalversions/internalinterfaces/factory_interfaces.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2025 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 | // Code generated by informer-gen. DO NOT EDIT.
17 |
18 | package internalinterfaces
19 |
20 | import (
21 | time "time"
22 |
23 | versioned "github.com/kubeflow/spark-operator/v2/pkg/client/clientset/versioned"
24 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
25 | runtime "k8s.io/apimachinery/pkg/runtime"
26 | cache "k8s.io/client-go/tools/cache"
27 | )
28 |
29 | // NewInformerFunc takes versioned.Interface and time.Duration to return a SharedIndexInformer.
30 | type NewInformerFunc func(versioned.Interface, time.Duration) cache.SharedIndexInformer
31 |
32 | // SharedInformerFactory a small interface to allow for adding an informer without an import cycle
33 | type SharedInformerFactory interface {
34 | Start(stopCh <-chan struct{})
35 | InformerFor(obj runtime.Object, newFunc NewInformerFunc) cache.SharedIndexInformer
36 | }
37 |
38 | // TweakListOptionsFunc is a function that transforms a v1.ListOptions.
39 | type TweakListOptionsFunc func(*v1.ListOptions)
40 |
--------------------------------------------------------------------------------
/charts/spark-operator-chart/templates/spark/_helpers.tpl:
--------------------------------------------------------------------------------
1 | {{/*
2 | Copyright 2024 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */}}
16 |
17 | {{/*
18 | Create the name of spark component
19 | */}}
20 | {{- define "spark-operator.spark.name" -}}
21 | {{- include "spark-operator.fullname" . }}-spark
22 | {{- end -}}
23 |
24 | {{/*
25 | Create the name of the service account to be used by spark applications
26 | */}}
27 | {{- define "spark-operator.spark.serviceAccountName" -}}
28 | {{- if .Values.spark.serviceAccount.create -}}
29 | {{- .Values.spark.serviceAccount.name | default (include "spark-operator.spark.name" .) -}}
30 | {{- else -}}
31 | {{- .Values.spark.serviceAccount.name | default "default" -}}
32 | {{- end -}}
33 | {{- end -}}
34 |
35 | {{/*
36 | Create the name of the role to be used by spark service account
37 | */}}
38 | {{- define "spark-operator.spark.roleName" -}}
39 | {{- include "spark-operator.spark.serviceAccountName" . }}
40 | {{- end -}}
41 |
42 | {{/*
43 | Create the name of the role binding to be used by spark service account
44 | */}}
45 | {{- define "spark-operator.spark.roleBindingName" -}}
46 | {{- include "spark-operator.spark.serviceAccountName" . }}
47 | {{- end -}}
48 |
--------------------------------------------------------------------------------
/examples/spark-pi-python.yaml:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright 2018 Google LLC
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # https://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | apiVersion: sparkoperator.k8s.io/v1beta2
17 | kind: SparkApplication
18 | metadata:
19 | name: spark-pi-python
20 | namespace: default
21 | spec:
22 | type: Python
23 | pythonVersion: "3"
24 | mode: cluster
25 | image: docker.io/library/spark:4.0.0
26 | imagePullPolicy: IfNotPresent
27 | mainApplicationFile: local:///opt/spark/examples/src/main/python/pi.py
28 | sparkVersion: 4.0.0
29 | driver:
30 | cores: 1
31 | memory: 512m
32 | serviceAccount: spark-operator-spark
33 | securityContext:
34 | capabilities:
35 | drop:
36 | - ALL
37 | runAsGroup: 185
38 | runAsUser: 185
39 | runAsNonRoot: true
40 | allowPrivilegeEscalation: false
41 | seccompProfile:
42 | type: RuntimeDefault
43 | executor:
44 | instances: 1
45 | cores: 1
46 | memory: 512m
47 | securityContext:
48 | capabilities:
49 | drop:
50 | - ALL
51 | runAsGroup: 185
52 | runAsUser: 185
53 | runAsNonRoot: true
54 | allowPrivilegeEscalation: false
55 | seccompProfile:
56 | type: RuntimeDefault
57 |
--------------------------------------------------------------------------------
/pkg/scheme/scheme.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2025 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 | // Code generated by lister-gen. DO NOT EDIT.
17 |
18 | package scheme
19 |
20 | import (
21 | "k8s.io/apimachinery/pkg/runtime"
22 | utilruntime "k8s.io/apimachinery/pkg/util/runtime"
23 | clientgoscheme "k8s.io/client-go/kubernetes/scheme"
24 | schedulingv1alpha1 "sigs.k8s.io/scheduler-plugins/apis/scheduling/v1alpha1"
25 |
26 | "github.com/kubeflow/spark-operator/v2/api/v1alpha1"
27 | "github.com/kubeflow/spark-operator/v2/api/v1beta2"
28 | )
29 |
30 | // Scheme holds the aggregated Kubernetes's schemes and extended schemes.
31 | var ControllerScheme = runtime.NewScheme()
32 | var WebhookScheme = runtime.NewScheme()
33 |
34 | func init() {
35 | utilruntime.Must(clientgoscheme.AddToScheme(ControllerScheme))
36 | utilruntime.Must(schedulingv1alpha1.AddToScheme(ControllerScheme))
37 |
38 | utilruntime.Must(v1alpha1.AddToScheme(ControllerScheme))
39 | utilruntime.Must(v1beta2.AddToScheme(ControllerScheme))
40 | // +kubebuilder:scaffold:scheme
41 |
42 | utilruntime.Must(clientgoscheme.AddToScheme(WebhookScheme))
43 | utilruntime.Must(v1beta2.AddToScheme(WebhookScheme))
44 | // +kubebuilder:scaffold:scheme
45 | }
46 |
--------------------------------------------------------------------------------
/internal/scheduler/yunikorn/resourceusage/java_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2024 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package resourceusage
18 |
19 | import (
20 | "testing"
21 |
22 | "github.com/stretchr/testify/assert"
23 | )
24 |
25 | func TestByteStringAsMb(t *testing.T) {
26 | testCases := []struct {
27 | input string
28 | expected int
29 | }{
30 | {"1k", 1024},
31 | {"1m", 1024 * 1024},
32 | {"1g", 1024 * 1024 * 1024},
33 | {"1t", 1024 * 1024 * 1024 * 1024},
34 | {"1p", 1024 * 1024 * 1024 * 1024 * 1024},
35 | }
36 |
37 | for _, tc := range testCases {
38 | t.Run(tc.input, func(t *testing.T) {
39 | actual, err := byteStringAsBytes(tc.input)
40 | assert.Nil(t, err)
41 | assert.Equal(t, int64(tc.expected), actual)
42 | })
43 | }
44 | }
45 |
46 | func TestByteStringAsMbInvalid(t *testing.T) {
47 | invalidInputs := []string{
48 | "0.064",
49 | "0.064m",
50 | "500ub",
51 | "This breaks 600b",
52 | "This breaks 600",
53 | "600gb This breaks",
54 | "This 123mb breaks",
55 | }
56 |
57 | for _, input := range invalidInputs {
58 | t.Run(input, func(t *testing.T) {
59 | _, err := byteStringAsBytes(input)
60 | assert.NotNil(t, err)
61 | })
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/spark-docker/README.md:
--------------------------------------------------------------------------------
1 | This directory contains a Dockerfile for a variant of the Spark image with built-in support for accessing Google Cloud Storage using the Hadoop FileSystem API and exposing Spark metrics (e.g., driver and executor metrics) to Prometheus in the Prometheus data model. The `conf` directory contains `metrics.properties` that configures the Spark metric system and `prometheus.yaml` that is the configuration file to be used with the [Prometheus JMX exporter](https://github.com/prometheus/jmx_exporter).
2 |
3 | By default both configuration files under `conf` are put under `/prometheus` in the image. To make Spark be aware of `metrics.properties`, please set the Spark configuration property `spark.metrics.conf=/prometheus/metrics.properties`. The Prometheus JMX exporter runs as a Java agent to scrape metrics exposed through JMX. To configure the Java agent for the exporter, add the following to the Spark configuration property `spark.driver.extraJavaOptions` for the driver (or `spark.executor.extraJavaOptions` for executors):
4 |
5 | ```
6 | -javaagent:/prometheus/jmx_prometheus_javaagent-0.11.0.jar=8090:/prometheus/prometheus.yaml
7 | ```
8 |
9 | The JMX exporter exposes a HTTP server serving the metrics on the specified port (`8090` in the example above). To make Prometheus discover and scrape the metrics, please add the following annotations to the Spark driver or executors. Make sure the value of `prometheus.io/port` is the same as the port specified in the Java agent configuration.
10 |
11 | ```
12 | "prometheus.io/scrape": "true"
13 | "prometheus.io/port": "8090"
14 | "prometheus.io/path": "/metrics"
15 | ```
16 |
17 | A complete example `SparkApplication` specification with metric exporting to Prometheus enabled can be found [here](../examples/spark-pi-prometheus.yaml).
--------------------------------------------------------------------------------
/pkg/certificate/util_test.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2024 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package certificate_test
18 |
19 | import (
20 | "crypto/rand"
21 | "crypto/rsa"
22 | "crypto/x509"
23 | "testing"
24 | "time"
25 |
26 | "k8s.io/client-go/util/cert"
27 |
28 | "github.com/kubeflow/spark-operator/v2/pkg/certificate"
29 | "github.com/kubeflow/spark-operator/v2/pkg/common"
30 | )
31 |
32 | func TestNewPrivateKey(t *testing.T) {
33 | _, err := certificate.NewPrivateKey()
34 | if err != nil {
35 | t.Errorf("failed to generate private key: %v", err)
36 | }
37 | }
38 |
39 | func TestNewSignedServerCert(t *testing.T) {
40 | cfg := cert.Config{
41 | CommonName: "test-server",
42 | Organization: []string{"test-org"},
43 | NotBefore: time.Now(),
44 | }
45 |
46 | caKey, _ := rsa.GenerateKey(rand.Reader, common.RSAKeySize)
47 | caCert := &x509.Certificate{}
48 | serverKey, _ := rsa.GenerateKey(rand.Reader, common.RSAKeySize)
49 |
50 | serverCert, err := certificate.NewSignedServerCert(cfg, caKey, caCert, serverKey)
51 | if err != nil {
52 | t.Errorf("failed to generate signed server certificate: %v", err)
53 | }
54 |
55 | if serverCert == nil {
56 | t.Error("server certificate is nil")
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/charts/spark-operator-chart/tests/hook/cluster_role_test.yaml:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright 2025 The Kubeflow authors.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # https://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 | #
16 |
17 | suite: Test hook ClusterRole
18 |
19 | templates:
20 | - hook/cluster_role.yaml
21 |
22 | release:
23 | name: spark-operator
24 | namespace: spark-operator
25 |
26 | tests:
27 | - it: Should not create hook ClusterRole if `hook.upgradeCrd` is false
28 | set:
29 | hook:
30 | upgradeCrd: false
31 | asserts:
32 | - hasDocuments:
33 | count: 0
34 |
35 | - it: Should create hook ClusterRole if `hook.upgradeCrd` is true
36 | set:
37 | hook:
38 | upgradeCrd: true
39 | asserts:
40 | - containsDocument:
41 | apiVersion: rbac.authorization.k8s.io/v1
42 | kind: ClusterRole
43 | name: spark-operator-hook
44 | - contains:
45 | path: rules
46 | content:
47 | apiGroups:
48 | - apiextensions.k8s.io
49 | resources:
50 | - customresourcedefinitions
51 | resourceNames:
52 | - sparkapplications.sparkoperator.k8s.io
53 | - sparkconnects.sparkoperator.k8s.io
54 | - scheduledsparkapplications.sparkoperator.k8s.io
55 | verbs:
56 | - get
57 | - patch
58 | - create
59 |
--------------------------------------------------------------------------------
/internal/controller/mutatingwebhookconfiguration/event_filter.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2024 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package mutatingwebhookconfiguration
18 |
19 | import (
20 | "sigs.k8s.io/controller-runtime/pkg/event"
21 | "sigs.k8s.io/controller-runtime/pkg/predicate"
22 | )
23 |
24 | // EventFilter filters events for MutatingWebhookConfiguration.
25 | type EventFilter struct {
26 | name string
27 | }
28 |
29 | func NewEventFilter(name string) *EventFilter {
30 | return &EventFilter{
31 | name: name,
32 | }
33 | }
34 |
35 | // MutatingWebhookConfigurationEventFilter implements predicate.Predicate.
36 | var _ predicate.Predicate = &EventFilter{}
37 |
38 | // Create implements predicate.Predicate.
39 | func (f *EventFilter) Create(e event.CreateEvent) bool {
40 | return e.Object.GetName() == f.name
41 | }
42 |
43 | // Update implements predicate.Predicate.
44 | func (f *EventFilter) Update(e event.UpdateEvent) bool {
45 | return e.ObjectOld.GetName() == f.name
46 | }
47 |
48 | // Delete implements predicate.Predicate.
49 | func (f *EventFilter) Delete(event.DeleteEvent) bool {
50 | return false
51 | }
52 |
53 | // Generic implements predicate.Predicate.
54 | func (f *EventFilter) Generic(event.GenericEvent) bool {
55 | return false
56 | }
57 |
--------------------------------------------------------------------------------
/examples/spark-pi-ttl.yaml:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright 2024 The Kubeflow authors.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # https://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | apiVersion: sparkoperator.k8s.io/v1beta2
17 | kind: SparkApplication
18 | metadata:
19 | name: spark-pi-ttl
20 | namespace: default
21 | spec:
22 | type: Scala
23 | mode: cluster
24 | image: docker.io/library/spark:4.0.0
25 | imagePullPolicy: IfNotPresent
26 | mainClass: org.apache.spark.examples.SparkPi
27 | mainApplicationFile: local:///opt/spark/examples/jars/spark-examples.jar
28 | sparkVersion: 4.0.0
29 | timeToLiveSeconds: 30
30 | driver:
31 | cores: 1
32 | memory: 512m
33 | serviceAccount: spark-operator-spark
34 | securityContext:
35 | capabilities:
36 | drop:
37 | - ALL
38 | runAsGroup: 185
39 | runAsUser: 185
40 | runAsNonRoot: true
41 | allowPrivilegeEscalation: false
42 | seccompProfile:
43 | type: RuntimeDefault
44 | executor:
45 | instances: 1
46 | cores: 1
47 | memory: 512m
48 | securityContext:
49 | capabilities:
50 | drop:
51 | - ALL
52 | runAsGroup: 185
53 | runAsUser: 185
54 | runAsNonRoot: true
55 | allowPrivilegeEscalation: false
56 | seccompProfile:
57 | type: RuntimeDefault
58 |
--------------------------------------------------------------------------------
/examples/spark-pi-volcano.yaml:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright 2024 The Kubeflow authors.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | apiVersion: sparkoperator.k8s.io/v1beta2
17 | kind: SparkApplication
18 | metadata:
19 | name: spark-pi-volcano
20 | namespace: default
21 | spec:
22 | type: Scala
23 | mode: cluster
24 | image: docker.io/library/spark:4.0.0
25 | imagePullPolicy: IfNotPresent
26 | mainClass: org.apache.spark.examples.SparkPi
27 | mainApplicationFile: local:///opt/spark/examples/jars/spark-examples.jar
28 | sparkVersion: 4.0.0
29 | driver:
30 | cores: 1
31 | memory: 512m
32 | serviceAccount: spark-operator-spark
33 | securityContext:
34 | capabilities:
35 | drop:
36 | - ALL
37 | runAsGroup: 185
38 | runAsUser: 185
39 | runAsNonRoot: true
40 | allowPrivilegeEscalation: false
41 | seccompProfile:
42 | type: RuntimeDefault
43 | executor:
44 | instances: 2
45 | cores: 1
46 | memory: 512m
47 | securityContext:
48 | capabilities:
49 | drop:
50 | - ALL
51 | runAsGroup: 185
52 | runAsUser: 185
53 | runAsNonRoot: true
54 | allowPrivilegeEscalation: false
55 | seccompProfile:
56 | type: RuntimeDefault
57 | batchScheduler: volcano
58 |
--------------------------------------------------------------------------------
/internal/controller/validatingwebhookconfiguration/event_filter.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2024 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package validatingwebhookconfiguration
18 |
19 | import (
20 | "sigs.k8s.io/controller-runtime/pkg/event"
21 | "sigs.k8s.io/controller-runtime/pkg/predicate"
22 | )
23 |
24 | // EventFilter filters events for the ValidatingWebhookConfiguration.
25 | type EventFilter struct {
26 | name string
27 | }
28 |
29 | func NewEventFilter(name string) *EventFilter {
30 | return &EventFilter{
31 | name: name,
32 | }
33 | }
34 |
35 | // ValidatingWebhookConfigurationEventFilter implements predicate.Predicate interface.
36 | var _ predicate.Predicate = &EventFilter{}
37 |
38 | // Create implements predicate.Predicate.
39 | func (f *EventFilter) Create(e event.CreateEvent) bool {
40 | return e.Object.GetName() == f.name
41 | }
42 |
43 | // Update implements predicate.Predicate.
44 | func (f *EventFilter) Update(e event.UpdateEvent) bool {
45 | return e.ObjectOld.GetName() == f.name
46 | }
47 |
48 | // Delete implements predicate.Predicate.
49 | func (f *EventFilter) Delete(event.DeleteEvent) bool {
50 | return false
51 | }
52 |
53 | // Generic implements predicate.Predicate.
54 | func (f *EventFilter) Generic(event.GenericEvent) bool {
55 | return false
56 | }
57 |
--------------------------------------------------------------------------------
/examples/spark-pi-kube-scheduler.yaml:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright 2024 The Kubeflow authors.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | apiVersion: sparkoperator.k8s.io/v1beta2
17 | kind: SparkApplication
18 | metadata:
19 | name: spark-pi-kube-scheduler
20 | namespace: default
21 | spec:
22 | type: Scala
23 | mode: cluster
24 | image: docker.io/library/spark:4.0.0
25 | imagePullPolicy: IfNotPresent
26 | mainClass: org.apache.spark.examples.SparkPi
27 | mainApplicationFile: local:///opt/spark/examples/jars/spark-examples.jar
28 | sparkVersion: 4.0.0
29 | driver:
30 | cores: 1
31 | memory: 512m
32 | serviceAccount: spark-operator-spark
33 | securityContext:
34 | capabilities:
35 | drop:
36 | - ALL
37 | runAsGroup: 185
38 | runAsUser: 185
39 | runAsNonRoot: true
40 | allowPrivilegeEscalation: false
41 | seccompProfile:
42 | type: RuntimeDefault
43 | executor:
44 | instances: 2
45 | cores: 1
46 | memory: 512m
47 | securityContext:
48 | capabilities:
49 | drop:
50 | - ALL
51 | runAsGroup: 185
52 | runAsUser: 185
53 | runAsNonRoot: true
54 | allowPrivilegeEscalation: false
55 | seccompProfile:
56 | type: RuntimeDefault
57 | batchScheduler: kube-scheduler
58 |
--------------------------------------------------------------------------------
/pkg/client/informers/externalversions/api/interface.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2025 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 | // Code generated by informer-gen. DO NOT EDIT.
17 |
18 | package api
19 |
20 | import (
21 | v1beta2 "github.com/kubeflow/spark-operator/v2/pkg/client/informers/externalversions/api/v1beta2"
22 | internalinterfaces "github.com/kubeflow/spark-operator/v2/pkg/client/informers/externalversions/internalinterfaces"
23 | )
24 |
25 | // Interface provides access to each of this group's versions.
26 | type Interface interface {
27 | // V1beta2 provides access to shared informers for resources in V1beta2.
28 | V1beta2() v1beta2.Interface
29 | }
30 |
31 | type group struct {
32 | factory internalinterfaces.SharedInformerFactory
33 | namespace string
34 | tweakListOptions internalinterfaces.TweakListOptionsFunc
35 | }
36 |
37 | // New returns a new Interface.
38 | func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface {
39 | return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
40 | }
41 |
42 | // V1beta2 returns a new v1beta2.Interface.
43 | func (g *group) V1beta2() v1beta2.Interface {
44 | return v1beta2.New(g.factory, g.namespace, g.tweakListOptions)
45 | }
46 |
--------------------------------------------------------------------------------
/charts/spark-operator-chart/tests/hook/cluster_role_binding_test.yaml:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright 2025 The Kubeflow authors.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # https://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 | #
16 |
17 | suite: Test hook ClusterRole
18 |
19 | templates:
20 | - hook/cluster_role_binding.yaml
21 |
22 | release:
23 | name: spark-operator
24 | namespace: spark-operator
25 |
26 | tests:
27 | - it: Should not create hook ClusterRoleBinding if `hook.upgradeCrd` is false
28 | set:
29 | hook:
30 | upgradeCrd: false
31 | asserts:
32 | - hasDocuments:
33 | count: 0
34 |
35 | - it: Should create hook ClusterRoleBinding if `hook.upgradeCrd` is true
36 | set:
37 | hook:
38 | upgradeCrd: true
39 | asserts:
40 | - containsDocument:
41 | apiVersion: rbac.authorization.k8s.io/v1
42 | kind: ClusterRoleBinding
43 | name: spark-operator-hook
44 |
45 | - it: Should bind hook ClusterRole to hook ServiceAccount
46 | set:
47 | hook:
48 | upgradeCrd: true
49 | asserts:
50 | - equal:
51 | path: roleRef
52 | value:
53 | apiGroup: rbac.authorization.k8s.io
54 | kind: ClusterRole
55 | name: spark-operator-hook
56 | - contains:
57 | path: subjects
58 | content:
59 | kind: ServiceAccount
60 | name: spark-operator-hook
61 | namespace: spark-operator
62 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright 2017 Google LLC
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # https://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 | #
16 |
17 | ARG SPARK_IMAGE=docker.io/library/spark:4.0.0
18 |
19 | FROM golang:1.24.1 AS builder
20 |
21 | WORKDIR /workspace
22 |
23 | RUN --mount=type=cache,target=/go/pkg/mod/ \
24 | --mount=type=bind,source=go.mod,target=go.mod \
25 | --mount=type=bind,source=go.sum,target=go.sum \
26 | go mod download
27 |
28 | COPY . .
29 |
30 | ENV GOCACHE=/root/.cache/go-build
31 |
32 | ARG TARGETARCH
33 |
34 | RUN --mount=type=cache,target=/go/pkg/mod/ \
35 | --mount=type=cache,target="/root/.cache/go-build" \
36 | CGO_ENABLED=0 GOOS=linux GOARCH=${TARGETARCH} GO111MODULE=on make build-operator
37 |
38 | FROM ${SPARK_IMAGE}
39 |
40 | ARG SPARK_UID=185
41 |
42 | ARG SPARK_GID=185
43 |
44 | USER root
45 |
46 | RUN apt-get update \
47 | && apt-get install -y tini \
48 | && rm -rf /var/lib/apt/lists/*
49 |
50 | RUN mkdir -p /etc/k8s-webhook-server/serving-certs /home/spark && \
51 | chmod -R g+rw /etc/k8s-webhook-server/serving-certs && \
52 | chown -R spark /etc/k8s-webhook-server/serving-certs /home/spark
53 |
54 | USER ${SPARK_UID}:${SPARK_GID}
55 |
56 | COPY --from=builder /workspace/bin/spark-operator /usr/bin/spark-operator
57 |
58 | COPY entrypoint.sh /usr/bin/
59 |
60 | ENTRYPOINT ["/usr/bin/entrypoint.sh"]
61 |
--------------------------------------------------------------------------------
/examples/spark-pi-yunikorn.yaml:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright 2024 The Kubeflow authors.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | apiVersion: sparkoperator.k8s.io/v1beta2
17 | kind: SparkApplication
18 | metadata:
19 | name: spark-pi-yunikorn
20 | namespace: default
21 | spec:
22 | type: Scala
23 | mode: cluster
24 | image: docker.io/library/spark:4.0.0
25 | imagePullPolicy: IfNotPresent
26 | mainClass: org.apache.spark.examples.SparkPi
27 | mainApplicationFile: local:///opt/spark/examples/jars/spark-examples.jar
28 | sparkVersion: 4.0.0
29 | driver:
30 | cores: 1
31 | memory: 512m
32 | serviceAccount: spark-operator-spark
33 | securityContext:
34 | capabilities:
35 | drop:
36 | - ALL
37 | runAsGroup: 185
38 | runAsUser: 185
39 | runAsNonRoot: true
40 | allowPrivilegeEscalation: false
41 | seccompProfile:
42 | type: RuntimeDefault
43 | executor:
44 | instances: 2
45 | cores: 1
46 | memory: 512m
47 | securityContext:
48 | capabilities:
49 | drop:
50 | - ALL
51 | runAsGroup: 185
52 | runAsUser: 185
53 | runAsNonRoot: true
54 | allowPrivilegeEscalation: false
55 | seccompProfile:
56 | type: RuntimeDefault
57 | batchScheduler: yunikorn
58 | batchSchedulerOptions:
59 | queue: root.default
60 |
--------------------------------------------------------------------------------
/examples/spark-pi.yaml:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright 2017 Google LLC
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # https://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | apiVersion: sparkoperator.k8s.io/v1beta2
17 | kind: SparkApplication
18 | metadata:
19 | name: spark-pi
20 | namespace: default
21 | spec:
22 | type: Scala
23 | mode: cluster
24 | image: docker.io/library/spark:4.0.0
25 | imagePullPolicy: IfNotPresent
26 | mainClass: org.apache.spark.examples.SparkPi
27 | mainApplicationFile: local:///opt/spark/examples/jars/spark-examples.jar
28 | arguments:
29 | - "5000"
30 | sparkVersion: 4.0.0
31 | driver:
32 | labels:
33 | version: 4.0.0
34 | cores: 1
35 | memory: 512m
36 | serviceAccount: spark-operator-spark
37 | securityContext:
38 | capabilities:
39 | drop:
40 | - ALL
41 | runAsGroup: 185
42 | runAsUser: 185
43 | runAsNonRoot: true
44 | allowPrivilegeEscalation: false
45 | seccompProfile:
46 | type: RuntimeDefault
47 | executor:
48 | labels:
49 | version: 4.0.0
50 | instances: 1
51 | cores: 1
52 | memory: 512m
53 | securityContext:
54 | capabilities:
55 | drop:
56 | - ALL
57 | runAsGroup: 185
58 | runAsUser: 185
59 | runAsNonRoot: true
60 | allowPrivilegeEscalation: false
61 | seccompProfile:
62 | type: RuntimeDefault
63 |
--------------------------------------------------------------------------------
/charts/spark-operator-chart/templates/prometheus/podmonitor.yaml:
--------------------------------------------------------------------------------
1 | {{/*
2 | Copyright 2024 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */}}
16 |
17 | {{- if .Values.prometheus.podMonitor.create -}}
18 | {{- if not .Values.prometheus.metrics.enable }}
19 | {{- fail "`metrics.enable` must be set to true when `podMonitor.create` is true." }}
20 | {{- end }}
21 | {{- if not (.Capabilities.APIVersions.Has "monitoring.coreos.com/v1/PodMonitor") }}
22 | {{- fail "The cluster does not support the required API version `monitoring.coreos.com/v1` for `PodMonitor`." }}
23 | {{- end }}
24 | apiVersion: monitoring.coreos.com/v1
25 | kind: PodMonitor
26 | metadata:
27 | name: {{ include "spark-operator.prometheus.podMonitorName" . }}
28 | {{- with .Values.prometheus.podMonitor.labels }}
29 | labels:
30 | {{- toYaml . | nindent 4 }}
31 | {{- end }}
32 | spec:
33 | podMetricsEndpoints:
34 | - interval: {{ .Values.prometheus.podMonitor.podMetricsEndpoint.interval }}
35 | port: {{ .Values.prometheus.metrics.portName | quote }}
36 | scheme: {{ .Values.prometheus.podMonitor.podMetricsEndpoint.scheme }}
37 | jobLabel: {{ .Values.prometheus.podMonitor.jobLabel }}
38 | namespaceSelector:
39 | matchNames:
40 | - {{ .Release.Namespace }}
41 | selector:
42 | matchLabels:
43 | {{- include "spark-operator.selectorLabels" . | nindent 6 }}
44 | {{- end }}
45 |
--------------------------------------------------------------------------------
/examples/spark-pi-custom-resource.yaml:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright 2017 Google LLC
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # https://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | apiVersion: sparkoperator.k8s.io/v1beta2
17 | kind: SparkApplication
18 | metadata:
19 | name: spark-pi-custom-resource
20 | namespace: default
21 | spec:
22 | type: Scala
23 | mode: cluster
24 | image: docker.io/library/spark:4.0.0
25 | imagePullPolicy: IfNotPresent
26 | mainClass: org.apache.spark.examples.SparkPi
27 | mainApplicationFile: local:///opt/spark/examples/jars/spark-examples.jar
28 | sparkVersion: 4.0.0
29 | restartPolicy:
30 | type: Never
31 | driver:
32 | coreRequest: "0.5"
33 | coreLimit: 800m
34 | memory: 512m
35 | serviceAccount: spark-operator-spark
36 | securityContext:
37 | capabilities:
38 | drop:
39 | - ALL
40 | runAsGroup: 185
41 | runAsUser: 185
42 | runAsNonRoot: true
43 | allowPrivilegeEscalation: false
44 | seccompProfile:
45 | type: RuntimeDefault
46 | executor:
47 | instances: 1
48 | coreRequest: "1200m"
49 | coreLimit: 1500m
50 | memory: 512m
51 | securityContext:
52 | capabilities:
53 | drop:
54 | - ALL
55 | runAsGroup: 185
56 | runAsUser: 185
57 | runAsNonRoot: true
58 | allowPrivilegeEscalation: false
59 | seccompProfile:
60 | type: RuntimeDefault
61 |
--------------------------------------------------------------------------------
/pkg/common/metrics.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2024 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package common
18 |
19 | // Spark application metric names.
20 | const (
21 | MetricSparkApplicationCount = "spark_application_count"
22 |
23 | MetricSparkApplicationSubmitCount = "spark_application_submit_count"
24 |
25 | MetricSparkApplicationFailedSubmissionCount = "spark_application_failed_submission_count"
26 |
27 | MetricSparkApplicationRunningCount = "spark_application_running_count"
28 |
29 | MetricSparkApplicationSuccessCount = "spark_application_success_count"
30 |
31 | MetricSparkApplicationFailureCount = "spark_application_failure_count"
32 |
33 | MetricSparkApplicationSuccessExecutionTimeSeconds = "spark_application_success_execution_time_seconds"
34 |
35 | MetricSparkApplicationFailureExecutionTimeSeconds = "spark_application_failure_execution_time_seconds"
36 |
37 | MetricSparkApplicationStartLatencySeconds = "spark_application_start_latency_seconds"
38 |
39 | MetricSparkApplicationStartLatencySecondsHistogram = "spark_application_start_latency_seconds_histogram"
40 | )
41 |
42 | // Spark executor metric names.
43 | const (
44 | MetricSparkExecutorRunningCount = "spark_executor_running_count"
45 |
46 | MetricSparkExecutorSuccessCount = "spark_executor_success_count"
47 |
48 | MetricSparkExecutorFailureCount = "spark_executor_failure_count"
49 | )
50 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
7 |
8 | ## Purpose of this PR
9 |
10 |
11 |
12 | **Proposed changes:**
13 |
14 | -
15 | -
16 | -
17 |
18 | ## Change Category
19 |
20 |
21 |
22 | - [ ] Bugfix (non-breaking change which fixes an issue)
23 | - [ ] Feature (non-breaking change which adds functionality)
24 | - [ ] Breaking change (fix or feature that could affect existing functionality)
25 | - [ ] Documentation update
26 |
27 | ### Rationale
28 |
29 |
30 |
31 | ## Checklist
32 |
33 |
34 |
35 | - [ ] I have conducted a self-review of my own code.
36 | - [ ] I have updated documentation accordingly.
37 | - [ ] I have added tests that prove my changes are effective or that my feature works.
38 | - [ ] Existing unit tests pass locally with my changes.
39 |
40 | ### Additional Notes
41 |
42 |
43 |
--------------------------------------------------------------------------------
/config/rbac/role.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: rbac.authorization.k8s.io/v1
3 | kind: ClusterRole
4 | metadata:
5 | name: spark-operator-controller
6 | rules:
7 | - resources:
8 | - configmaps
9 | verbs:
10 | - create
11 | - delete
12 | - get
13 | - list
14 | - patch
15 | - update
16 | - resources:
17 | - events
18 | verbs:
19 | - create
20 | - patch
21 | - update
22 | - resources:
23 | - nodes
24 | verbs:
25 | - get
26 | - resources:
27 | - pods
28 | verbs:
29 | - create
30 | - delete
31 | - deletecollection
32 | - get
33 | - list
34 | - patch
35 | - update
36 | - watch
37 | - resources:
38 | - resourcequotas
39 | verbs:
40 | - get
41 | - list
42 | - watch
43 | - resources:
44 | - services
45 | verbs:
46 | - create
47 | - delete
48 | - get
49 | - list
50 | - update
51 | - watch
52 | - apiGroups:
53 | - apiextensions.k8s.io
54 | resources:
55 | - customresourcedefinitions
56 | verbs:
57 | - get
58 | - apiGroups:
59 | - extensions
60 | - networking.k8s.io
61 | resources:
62 | - ingresses
63 | verbs:
64 | - create
65 | - delete
66 | - get
67 | - list
68 | - update
69 | - watch
70 | - apiGroups:
71 | - sparkoperator.k8s.io
72 | resources:
73 | - scheduledsparkapplications
74 | - sparkapplications
75 | - sparkconnects
76 | verbs:
77 | - create
78 | - delete
79 | - get
80 | - list
81 | - patch
82 | - update
83 | - watch
84 | - apiGroups:
85 | - sparkoperator.k8s.io
86 | resources:
87 | - scheduledsparkapplications/finalizers
88 | - sparkapplications/finalizers
89 | verbs:
90 | - update
91 | - apiGroups:
92 | - sparkoperator.k8s.io
93 | resources:
94 | - scheduledsparkapplications/status
95 | - sparkapplications/status
96 | - sparkconnects/status
97 | verbs:
98 | - get
99 | - patch
100 | - update
101 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.yaml:
--------------------------------------------------------------------------------
1 | name: Bug Report
2 | description: Tell us about a problem you are experiencing with the Spark operator.
3 | labels:
4 | - kind/bug
5 | - lifecycle/needs-triage
6 | body:
7 | - type: markdown
8 | attributes:
9 | value: |
10 | Thanks for taking the time to fill out this Spark operator bug report!
11 | - type: textarea
12 | id: problem
13 | attributes:
14 | label: What happened?
15 | description: |
16 | Please provide a clear and concise description of the issue you are encountering, and a reproduction of your configuration.
17 | If your request is for a new feature, please use the `Feature request` template.
18 | value: |
19 | - [ ] ✋ I have searched the open/closed issues and my issue is not listed.
20 | validations:
21 | required: true
22 | - type: textarea
23 | id: reproduce
24 | attributes:
25 | label: Reproduction Code
26 | description: Steps to reproduce the behavior.
27 | - type: textarea
28 | id: expected
29 | attributes:
30 | label: Expected behavior
31 | description: A clear and concise description of what you expected to happen.
32 | - type: textarea
33 | id: actual
34 | attributes:
35 | label: Actual behavior
36 | description: A clear and concise description of what actually happened.
37 | - type: textarea
38 | id: environment
39 | attributes:
40 | label: Environment & Versions
41 | value: |
42 | - Kubernetes Version:
43 | - Spark Operator Version:
44 | - Apache Spark Version:
45 | - type: textarea
46 | id: context
47 | attributes:
48 | label: Additional context
49 | description: Add any other context about the problem here.
50 | - type: input
51 | id: votes
52 | attributes:
53 | label: Impacted by this bug?
54 | value: Give it a 👍 We prioritize the issues with most 👍
55 |
--------------------------------------------------------------------------------
/examples/spark-pi-dynamic-allocation.yaml:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright 2024 The Kubeflow authors.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | apiVersion: sparkoperator.k8s.io/v1beta2
17 | kind: SparkApplication
18 | metadata:
19 | name: spark-pi-dynamic-allocation
20 | namespace: default
21 | spec:
22 | type: Scala
23 | mode: cluster
24 | image: docker.io/library/spark:4.0.0
25 | imagePullPolicy: IfNotPresent
26 | mainClass: org.apache.spark.examples.SparkPi
27 | mainApplicationFile: local:///opt/spark/examples/jars/spark-examples.jar
28 | sparkVersion: 4.0.0
29 | driver:
30 | cores: 1
31 | memory: 512m
32 | serviceAccount: spark-operator-spark
33 | securityContext:
34 | capabilities:
35 | drop:
36 | - ALL
37 | runAsGroup: 185
38 | runAsUser: 185
39 | runAsNonRoot: true
40 | allowPrivilegeEscalation: false
41 | seccompProfile:
42 | type: RuntimeDefault
43 | executor:
44 | instances: 1
45 | cores: 1
46 | memory: 512m
47 | securityContext:
48 | capabilities:
49 | drop:
50 | - ALL
51 | runAsGroup: 185
52 | runAsUser: 185
53 | runAsNonRoot: true
54 | allowPrivilegeEscalation: false
55 | seccompProfile:
56 | type: RuntimeDefault
57 | dynamicAllocation:
58 | enabled: true
59 | initialExecutors: 2
60 | maxExecutors: 5
61 | minExecutors: 1
62 |
--------------------------------------------------------------------------------
/charts/spark-operator-chart/tests/hook/job_test.yaml:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright 2025 The Kubeflow authors.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # https://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 | #
16 |
17 | suite: Test hook job
18 |
19 | templates:
20 | - hook/job.yaml
21 |
22 | release:
23 | name: spark-operator
24 | namespace: spark-operator
25 |
26 | tests:
27 | - it: Should not create hook job if `hook.upgradeCrd` is false
28 | set:
29 | hook:
30 | upgradeCrd: false
31 | asserts:
32 | - hasDocuments:
33 | count: 0
34 |
35 | - it: Should create hook job if `hook.upgradeCrd` is true
36 | set:
37 | hook:
38 | upgradeCrd: true
39 | asserts:
40 | - containsDocument:
41 | apiVersion: batch/v1
42 | kind: Job
43 | name: spark-operator-hook
44 |
45 | - it: Should use the specified image repository
46 | set:
47 | hook:
48 | upgradeCrd: true
49 | image:
50 | registry: test-registry
51 | repository: test-repository
52 | tag: test-tag
53 | asserts:
54 | - equal:
55 | path: spec.template.spec.containers[?(@.name=="spark-operator-hook")].image
56 | value: test-registry/test-repository:test-tag
57 |
58 | - it: Should use the specified image pull policy if `image.pullPolicy` is set
59 | set:
60 | image:
61 | pullPolicy: Always
62 | hook:
63 | upgradeCrd: true
64 | asserts:
65 | - equal:
66 | path: spec.template.spec.containers[*].imagePullPolicy
67 | value: Always
68 |
--------------------------------------------------------------------------------
/examples/spark-pi-scheduled.yaml:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright 2018 Google LLC
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # https://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 | #
16 |
17 | apiVersion: sparkoperator.k8s.io/v1beta2
18 | kind: ScheduledSparkApplication
19 | metadata:
20 | name: spark-pi-scheduled
21 | namespace: default
22 | spec:
23 | schedule: "@every 3m"
24 | concurrencyPolicy: Allow
25 | template:
26 | type: Scala
27 | mode: cluster
28 | image: docker.io/library/spark:4.0.0
29 | imagePullPolicy: IfNotPresent
30 | mainClass: org.apache.spark.examples.SparkPi
31 | mainApplicationFile: local:///opt/spark/examples/jars/spark-examples.jar
32 | sparkVersion: 4.0.0
33 | restartPolicy:
34 | type: Never
35 | driver:
36 | cores: 1
37 | memory: 512m
38 | serviceAccount: spark-operator-spark
39 | securityContext:
40 | capabilities:
41 | drop:
42 | - ALL
43 | runAsGroup: 185
44 | runAsUser: 185
45 | runAsNonRoot: true
46 | allowPrivilegeEscalation: false
47 | seccompProfile:
48 | type: RuntimeDefault
49 | executor:
50 | instances: 1
51 | cores: 1
52 | memory: 512m
53 | securityContext:
54 | capabilities:
55 | drop:
56 | - ALL
57 | runAsGroup: 185
58 | runAsUser: 185
59 | runAsNonRoot: true
60 | allowPrivilegeEscalation: false
61 | seccompProfile:
62 | type: RuntimeDefault
63 |
--------------------------------------------------------------------------------
/api/v1beta2/groupversion_info.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2024 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | // Package v1beta2 contains API Schema definitions for the v1beta2 API group
18 | // +kubebuilder:object:generate=true
19 | // +groupName=sparkoperator.k8s.io
20 | package v1beta2
21 |
22 | import (
23 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
24 | "k8s.io/apimachinery/pkg/runtime"
25 | "k8s.io/apimachinery/pkg/runtime/schema"
26 | )
27 |
28 | var (
29 | // GroupVersion is group version used to register these objects.
30 | GroupVersion = schema.GroupVersion{Group: "sparkoperator.k8s.io", Version: "v1beta2"}
31 |
32 | // SchemeBuilder is the scheme builder with scheme init functions.
33 | SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes, addDefaultingFuncs)
34 |
35 | // AddToScheme adds the types in this group-version to the given scheme.
36 | AddToScheme = SchemeBuilder.AddToScheme
37 | )
38 |
39 | func init() {
40 | SchemeBuilder.Register(addKnownTypes, addDefaultingFuncs)
41 | }
42 |
43 | // Adds the list of known types to Scheme.
44 | func addKnownTypes(scheme *runtime.Scheme) error {
45 | scheme.AddKnownTypes(GroupVersion,
46 | &SparkApplication{},
47 | &SparkApplicationList{},
48 | &ScheduledSparkApplication{},
49 | &ScheduledSparkApplicationList{},
50 | )
51 |
52 | // AddToGroupVersion allows the serialization of client types like ListOptions.
53 | metav1.AddToGroupVersion(scheme, SchemeGroupVersion)
54 | return nil
55 | }
56 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.yaml:
--------------------------------------------------------------------------------
1 | name: Feature Request
2 | description: Suggest an idea for the Spark operator.
3 | labels:
4 | - kind/feature
5 | - lifecycle/needs-triage
6 | body:
7 | - type: markdown
8 | attributes:
9 | value: |
10 | Thanks for taking the time to fill out this Spark operator feature request!
11 | - type: markdown
12 | attributes:
13 | value: |
14 | - Please vote on this issue by adding a 👍 [reaction](https://blog.github.com/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/) to the original issue to help the community and maintainers prioritize this request.
15 | - Please do not leave "+1" or other comments that do not add relevant new information or questions, they generate extra noise for issue followers and do not help prioritize the request.
16 | - If you are interested in working on this issue or have submitted a pull request, please leave a comment.
17 | - type: textarea
18 | id: feature
19 | attributes:
20 | label: What feature you would like to be added?
21 | description: |
22 | A clear and concise description of what you want to add to the Spark operator.
23 | Please consider to write a Spark operator enhancement proposal if it is a large feature request.
24 | validations:
25 | required: true
26 | - type: textarea
27 | id: rationale
28 | attributes:
29 | label: Why is this needed?
30 | - type: textarea
31 | id: solution
32 | attributes:
33 | label: Describe the solution you would like
34 | - type: textarea
35 | id: alternatives
36 | attributes:
37 | label: Describe alternatives you have considered
38 | - type: textarea
39 | id: context
40 | attributes:
41 | label: Additional context
42 | description: Add any other context or screenshots about the feature request here.
43 | - type: input
44 | id: votes
45 | attributes:
46 | label: Love this feature?
47 | value: Give it a 👍 We prioritize the features with most 👍
48 |
--------------------------------------------------------------------------------
/pkg/common/event.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2024 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package common
18 |
19 | // SparkApplication events
20 | const (
21 | EventSparkApplicationAdded = "SparkApplicationAdded"
22 |
23 | EventSparkApplicationSubmitted = "SparkApplicationSubmitted"
24 |
25 | EventSparkApplicationSubmissionFailed = "SparkApplicationSubmissionFailed"
26 |
27 | EventSparkApplicationCompleted = "SparkApplicationCompleted"
28 |
29 | EventSparkApplicationFailed = "SparkApplicationFailed"
30 |
31 | EventSparkApplicationPendingRerun = "SparkApplicationPendingRerun"
32 |
33 | EventSparkApplicationSuspending = "SparkApplicationSuspending"
34 |
35 | EventSparkApplicationSuspended = "SparkApplicationSuspended"
36 |
37 | EventSparkApplicationResuming = "SparkApplicationResuming"
38 | )
39 |
40 | // Spark driver events
41 | const (
42 | EventSparkDriverPending = "SparkDriverPending"
43 |
44 | EventSparkDriverRunning = "SparkDriverRunning"
45 |
46 | EventSparkDriverCompleted = "SparkDriverCompleted"
47 |
48 | EventSparkDriverFailed = "SparkDriverFailed"
49 |
50 | EventSparkDriverUnknown = "SparkDriverUnknown"
51 | )
52 |
53 | // Spark executor events
54 | const (
55 | EventSparkExecutorPending = "SparkExecutorPending"
56 |
57 | EventSparkExecutorRunning = "SparkExecutorRunning"
58 |
59 | EventSparkExecutorCompleted = "SparkExecutorCompleted"
60 |
61 | EventSparkExecutorFailed = "SparkExecutorFailed"
62 |
63 | EventSparkExecutorUnknown = "SparkExecutorUnknown"
64 | )
65 |
--------------------------------------------------------------------------------
/spark-docker/Dockerfile:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright 2018 Google LLC
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # https://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 | #
16 |
17 | ARG SPARK_IMAGE=spark:3.5.5
18 | FROM ${SPARK_IMAGE}
19 |
20 | # Switch to user root so we can add additional jars and configuration files.
21 | USER root
22 |
23 | # Setup dependencies for Google Cloud Storage access.
24 | RUN rm $SPARK_HOME/jars/guava-14.0.1.jar
25 | ADD https://repo1.maven.org/maven2/com/google/guava/guava/23.0/guava-23.0.jar $SPARK_HOME/jars
26 | RUN chmod 644 $SPARK_HOME/jars/guava-23.0.jar
27 | # Add the connector jar needed to access Google Cloud Storage using the Hadoop FileSystem API.
28 | ADD https://storage.googleapis.com/hadoop-lib/gcs/gcs-connector-latest-hadoop2.jar $SPARK_HOME/jars
29 | RUN chmod 644 $SPARK_HOME/jars/gcs-connector-latest-hadoop2.jar
30 | ADD https://storage.googleapis.com/spark-lib/bigquery/spark-bigquery-latest_2.12.jar $SPARK_HOME/jars
31 | RUN chmod 644 $SPARK_HOME/jars/spark-bigquery-latest_2.12.jar
32 |
33 | # Setup for the Prometheus JMX exporter.
34 | # Add the Prometheus JMX exporter Java agent jar for exposing metrics sent to the JmxSink to Prometheus.
35 | ADD https://repo1.maven.org/maven2/io/prometheus/jmx/jmx_prometheus_javaagent/0.11.0/jmx_prometheus_javaagent-0.11.0.jar /prometheus/
36 | RUN chmod 644 /prometheus/jmx_prometheus_javaagent-0.11.0.jar
37 |
38 | USER ${spark_uid}
39 |
40 | RUN mkdir -p /etc/metrics/conf
41 | COPY conf/metrics.properties /etc/metrics/conf
42 | COPY conf/prometheus.yaml /etc/metrics/conf
43 |
44 | ENTRYPOINT ["/opt/entrypoint.sh"]
45 |
--------------------------------------------------------------------------------
/internal/scheduler/registry.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2019 Google LLC
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package scheduler
18 |
19 | import (
20 | "fmt"
21 | "sync"
22 | )
23 |
24 | var registry *Registry
25 |
26 | // Registry is a registry of scheduler factories.
27 | type Registry struct {
28 | factories map[string]Factory
29 |
30 | mu sync.Mutex
31 | }
32 |
33 | func GetRegistry() *Registry {
34 | if registry == nil {
35 | registry = &Registry{
36 | factories: make(map[string]Factory),
37 | }
38 | }
39 | return registry
40 | }
41 |
42 | func (r *Registry) GetScheduler(name string, config Config) (Interface, error) {
43 | r.mu.Lock()
44 | defer r.mu.Unlock()
45 |
46 | factory, exists := r.factories[name]
47 | if !exists {
48 | return nil, fmt.Errorf("scheduler %s not found", name)
49 | }
50 |
51 | return factory(config)
52 | }
53 |
54 | // RegisterScheduler registers a scheduler to the manager.
55 | func (r *Registry) Register(name string, factory Factory) error {
56 | r.mu.Lock()
57 | defer r.mu.Unlock()
58 |
59 | if _, ok := r.factories[name]; ok {
60 | return fmt.Errorf("scheduler %s is already registered", name)
61 | }
62 |
63 | r.factories[name] = factory
64 | logger.Info("Registered scheduler", "name", name)
65 | return nil
66 | }
67 |
68 | // GetRegisteredSchedulerNames gets the registered scheduler names.
69 | func (r *Registry) GetRegisteredSchedulerNames() []string {
70 | var names []string
71 | for name := range r.factories {
72 | names = append(names, name)
73 | }
74 | return names
75 | }
76 |
--------------------------------------------------------------------------------
/.golangci.yaml:
--------------------------------------------------------------------------------
1 | version: "2"
2 |
3 | run:
4 | # Timeout for total work, e.g. 30s, 5m, 5m30s.
5 | # If the value is lower or equal to 0, the timeout is disabled.
6 | # Default: 0 (disabled)
7 | timeout: 2m
8 |
9 | linters:
10 | # Enable specific linters.
11 | # https://golangci-lint.run/usage/linters/#enabled-by-default
12 | enable:
13 | # Detects places where loop variables are copied.
14 | - copyloopvar
15 | # Checks for duplicate words in the source code.
16 | - dupword
17 | # Tool for detection of FIXME, TODO and other comment keywords.
18 | # - godox
19 | # Enforces consistent import aliases.
20 | - importas
21 | # Find code that shadows one of Go's predeclared identifiers.
22 | - predeclared
23 | # Check that struct tags are well aligned.
24 | - tagalign
25 | # Remove unnecessary type conversions.
26 | - unconvert
27 | # Checks Go code for unused constants, variables, functions and types.
28 | - unused
29 |
30 | settings:
31 | importas:
32 | # List of aliases
33 | alias:
34 | - pkg: k8s.io/api/admissionregistration/v1
35 | alias: admissionregistrationv1
36 | - pkg: k8s.io/api/apps/v1
37 | alias: appsv1
38 | - pkg: k8s.io/api/batch/v1
39 | alias: batchv1
40 | - pkg: k8s.io/api/core/v1
41 | alias: corev1
42 | - pkg: k8s.io/api/extensions/v1beta1
43 | alias: extensionsv1beta1
44 | - pkg: k8s.io/api/networking/v1
45 | alias: networkingv1
46 | - pkg: k8s.io/apimachinery/pkg/apis/meta/v1
47 | alias: metav1
48 | - pkg: sigs.k8s.io/controller-runtime
49 | alias: ctrl
50 |
51 | issues:
52 | # Maximum issues count per one linter.
53 | # Set to 0 to disable.
54 | # Default: 50
55 | max-issues-per-linter: 50
56 | # Maximum count of issues with the same text.
57 | # Set to 0 to disable.
58 | # Default: 3
59 | max-same-issues: 3
60 |
61 | formatters:
62 | enable:
63 | # Check import statements are formatted according to the 'goimport' command.
64 | - goimports
65 |
66 |
--------------------------------------------------------------------------------
/examples/spark-pi-configmap.yaml:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright 2017 Google LLC
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # https://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | apiVersion: sparkoperator.k8s.io/v1beta2
17 | kind: SparkApplication
18 | metadata:
19 | name: spark-pi-configmap
20 | namespace: default
21 | spec:
22 | type: Scala
23 | mode: cluster
24 | image: docker.io/library/spark:4.0.0
25 | imagePullPolicy: IfNotPresent
26 | mainClass: org.apache.spark.examples.SparkPi
27 | mainApplicationFile: local:///opt/spark/examples/jars/spark-examples.jar
28 | sparkVersion: 4.0.0
29 | restartPolicy:
30 | type: Never
31 | volumes:
32 | - name: config-vol
33 | configMap:
34 | name: test-configmap
35 | driver:
36 | cores: 1
37 | memory: 512m
38 | volumeMounts:
39 | - name: config-vol
40 | mountPath: /opt/spark/config
41 | serviceAccount: spark-operator-spark
42 | securityContext:
43 | capabilities:
44 | drop:
45 | - ALL
46 | runAsGroup: 185
47 | runAsUser: 185
48 | runAsNonRoot: true
49 | allowPrivilegeEscalation: false
50 | seccompProfile:
51 | type: RuntimeDefault
52 | executor:
53 | instances: 1
54 | cores: 1
55 | memory: 512m
56 | volumeMounts:
57 | - name: config-vol
58 | mountPath: /opt/spark/config
59 | securityContext:
60 | capabilities:
61 | drop:
62 | - ALL
63 | runAsGroup: 185
64 | runAsUser: 185
65 | runAsNonRoot: true
66 | allowPrivilegeEscalation: false
67 | seccompProfile:
68 | type: RuntimeDefault
69 |
--------------------------------------------------------------------------------
/pkg/client/clientset/versioned/fake/register.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2025 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 | // Code generated by client-gen. DO NOT EDIT.
17 |
18 | package fake
19 |
20 | import (
21 | sparkoperatorv1beta2 "github.com/kubeflow/spark-operator/v2/api/v1beta2"
22 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
23 | runtime "k8s.io/apimachinery/pkg/runtime"
24 | schema "k8s.io/apimachinery/pkg/runtime/schema"
25 | serializer "k8s.io/apimachinery/pkg/runtime/serializer"
26 | utilruntime "k8s.io/apimachinery/pkg/util/runtime"
27 | )
28 |
29 | var scheme = runtime.NewScheme()
30 | var codecs = serializer.NewCodecFactory(scheme)
31 |
32 | var localSchemeBuilder = runtime.SchemeBuilder{
33 | sparkoperatorv1beta2.AddToScheme,
34 | }
35 |
36 | // AddToScheme adds all types of this clientset into the given scheme. This allows composition
37 | // of clientsets, like in:
38 | //
39 | // import (
40 | // "k8s.io/client-go/kubernetes"
41 | // clientsetscheme "k8s.io/client-go/kubernetes/scheme"
42 | // aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme"
43 | // )
44 | //
45 | // kclientset, _ := kubernetes.NewForConfig(c)
46 | // _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme)
47 | //
48 | // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types
49 | // correctly.
50 | var AddToScheme = localSchemeBuilder.AddToScheme
51 |
52 | func init() {
53 | v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"})
54 | utilruntime.Must(AddToScheme(scheme))
55 | }
56 |
--------------------------------------------------------------------------------
/internal/controller/doc.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2024 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package controller
18 |
19 | // Package controller implements the CustomResourceDefinition (CRD) controller for SparkApplications and
20 | // ScheduledSparkApplications.
21 | //
22 | // The ScheduledSparkApplication controller is responsible for watching ScheduledSparkApplications objects
23 | // and scheduling them according to the cron schedule in the ScheduledSparkApplication specification. For
24 | // each ScheduledSparkApplication, the controller creates a new SparkApplication instance when the next run
25 | // of the application is due and the condition for starting the next run is satisfied.
26 | //
27 | // The SparkApplication controller is responsible for watching SparkApplication objects and submitting
28 | // Spark applications described by the specs in the objects on behalf of users. After an application is
29 | // submitted, the controller monitors the application state and updates the status field of the
30 | // SparkApplication object accordingly. The controller uses a sparkSubmitRunner to submit applications
31 | // to run in the Kubernetes cluster where Spark Operator runs. The sparkSubmitRunner maintains a set of
32 | // workers, each of which is a goroutine, for actually running the spark-submit commands. The controller
33 | // also uses a sparkPodMonitor to watch Spark driver and executor pods. The sparkPodMonitor sends driver
34 | // and executor state updates to the controller, which then updates status field of SparkApplication
35 | // objects accordingly.
36 |
--------------------------------------------------------------------------------
/hack/api-docs/template/type.tpl:
--------------------------------------------------------------------------------
1 | {{ define "type" }}
2 |
3 |
4 | {{- .Name.Name }}
5 | {{ if eq .Kind "Alias" }}({{.Underlying}} alias){{ end -}}
6 |
7 | {{ with (typeReferences .) }}
8 |
9 | (Appears on:
10 | {{- $prev := "" -}}
11 | {{- range . -}}
12 | {{- if $prev -}}, {{ end -}}
13 | {{- $prev = . -}}
14 | {{ typeDisplayName . }}
15 | {{- end -}}
16 | )
17 |
18 | {{ end }}
19 |
20 |
21 | {{ safe (renderComments .CommentLines) }}
22 |
23 |
24 | {{ with (constantsOfType .) }}
25 |
26 |
27 |
28 | | Value |
29 | Description |
30 |
31 |
32 |
33 | {{- range . -}}
34 |
35 | {{- /*
36 | renderComments implicitly creates a element, so we
37 | add one to the display name as well to make the contents
38 | of the two cells align evenly.
39 | */ -}}
40 |
{{ typeDisplayName . }} |
41 | {{ safe (renderComments .CommentLines) }} |
42 |
43 | {{- end -}}
44 |
45 |
46 | {{ end }}
47 |
48 | {{ if .Members }}
49 |
50 |
51 |
52 | | Field |
53 | Description |
54 |
55 |
56 |
57 | {{ if isExportedType . }}
58 |
59 |
60 | apiVersion
61 | string |
62 |
63 |
64 | {{apiGroup .}}
65 |
66 | |
67 |
68 |
69 |
70 | kind
71 | string
72 | |
73 | {{.Name.Name}} |
74 |
75 | {{ end }}
76 | {{ template "members" .}}
77 |
78 |
79 | {{ end }}
80 |
81 | {{ end }}
--------------------------------------------------------------------------------
/pkg/client/clientset/versioned/scheme/register.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2025 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 | // Code generated by client-gen. DO NOT EDIT.
17 |
18 | package scheme
19 |
20 | import (
21 | sparkoperatorv1beta2 "github.com/kubeflow/spark-operator/v2/api/v1beta2"
22 | v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
23 | runtime "k8s.io/apimachinery/pkg/runtime"
24 | schema "k8s.io/apimachinery/pkg/runtime/schema"
25 | serializer "k8s.io/apimachinery/pkg/runtime/serializer"
26 | utilruntime "k8s.io/apimachinery/pkg/util/runtime"
27 | )
28 |
29 | var Scheme = runtime.NewScheme()
30 | var Codecs = serializer.NewCodecFactory(Scheme)
31 | var ParameterCodec = runtime.NewParameterCodec(Scheme)
32 | var localSchemeBuilder = runtime.SchemeBuilder{
33 | sparkoperatorv1beta2.AddToScheme,
34 | }
35 |
36 | // AddToScheme adds all types of this clientset into the given scheme. This allows composition
37 | // of clientsets, like in:
38 | //
39 | // import (
40 | // "k8s.io/client-go/kubernetes"
41 | // clientsetscheme "k8s.io/client-go/kubernetes/scheme"
42 | // aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme"
43 | // )
44 | //
45 | // kclientset, _ := kubernetes.NewForConfig(c)
46 | // _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme)
47 | //
48 | // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types
49 | // correctly.
50 | var AddToScheme = localSchemeBuilder.AddToScheme
51 |
52 | func init() {
53 | v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"})
54 | utilruntime.Must(AddToScheme(Scheme))
55 | }
56 |
--------------------------------------------------------------------------------
/charts/spark-operator-chart/templates/hook/job.yaml:
--------------------------------------------------------------------------------
1 | {{- /*
2 | Copyright 2025 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */ -}}
16 |
17 | {{- if .Values.hook.upgradeCrd -}}
18 | apiVersion: batch/v1
19 | kind: Job
20 | metadata:
21 | name: {{ include "spark-operator.hook.job.name" . }}
22 | namespace: {{ .Release.Namespace }}
23 | labels:
24 | {{- include "spark-operator.hook.labels" . | nindent 4 }}
25 | annotations:
26 | helm.sh/hook: pre-install,pre-upgrade
27 | helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
28 | helm.sh/hook-weight: "4"
29 | spec:
30 | template:
31 | spec:
32 | containers:
33 | - name: spark-operator-hook
34 | image: {{ include "spark-operator.hook.image" . }}
35 | {{- with .Values.image.pullPolicy }}
36 | imagePullPolicy: {{ . }}
37 | {{- end }}
38 | args:
39 | - apply
40 | - --server-side
41 | - -f
42 | - /etc/spark-operator/crds
43 | resources:
44 | requests:
45 | cpu: 100m
46 | memory: 64Mi
47 | limits:
48 | cpu: 100m
49 | memory: 64Mi
50 | securityContext:
51 | readOnlyRootFilesystem: true
52 | privileged: false
53 | allowPrivilegeEscalation: false
54 | capabilities:
55 | drop:
56 | - ALL
57 | {{- with .Values.image.pullSecrets }}
58 | imagePullSecrets:
59 | {{- toYaml . | nindent 8 }}
60 | {{- end }}
61 | serviceAccountName: {{ include "spark-operator.hook.serviceAccount.name" . }}
62 | restartPolicy: Never
63 | {{- end }}
64 |
--------------------------------------------------------------------------------
/examples/spark-pi-prometheus.yaml:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright 2018 Google LLC
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # https://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 | #
16 |
17 | apiVersion: sparkoperator.k8s.io/v1beta2
18 | kind: SparkApplication
19 | metadata:
20 | name: spark-pi
21 | namespace: default
22 | spec:
23 | type: Scala
24 | mode: cluster
25 | image: {IMAGE_REGISTRY}/{IMAGE_REPOSITORY}/docker.io/library/spark:4.0.0-gcs-prometheus
26 | imagePullPolicy: Always
27 | mainClass: org.apache.spark.examples.SparkPi
28 | mainApplicationFile: local:///opt/spark/examples/jars/spark-examples.jar
29 | arguments:
30 | - "100000"
31 | sparkVersion: 4.0.0
32 | restartPolicy:
33 | type: Never
34 | driver:
35 | cores: 1
36 | memory: 512m
37 | labels:
38 | version: 4.0.0
39 | serviceAccount: spark-operator-spark
40 | securityContext:
41 | capabilities:
42 | drop:
43 | - ALL
44 | runAsGroup: 185
45 | runAsUser: 185
46 | runAsNonRoot: true
47 | allowPrivilegeEscalation: false
48 | seccompProfile:
49 | type: RuntimeDefault
50 | executor:
51 | cores: 1
52 | instances: 1
53 | memory: 512m
54 | securityContext:
55 | capabilities:
56 | drop:
57 | - ALL
58 | runAsGroup: 185
59 | runAsUser: 185
60 | runAsNonRoot: true
61 | allowPrivilegeEscalation: false
62 | seccompProfile:
63 | type: RuntimeDefault
64 | labels:
65 | version: 4.0.0
66 | monitoring:
67 | exposeDriverMetrics: true
68 | exposeExecutorMetrics: true
69 | prometheus:
70 | jmxExporterJar: /prometheus/jmx_prometheus_javaagent-0.11.0.jar
71 | port: 8090
72 |
--------------------------------------------------------------------------------
/internal/webhook/scheduledsparkapplication_defaulter.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2024 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package webhook
18 |
19 | import (
20 | "context"
21 |
22 | "k8s.io/apimachinery/pkg/runtime"
23 | "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
24 |
25 | "github.com/kubeflow/spark-operator/v2/api/v1beta2"
26 | )
27 |
28 | // +kubebuilder:webhook:admissionReviewVersions=v1,failurePolicy=fail,groups=sparkoperator.k8s.io,matchPolicy=Exact,mutating=false,name=mutate-scheduledsparkapplication.sparkoperator.k8s.io,path=/validate-sparkoperator-k8s-io-v1beta2-sparkapplication,reinvocationPolicy=Never,resources=scheduledsparkapplications,sideEffects=None,verbs=create;update,versions=v1beta2,webhookVersions=v1
29 |
30 | // ScheduledSparkApplicationDefaulter sets default values for a SparkApplication.
31 | type ScheduledSparkApplicationDefaulter struct{}
32 |
33 | // NewSparkApplicationValidator creates a new SparkApplicationValidator instance.
34 | func NewScheduledSparkApplicationDefaulter() *ScheduledSparkApplicationDefaulter {
35 | return &ScheduledSparkApplicationDefaulter{}
36 | }
37 |
38 | // SparkApplicationDefaulter implements admission.CustomDefaulter.
39 | var _ admission.CustomDefaulter = &ScheduledSparkApplicationDefaulter{}
40 |
41 | // Default implements admission.CustomDefaulter.
42 | func (d *ScheduledSparkApplicationDefaulter) Default(ctx context.Context, obj runtime.Object) error {
43 | app, ok := obj.(*v1beta2.ScheduledSparkApplication)
44 | if !ok {
45 | return nil
46 | }
47 | logger.Info("Defaulting ScheduledSparkApplication", "name", app.Name, "namespace", app.Namespace)
48 | return nil
49 | }
50 |
--------------------------------------------------------------------------------
/charts/spark-operator-chart/tests/controller/serviceaccount_test.yaml:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright 2024 The Kubeflow authors.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # https://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 | #
16 |
17 | suite: Test controller service account
18 |
19 | templates:
20 | - controller/serviceaccount.yaml
21 |
22 | release:
23 | name: spark-operator
24 | namespace: spark-operator
25 |
26 | tests:
27 | - it: Should not create controller service account if `controller.serviceAccount.create` is false
28 | set:
29 | controller:
30 | serviceAccount:
31 | create: false
32 | asserts:
33 | - hasDocuments:
34 | count: 0
35 |
36 | - it: Should create controller service account by default
37 | asserts:
38 | - containsDocument:
39 | apiVersion: v1
40 | kind: ServiceAccount
41 | name: spark-operator-controller
42 |
43 | - it: Should use the specified service account name if `controller.serviceAccount.name` is set
44 | set:
45 | controller:
46 | serviceAccount:
47 | name: custom-service-account
48 | asserts:
49 | - containsDocument:
50 | apiVersion: v1
51 | kind: ServiceAccount
52 | name: custom-service-account
53 |
54 | - it: Should add extra annotations if `controller.serviceAccount.annotations` is set
55 | set:
56 | controller:
57 | serviceAccount:
58 | annotations:
59 | key1: value1
60 | key2: value2
61 | asserts:
62 | - equal:
63 | path: metadata.annotations.key1
64 | value: value1
65 | - equal:
66 | path: metadata.annotations.key2
67 | value: value2
68 |
--------------------------------------------------------------------------------
/charts/spark-operator-chart/templates/spark/rbac.yaml:
--------------------------------------------------------------------------------
1 | {{/*
2 | Copyright 2024 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */}}
16 |
17 | {{- if .Values.spark.rbac.create -}}
18 | {{- range $jobNamespace := .Values.spark.jobNamespaces | default list }}
19 | {{- if ne $jobNamespace "" }}
20 |
21 | ---
22 | apiVersion: rbac.authorization.k8s.io/v1
23 | kind: Role
24 | metadata:
25 | name: {{ include "spark-operator.spark.roleName" $ }}
26 | namespace: {{ $jobNamespace }}
27 | labels:
28 | {{- include "spark-operator.labels" $ | nindent 4 }}
29 | {{- with $.Values.spark.rbac.annotations }}
30 | annotations:
31 | {{- toYaml . | nindent 4 }}
32 | {{- end }}
33 | rules:
34 | - apiGroups:
35 | - ""
36 | resources:
37 | - pods
38 | - configmaps
39 | - persistentvolumeclaims
40 | - services
41 | verbs:
42 | - get
43 | - list
44 | - watch
45 | - create
46 | - update
47 | - patch
48 | - delete
49 | - deletecollection
50 |
51 | ---
52 | apiVersion: rbac.authorization.k8s.io/v1
53 | kind: RoleBinding
54 | metadata:
55 | name: {{ include "spark-operator.spark.roleBindingName" $ }}
56 | namespace: {{ $jobNamespace }}
57 | labels:
58 | {{- include "spark-operator.labels" $ | nindent 4 }}
59 | {{- with $.Values.spark.rbac.annotations }}
60 | annotations:
61 | {{- toYaml . | nindent 4 }}
62 | {{- end }}
63 | subjects:
64 | - kind: ServiceAccount
65 | name: {{ include "spark-operator.spark.serviceAccountName" $ }}
66 | namespace: {{ $jobNamespace }}
67 | roleRef:
68 | apiGroup: rbac.authorization.k8s.io
69 | kind: Role
70 | name: {{ include "spark-operator.spark.roleName" $ }}
71 | {{- end }}
72 | {{- end }}
73 | {{- end }}
74 |
--------------------------------------------------------------------------------
/pkg/client/clientset/versioned/typed/api/v1beta2/fake/fake_sparkapplication.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2025 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 | // Code generated by client-gen. DO NOT EDIT.
17 |
18 | package fake
19 |
20 | import (
21 | v1beta2 "github.com/kubeflow/spark-operator/v2/api/v1beta2"
22 | apiv1beta2 "github.com/kubeflow/spark-operator/v2/pkg/client/clientset/versioned/typed/api/v1beta2"
23 | gentype "k8s.io/client-go/gentype"
24 | )
25 |
26 | // fakeSparkApplications implements SparkApplicationInterface
27 | type fakeSparkApplications struct {
28 | *gentype.FakeClientWithList[*v1beta2.SparkApplication, *v1beta2.SparkApplicationList]
29 | Fake *FakeSparkoperatorV1beta2
30 | }
31 |
32 | func newFakeSparkApplications(fake *FakeSparkoperatorV1beta2, namespace string) apiv1beta2.SparkApplicationInterface {
33 | return &fakeSparkApplications{
34 | gentype.NewFakeClientWithList[*v1beta2.SparkApplication, *v1beta2.SparkApplicationList](
35 | fake.Fake,
36 | namespace,
37 | v1beta2.SchemeGroupVersion.WithResource("sparkapplications"),
38 | v1beta2.SchemeGroupVersion.WithKind("SparkApplication"),
39 | func() *v1beta2.SparkApplication { return &v1beta2.SparkApplication{} },
40 | func() *v1beta2.SparkApplicationList { return &v1beta2.SparkApplicationList{} },
41 | func(dst, src *v1beta2.SparkApplicationList) { dst.ListMeta = src.ListMeta },
42 | func(list *v1beta2.SparkApplicationList) []*v1beta2.SparkApplication {
43 | return gentype.ToPointerSlice(list.Items)
44 | },
45 | func(list *v1beta2.SparkApplicationList, items []*v1beta2.SparkApplication) {
46 | list.Items = gentype.FromPointerSlice(items)
47 | },
48 | ),
49 | fake,
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/charts/spark-operator-chart/templates/certmanager/certificate.yaml:
--------------------------------------------------------------------------------
1 | {{- /*
2 | Copyright 2025 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */ -}}
16 |
17 | {{- if .Values.webhook.enable }}
18 | {{- if .Values.certManager.enable }}
19 | {{- if not (.Capabilities.APIVersions.Has "cert-manager.io/v1/Certificate") }}
20 | {{- fail "The cluster does not support the required API version `cert-manager.io/v1` for `Certificate`." }}
21 | {{- end }}
22 | apiVersion: cert-manager.io/v1
23 | kind: Certificate
24 | metadata:
25 | name: {{ include "spark-operator.certManager.certificate.name" . }}
26 | namespace: {{ .Release.Namespace }}
27 | labels:
28 | {{- include "spark-operator.labels" . | nindent 4 }}
29 | spec:
30 | secretName: {{ include "spark-operator.webhook.secretName" . }}
31 | issuerRef:
32 | {{- if not .Values.certManager.issuerRef }}
33 | group: cert-manager.io
34 | kind: Issuer
35 | name: {{ include "spark-operator.certManager.issuer.name" . }}
36 | {{- else }}
37 | {{- toYaml .Values.certManager.issuerRef | nindent 4 }}
38 | {{- end }}
39 | commonName: {{ include "spark-operator.webhook.serviceName" . }}.{{ .Release.Namespace }}.svc
40 | dnsNames:
41 | - {{ include "spark-operator.webhook.serviceName" . }}.{{ .Release.Namespace }}.svc
42 | - {{ include "spark-operator.webhook.serviceName" . }}.{{ .Release.Namespace }}.svc.cluster.local
43 | subject:
44 | organizationalUnits:
45 | - spark-operator
46 | usages:
47 | - server auth
48 | - client auth
49 | {{- with .Values.certManager.duration }}
50 | duration: {{ . }}
51 | {{- end }}
52 | {{- with .Values.certManager.renewBefore }}
53 | renewBefore: {{ . }}
54 | {{- end }}
55 | {{- end }}
56 | {{- end }}
57 |
--------------------------------------------------------------------------------
/pkg/client/informers/externalversions/api/v1beta2/interface.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2025 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 | // Code generated by informer-gen. DO NOT EDIT.
17 |
18 | package v1beta2
19 |
20 | import (
21 | internalinterfaces "github.com/kubeflow/spark-operator/v2/pkg/client/informers/externalversions/internalinterfaces"
22 | )
23 |
24 | // Interface provides access to all the informers in this group version.
25 | type Interface interface {
26 | // ScheduledSparkApplications returns a ScheduledSparkApplicationInformer.
27 | ScheduledSparkApplications() ScheduledSparkApplicationInformer
28 | // SparkApplications returns a SparkApplicationInformer.
29 | SparkApplications() SparkApplicationInformer
30 | }
31 |
32 | type version struct {
33 | factory internalinterfaces.SharedInformerFactory
34 | namespace string
35 | tweakListOptions internalinterfaces.TweakListOptionsFunc
36 | }
37 |
38 | // New returns a new Interface.
39 | func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface {
40 | return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
41 | }
42 |
43 | // ScheduledSparkApplications returns a ScheduledSparkApplicationInformer.
44 | func (v *version) ScheduledSparkApplications() ScheduledSparkApplicationInformer {
45 | return &scheduledSparkApplicationInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
46 | }
47 |
48 | // SparkApplications returns a SparkApplicationInformer.
49 | func (v *version) SparkApplications() SparkApplicationInformer {
50 | return &sparkApplicationInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
51 | }
52 |
--------------------------------------------------------------------------------
/charts/spark-operator-chart/templates/hook/_helpers.tpl:
--------------------------------------------------------------------------------
1 | {{- /*
2 | Copyright 2025 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */ -}}
16 |
17 | {{- /* Create the name of Helm hook */ -}}
18 | {{- define "spark-operator.hook.name" -}}
19 | {{- include "spark-operator.fullname" . }}-hook
20 | {{- end -}}
21 |
22 | {{- /* Common labels for the Helm hook */ -}}
23 | {{- define "spark-operator.hook.labels" -}}
24 | {{ include "spark-operator.labels" . }}
25 | app.kubernetes.io/component: hook
26 | {{- end -}}
27 |
28 | {{- /* Selector labels for the Helm hook */ -}}
29 | {{- define "spark-operator.hook.selectorLabels" -}}
30 | {{ include "spark-operator.hook.labels" . }}
31 | {{- end -}}
32 |
33 | {{- /* Create the name of the service account to be used by the Helm hooks. */ -}}
34 | {{- define "spark-operator.hook.serviceAccount.name" -}}
35 | {{ include "spark-operator.hook.name" . }}
36 | {{- end -}}
37 |
38 | {{- /* Create the name of the cluster role to be used by the Helm hooks. */ -}}
39 | {{- define "spark-operator.hook.clusterRole.name" -}}
40 | {{ include "spark-operator.hook.name" . }}
41 | {{- end -}}
42 |
43 | {{- /* Create the name of the cluster role binding to be used by the Helm hooks. */ -}}
44 | {{- define "spark-operator.hook.clusterRoleBinding.name" -}}
45 | {{ include "spark-operator.hook.clusterRole.name" . }}
46 | {{- end -}}
47 |
48 | {{- /* Create the name of the Helm hook job. */ -}}
49 | {{- define "spark-operator.hook.job.name" -}}
50 | {{ include "spark-operator.hook.name" . }}
51 | {{- end -}}
52 |
53 | {{- /* Create the name of the Helm hook job. */ -}}
54 | {{- define "spark-operator.hook.image" -}}
55 | {{ printf "%s/%s:%s" .Values.hook.image.registry .Values.hook.image.repository (.Values.hook.image.tag | default .Chart.AppVersion | toString) }}
56 | {{- end -}}
57 |
--------------------------------------------------------------------------------
/.github/workflows/check-release.yaml:
--------------------------------------------------------------------------------
1 | name: Check Release
2 |
3 | on:
4 | pull_request:
5 | branches:
6 | - release-*
7 | paths:
8 | - VERSION
9 |
10 | permissions:
11 | contents: read
12 |
13 | concurrency:
14 | group: ${{ github.workflow }}-${{ github.ref }}
15 | cancel-in-progress: true
16 |
17 | env:
18 | SEMVER_PATTERN: '^v([0-9]+)\.([0-9]+)\.([0-9]+)(-rc\.([0-9]+))?$'
19 |
20 | jobs:
21 | check:
22 | runs-on: ubuntu-latest
23 |
24 | steps:
25 | - name: Checkout source code
26 | uses: actions/checkout@v5.0.0
27 | with:
28 | fetch-depth: 0
29 |
30 | - name: Check whether version matches semver pattern
31 | run: |
32 | VERSION=$(cat VERSION)
33 | if [[ ${VERSION} =~ ${{ env.SEMVER_PATTERN }} ]]; then
34 | echo "Version '${VERSION}' matches semver pattern."
35 | else
36 | echo "Version '${VERSION}' does not match semver pattern."
37 | exit 1
38 | fi
39 | echo "VERSION=${VERSION}" >> $GITHUB_ENV
40 |
41 | - name: Check whether chart version and appVersion matches version
42 | run: |
43 | VERSION=${VERSION#v}
44 | CHART_VERSION=$(cat charts/spark-operator-chart/Chart.yaml | grep version | awk '{print $2}')
45 | CHART_APP_VERSION=$(cat charts/spark-operator-chart/Chart.yaml | grep appVersion | awk '{print $2}')
46 | if [[ ${CHART_VERSION} == ${VERSION} ]]; then
47 | echo "Chart version '${CHART_VERSION}' matches version '${VERSION}'."
48 | else
49 | echo "Chart version '${CHART_VERSION}' does not match version '${VERSION}'."
50 | exit 1
51 | fi
52 | if [[ ${CHART_APP_VERSION} == ${VERSION} ]]; then
53 | echo "Chart appVersion '${CHART_APP_VERSION}' matches version '${VERSION}'."
54 | else
55 | echo "Chart appVersion '${CHART_APP_VERSION}' does not match version '${VERSION}'."
56 | exit 1
57 | fi
58 |
59 | - name: Check if tag exists
60 | run: |
61 | git fetch --tags
62 | if git tag -l | grep -q "^${VERSION}$"; then
63 | echo "Tag '${VERSION}' already exists."
64 | exit 1
65 | else
66 | echo "Tag '${VERSION}' does not exist."
67 | fi
68 |
--------------------------------------------------------------------------------
/charts/spark-operator-chart/tests/controller/poddisruptionbudget_test.yaml:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright 2024 The Kubeflow authors.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # https://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 | #
16 |
17 | suite: Test controller pod disruption budget
18 |
19 | templates:
20 | - controller/poddisruptionbudget.yaml
21 |
22 | release:
23 | name: spark-operator
24 | namespace: spark-operator
25 |
26 | tests:
27 | - it: Should not render podDisruptionBudget if `controller.podDisruptionBudget.enable` is false
28 | set:
29 | controller:
30 | podDisruptionBudget:
31 | enable: false
32 | asserts:
33 | - hasDocuments:
34 | count: 0
35 |
36 | - it: Should fail if `controller.replicas` is less than 2 when `controller.podDisruptionBudget.enable` is true
37 | set:
38 | controller:
39 | replicas: 1
40 | podDisruptionBudget:
41 | enable: true
42 | asserts:
43 | - failedTemplate:
44 | errorMessage: "controller.replicas must be greater than 1 to enable pod disruption budget for controller"
45 |
46 | - it: Should render spark operator podDisruptionBudget if `controller.podDisruptionBudget.enable` is true
47 | set:
48 | controller:
49 | replicas: 2
50 | podDisruptionBudget:
51 | enable: true
52 | asserts:
53 | - containsDocument:
54 | apiVersion: policy/v1
55 | kind: PodDisruptionBudget
56 | name: spark-operator-controller-pdb
57 |
58 | - it: Should set minAvailable if `controller.podDisruptionBudget.minAvailable` is specified
59 | set:
60 | controller:
61 | replicas: 2
62 | podDisruptionBudget:
63 | enable: true
64 | minAvailable: 3
65 | asserts:
66 | - equal:
67 | path: spec.minAvailable
68 | value: 3
69 |
--------------------------------------------------------------------------------
/pkg/client/clientset/versioned/typed/api/v1beta2/fake/fake_scheduledsparkapplication.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2025 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 | // Code generated by client-gen. DO NOT EDIT.
17 |
18 | package fake
19 |
20 | import (
21 | v1beta2 "github.com/kubeflow/spark-operator/v2/api/v1beta2"
22 | apiv1beta2 "github.com/kubeflow/spark-operator/v2/pkg/client/clientset/versioned/typed/api/v1beta2"
23 | gentype "k8s.io/client-go/gentype"
24 | )
25 |
26 | // fakeScheduledSparkApplications implements ScheduledSparkApplicationInterface
27 | type fakeScheduledSparkApplications struct {
28 | *gentype.FakeClientWithList[*v1beta2.ScheduledSparkApplication, *v1beta2.ScheduledSparkApplicationList]
29 | Fake *FakeSparkoperatorV1beta2
30 | }
31 |
32 | func newFakeScheduledSparkApplications(fake *FakeSparkoperatorV1beta2, namespace string) apiv1beta2.ScheduledSparkApplicationInterface {
33 | return &fakeScheduledSparkApplications{
34 | gentype.NewFakeClientWithList[*v1beta2.ScheduledSparkApplication, *v1beta2.ScheduledSparkApplicationList](
35 | fake.Fake,
36 | namespace,
37 | v1beta2.SchemeGroupVersion.WithResource("scheduledsparkapplications"),
38 | v1beta2.SchemeGroupVersion.WithKind("ScheduledSparkApplication"),
39 | func() *v1beta2.ScheduledSparkApplication { return &v1beta2.ScheduledSparkApplication{} },
40 | func() *v1beta2.ScheduledSparkApplicationList { return &v1beta2.ScheduledSparkApplicationList{} },
41 | func(dst, src *v1beta2.ScheduledSparkApplicationList) { dst.ListMeta = src.ListMeta },
42 | func(list *v1beta2.ScheduledSparkApplicationList) []*v1beta2.ScheduledSparkApplication {
43 | return gentype.ToPointerSlice(list.Items)
44 | },
45 | func(list *v1beta2.ScheduledSparkApplicationList, items []*v1beta2.ScheduledSparkApplication) {
46 | list.Items = gentype.FromPointerSlice(items)
47 | },
48 | ),
49 | fake,
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/internal/scheduler/yunikorn/resourceusage/resource_usage.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2024 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package resourceusage
18 |
19 | import (
20 | "fmt"
21 |
22 | "k8s.io/apimachinery/pkg/api/resource"
23 |
24 | "github.com/kubeflow/spark-operator/v2/api/v1beta2"
25 | )
26 |
27 | func cpuRequest(cores *int32, coreRequest *string) (string, error) {
28 | // coreRequest takes precedence over cores if specified
29 | // coreLimit is not relevant as pods are scheduled based on request values
30 | if coreRequest != nil {
31 | // Fail fast by validating coreRequest before app submission even though
32 | // both Spark and Yunikorn validate this field anyway
33 | if _, err := resource.ParseQuantity(*coreRequest); err != nil {
34 | return "", fmt.Errorf("failed to parse %s: %w", *coreRequest, err)
35 | }
36 | return *coreRequest, nil
37 | }
38 | if cores != nil {
39 | return fmt.Sprintf("%d", *cores), nil
40 | }
41 | return "1", nil
42 | }
43 |
44 | func DriverPodRequests(app *v1beta2.SparkApplication) (map[string]string, error) {
45 | cpuValue, err := cpuRequest(app.Spec.Driver.Cores, app.Spec.Driver.CoreRequest)
46 | if err != nil {
47 | return nil, err
48 | }
49 |
50 | memoryValue, err := driverMemoryRequest(app)
51 | if err != nil {
52 | return nil, err
53 | }
54 |
55 | return map[string]string{
56 | "cpu": cpuValue,
57 | "memory": memoryValue,
58 | }, nil
59 | }
60 |
61 | func ExecutorPodRequests(app *v1beta2.SparkApplication) (map[string]string, error) {
62 | cpuValue, err := cpuRequest(app.Spec.Executor.Cores, app.Spec.Executor.CoreRequest)
63 | if err != nil {
64 | return nil, err
65 | }
66 |
67 | memoryValue, err := executorMemoryRequest(app)
68 | if err != nil {
69 | return nil, err
70 | }
71 |
72 | return map[string]string{
73 | "cpu": cpuValue,
74 | "memory": memoryValue,
75 | }, nil
76 | }
77 |
--------------------------------------------------------------------------------
/pkg/util/sparkpod.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2024 The Kubeflow authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | https://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package util
18 |
19 | import (
20 | corev1 "k8s.io/api/core/v1"
21 |
22 | "github.com/kubeflow/spark-operator/v2/pkg/common"
23 | )
24 |
25 | // IsLaunchedBySparkOperator returns whether the given pod is launched by the Spark Operator.
26 | func IsLaunchedBySparkOperator(pod *corev1.Pod) bool {
27 | return pod.Labels[common.LabelLaunchedBySparkOperator] == "true"
28 | }
29 |
30 | // IsDriverPod returns whether the given pod is a Spark driver Pod.
31 | func IsDriverPod(pod *corev1.Pod) bool {
32 | return pod.Labels[common.LabelSparkRole] == common.SparkRoleDriver
33 | }
34 |
35 | // IsExecutorPod returns whether the given pod is a Spark executor Pod.
36 | func IsExecutorPod(pod *corev1.Pod) bool {
37 | return pod.Labels[common.LabelSparkRole] == common.SparkRoleExecutor
38 | }
39 |
40 | // GetSparkExecutorID returns the Spark executor ID by checking out pod labels.
41 | func GetSparkExecutorID(pod *corev1.Pod) string {
42 | return pod.Labels[common.LabelSparkExecutorID]
43 | }
44 |
45 | // GetAppName returns the spark application name by checking out pod labels.
46 | func GetAppName(pod *corev1.Pod) string {
47 | return pod.Labels[common.LabelSparkAppName]
48 | }
49 |
50 | // GetConnName returns the spark connection name by checking out pod labels.
51 | func GetConnName(pod *corev1.Pod) string {
52 | return pod.Labels[common.LabelSparkConnectName]
53 | }
54 |
55 | // GetSparkApplicationID returns the spark application ID by checking out pod labels.
56 | func GetSparkApplicationID(pod *corev1.Pod) string {
57 | return pod.Labels[common.LabelSparkApplicationSelector]
58 | }
59 |
60 | func IsPodReady(pod *corev1.Pod) bool {
61 | for _, condition := range pod.Status.Conditions {
62 | if condition.Type == corev1.PodReady && condition.Status == corev1.ConditionTrue {
63 | return true
64 | }
65 | }
66 | return false
67 | }
68 |
--------------------------------------------------------------------------------
/examples/sparkconnect/spark-connect.yaml:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright 2025 The Kubeflow authors.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # https://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | apiVersion: sparkoperator.k8s.io/v1alpha1
17 | kind: SparkConnect
18 | metadata:
19 | name: spark-connect
20 | namespace: default
21 | spec:
22 | sparkVersion: 4.0.0
23 | server:
24 | template:
25 | metadata:
26 | labels:
27 | key1: value1
28 | key2: value2
29 | annotations:
30 | key3: value3
31 | key4: value4
32 | spec:
33 | containers:
34 | - name: spark-kubernetes-driver
35 | image: spark:4.0.0
36 | imagePullPolicy: Always
37 | resources:
38 | requests:
39 | cpu: 1
40 | memory: 1Gi
41 | limits:
42 | cpu: 1
43 | memory: 1Gi
44 | serviceAccount: spark-operator-spark
45 | securityContext:
46 | capabilities:
47 | drop:
48 | - ALL
49 | runAsGroup: 185
50 | runAsUser: 185
51 | runAsNonRoot: true
52 | allowPrivilegeEscalation: false
53 | seccompProfile:
54 | type: RuntimeDefault
55 | executor:
56 | instances: 2
57 | cores: 1
58 | memory: 512m
59 | template:
60 | metadata:
61 | labels:
62 | key1: value1
63 | key2: value2
64 | annotations:
65 | key3: value3
66 | key4: value4
67 | spec:
68 | containers:
69 | - name: spark-kubernetes-executor
70 | image: spark:4.0.0
71 | imagePullPolicy: Always
72 | securityContext:
73 | capabilities:
74 | drop:
75 | - ALL
76 | runAsGroup: 185
77 | runAsUser: 185
78 | runAsNonRoot: true
79 | allowPrivilegeEscalation: false
80 | seccompProfile:
81 | type: RuntimeDefault
82 |
--------------------------------------------------------------------------------