You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@spark.apache.org by do...@apache.org on 2026/09/14 14:56:25 UTC

(spark) branch master updated: [SPARK-59489][K8S] Promote `KubernetesExecutorSpec` to `DeveloperApi` and `Stable`

This is an automated email from the ASF dual-hosted git repository.

dongjoon-hyun pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/spark.git


The following commit(s) were added to refs/heads/master by this push:
     new 93d40164f0da [SPARK-59489][K8S] Promote `KubernetesExecutorSpec` to `DeveloperApi` and `Stable`
93d40164f0da is described below

commit 93d40164f0daa7799e06c3eed2d97523c7af0238
Author: Dongjoon Hyun <do...@apache.org>
AuthorDate: Mon Sep 14 07:56:14 2026 -0700

    [SPARK-59489][K8S] Promote `KubernetesExecutorSpec` to `DeveloperApi` and `Stable`
    
    ### What changes were proposed in this pull request?
    
    This PR aims to promote `KubernetesExecutorSpec` to `DeveloperApi` and `Stable` with Java-friendly APIs:
    - Promote `KubernetesExecutorSpec` to `public`, `DeveloperApi`, and `Stable`.
    - Add Java getter: `spec.getExecutorKubernetesResourcesAsJavaList`.
    - Add Java factory: `KubernetesExecutorSpec.create(pod, executorKubernetesResources)`.
    
    ### Why are the changes needed?
    
    `KubernetesExecutorSpec` was introduced at Apache Spark 3.1.0 and has been unchanged for last 6 years.
    
    - https://github.com/apache/spark/pull/29472
    
    https://github.com/apache/spark/blob/07d92669ccd2c873bb5fca7aa1aaee7c463e6d70/resource-managers/kubernetes/core/src/main/scala/org/apache/spark/deploy/k8s/KubernetesExecutorSpec.scala#L21-L23
    
    To provide a Java-friendly `DeveloperApi` for external projects such as the Apache Spark Kubernetes Operator, symmetric to `KubernetesDriverSpec`.
    
    https://github.com/apache/spark/blob/07d92669ccd2c873bb5fca7aa1aaee7c463e6d70/resource-managers/kubernetes/core/src/main/scala/org/apache/spark/deploy/k8s/KubernetesDriverSpec.scala#L33-L36
    
    ### Does this PR introduce _any_ user-facing change?
    
    No.
    
    ### How was this patch tested?
    
    Pass the CIs with the newly added test suite.
    
    ### Was this patch authored or co-authored using generative AI tooling?
    
    Generated-by: Antigravity (Gemini 3.8 Flash)
    
    Closes #58773 from dongjoon-hyun/SPARK-59489.
    
    Authored-by: Dongjoon Hyun <do...@apache.org>
    Signed-off-by: Dongjoon Hyun <do...@apache.org>
---
 .../spark/deploy/k8s/KubernetesExecutorSpec.scala  | 39 +++++++++++++-
 .../deploy/k8s/KubernetesExecutorSpecSuite.scala   | 62 ++++++++++++++++++++++
 2 files changed, 99 insertions(+), 2 deletions(-)

diff --git a/resource-managers/kubernetes/core/src/main/scala/org/apache/spark/deploy/k8s/KubernetesExecutorSpec.scala b/resource-managers/kubernetes/core/src/main/scala/org/apache/spark/deploy/k8s/KubernetesExecutorSpec.scala
index 4db9211c1e42..d785e435a059 100644
--- a/resource-managers/kubernetes/core/src/main/scala/org/apache/spark/deploy/k8s/KubernetesExecutorSpec.scala
+++ b/resource-managers/kubernetes/core/src/main/scala/org/apache/spark/deploy/k8s/KubernetesExecutorSpec.scala
@@ -16,8 +16,43 @@
  */
 package org.apache.spark.deploy.k8s
 
+import java.util.{List => JList}
+
+import scala.jdk.CollectionConverters._
+
 import io.fabric8.kubernetes.api.model.HasMetadata
 
-private[spark] case class KubernetesExecutorSpec(
+import org.apache.spark.annotation.{DeveloperApi, Since, Stable}
+
+/**
+ * :: DeveloperApi ::
+ *
+ * Spec for executor pod and resources, used for K8s operations internally
+ * and Spark K8s operator.
+ */
+@Stable
+@DeveloperApi
+@Since("4.4.0")
+case class KubernetesExecutorSpec(
     pod: SparkPod,
-    executorKubernetesResources: Seq[HasMetadata])
+    executorKubernetesResources: Seq[HasMetadata]) {
+
+  /** Get executor Kubernetes resources as a Java-friendly list. */
+  @Since("4.4.0")
+  def getExecutorKubernetesResourcesAsJavaList: JList[HasMetadata] =
+    executorKubernetesResources.asJava
+}
+
+@Stable
+@DeveloperApi
+@Since("4.4.0")
+object KubernetesExecutorSpec {
+  @Since("4.4.0")
+  def create(
+      pod: SparkPod,
+      executorKubernetesResources: JList[HasMetadata]): KubernetesExecutorSpec = {
+    KubernetesExecutorSpec(
+      pod,
+      executorKubernetesResources.asScala.toSeq)
+  }
+}
diff --git a/resource-managers/kubernetes/core/src/test/scala/org/apache/spark/deploy/k8s/KubernetesExecutorSpecSuite.scala b/resource-managers/kubernetes/core/src/test/scala/org/apache/spark/deploy/k8s/KubernetesExecutorSpecSuite.scala
new file mode 100644
index 000000000000..446e5517f2a7
--- /dev/null
+++ b/resource-managers/kubernetes/core/src/test/scala/org/apache/spark/deploy/k8s/KubernetesExecutorSpecSuite.scala
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.spark.deploy.k8s
+
+import java.util.{Arrays, List => JList}
+
+import io.fabric8.kubernetes.api.model.{ContainerBuilder, HasMetadata, PodBuilder, SecretBuilder}
+
+import org.apache.spark.SparkFunSuite
+
+class KubernetesExecutorSpecSuite extends SparkFunSuite {
+
+  private val POD = new PodBuilder()
+    .withNewMetadata().withName("executor").endMetadata()
+    .withNewSpec().endSpec()
+    .build()
+  private val CONTAINER = new ContainerBuilder().withName("executor-container").build()
+  private val SPARK_POD = SparkPod(POD, CONTAINER)
+
+  test("create from Java collections") {
+    val secret = new SecretBuilder()
+      .withNewMetadata().withName("test-secret").endMetadata()
+      .build()
+    val resources = Arrays.asList[HasMetadata](secret)
+
+    val spec = KubernetesExecutorSpec.create(SPARK_POD, resources)
+
+    assert(spec.pod === SPARK_POD)
+    assert(spec.executorKubernetesResources.length === 1)
+    assert(spec.executorKubernetesResources.head === secret)
+
+    val javaResources = spec.getExecutorKubernetesResourcesAsJavaList
+    assert(javaResources.isInstanceOf[JList[_]])
+    assert(javaResources.size() === 1)
+    assert(javaResources.get(0) === secret)
+  }
+
+  test("create from empty Java collections") {
+    val resources = Arrays.asList[HasMetadata]()
+
+    val spec = KubernetesExecutorSpec.create(SPARK_POD, resources)
+
+    assert(spec.pod === SPARK_POD)
+    assert(spec.executorKubernetesResources.isEmpty)
+    assert(spec.getExecutorKubernetesResourcesAsJavaList.isEmpty)
+  }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@spark.apache.org
For additional commands, e-mail: commits-help@spark.apache.org