This is an automated email from the ASF dual-hosted git repository.
cryptoe pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/druid.git
The following commit(s) were added to refs/heads/master by this push:
new cec7f0cf0b3 feat: Add endpoint to fetch configured peon pod template
names (#19712)
cec7f0cf0b3 is described below
commit cec7f0cf0b3b98262af707d8899692599c019fa7
Author: Armanit Garg <[email protected]>
AuthorDate: Tue Jul 21 22:50:27 2026 +0530
feat: Add endpoint to fetch configured peon pod template names (#19712)
* feat: Add endpoint to fetch configured peon pod template specs
* only return names, not specs
---
docs/development/extensions-core/k8s-jobs.md | 69 +++++++++++++++++++
.../k8s/overlord/KubernetesOverlordModule.java | 2 +
.../KubernetesTaskRunnerPodTemplateResource.java | 77 ++++++++++++++++++++++
.../DynamicConfigPodTemplateSelector.java | 11 ++++
.../overlord/taskadapter/PodTemplateSelector.java | 8 +++
.../taskadapter/PodTemplateTaskAdapter.java | 5 ++
...ubernetesTaskRunnerPodTemplateResourceTest.java | 62 +++++++++++++++++
.../DynamicConfigPodTemplateSelectorTest.java | 21 ++++++
.../taskadapter/TestPodTemplateSelector.java | 9 +++
9 files changed, 264 insertions(+)
diff --git a/docs/development/extensions-core/k8s-jobs.md
b/docs/development/extensions-core/k8s-jobs.md
index 448309a87fd..8ba0e215922 100644
--- a/docs/development/extensions-core/k8s-jobs.md
+++ b/docs/development/extensions-core/k8s-jobs.md
@@ -344,6 +344,75 @@ Host: http://ROUTER_IP:ROUTER_PORT
```
</details>
+#### Get pod template names
+
+Retrieves the names of the peon pod templates currently configured on the
Overlord for the Kubernetes
+task runner. Returns a JSON array of the configured template names (the keys
of the
+`druid.indexer.runner.k8s.podTemplate.*` runtime properties, such as `base`
and per task type names).
+
+This endpoint is only available when the [Custom Template Pod
Adapter](#custom-template-pod-adapter) is
+configured (`druid.indexer.runner.k8s.adapter.type: customTemplateAdapter`).
For any other adapter it
+returns a `404` response.
+
+##### URL
+
+`GET` `/druid/indexer/v1/k8s/taskrunner/podTemplates`
+
+##### Responses
+
+<Tabs>
+
+<TabItem value="13" label="200 SUCCESS">
+
+
+*Successfully retrieved pod template names*
+
+</TabItem>
+
+<TabItem value="14" label="404 NOT FOUND">
+
+
+*The configured pod adapter is not the custom template pod adapter*
+
+</TabItem>
+</Tabs>
+
+---
+
+##### Sample request
+
+<Tabs>
+
+<TabItem value="15" label="cURL">
+
+```shell
+curl
"http://ROUTER_IP:ROUTER_PORT/druid/indexer/v1/k8s/taskrunner/podTemplates"
+```
+</TabItem>
+
+<TabItem value="16" label="HTTP">
+
+```HTTP
+GET /druid/indexer/v1/k8s/taskrunner/podTemplates HTTP/1.1
+Host: http://ROUTER_IP:ROUTER_PORT
+```
+
+</TabItem>
+</Tabs>
+
+##### Sample response
+
+<details>
+<summary>View the response</summary>
+
+```json
+[
+ "base",
+ "index_kafka"
+]
+```
+</details>
+
## Pod adapters
The logic defining how the pod template is built for your Kubernetes Job
depends on which pod adapter you have specified.
diff --git
a/extensions-core/kubernetes-overlord-extensions/src/main/java/org/apache/druid/k8s/overlord/KubernetesOverlordModule.java
b/extensions-core/kubernetes-overlord-extensions/src/main/java/org/apache/druid/k8s/overlord/KubernetesOverlordModule.java
index b45aa6fb846..8271fcfb723 100644
---
a/extensions-core/kubernetes-overlord-extensions/src/main/java/org/apache/druid/k8s/overlord/KubernetesOverlordModule.java
+++
b/extensions-core/kubernetes-overlord-extensions/src/main/java/org/apache/druid/k8s/overlord/KubernetesOverlordModule.java
@@ -64,6 +64,7 @@ import
org.apache.druid.k8s.overlord.common.httpclient.vertx.DruidKubernetesVert
import
org.apache.druid.k8s.overlord.common.httpclient.vertx.DruidKubernetesVertxHttpClientFactory;
import
org.apache.druid.k8s.overlord.execution.KubernetesTaskExecutionConfigResource;
import
org.apache.druid.k8s.overlord.execution.KubernetesTaskRunnerDynamicConfig;
+import
org.apache.druid.k8s.overlord.execution.KubernetesTaskRunnerPodTemplateResource;
import org.apache.druid.k8s.overlord.runnerstrategy.RunnerStrategy;
import
org.apache.druid.k8s.overlord.taskadapter.DynamicConfigPodTemplateSelector;
import org.apache.druid.k8s.overlord.taskadapter.MultiContainerTaskAdapter;
@@ -129,6 +130,7 @@ public class KubernetesOverlordModule implements DruidModule
.in(LazySingleton.class);
Jerseys.addResource(binder, KubernetesTaskExecutionConfigResource.class);
+ Jerseys.addResource(binder, KubernetesTaskRunnerPodTemplateResource.class);
PolyBind.createChoiceWithDefault(
binder,
diff --git
a/extensions-core/kubernetes-overlord-extensions/src/main/java/org/apache/druid/k8s/overlord/execution/KubernetesTaskRunnerPodTemplateResource.java
b/extensions-core/kubernetes-overlord-extensions/src/main/java/org/apache/druid/k8s/overlord/execution/KubernetesTaskRunnerPodTemplateResource.java
new file mode 100644
index 00000000000..d34413f58a5
--- /dev/null
+++
b/extensions-core/kubernetes-overlord-extensions/src/main/java/org/apache/druid/k8s/overlord/execution/KubernetesTaskRunnerPodTemplateResource.java
@@ -0,0 +1,77 @@
+/*
+ * 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.druid.k8s.overlord.execution;
+
+import com.sun.jersey.spi.container.ResourceFilters;
+import org.apache.druid.error.DruidException;
+import org.apache.druid.k8s.overlord.taskadapter.PodTemplateTaskAdapter;
+import org.apache.druid.k8s.overlord.taskadapter.TaskAdapter;
+import org.apache.druid.server.http.ServletResourceUtils;
+import org.apache.druid.server.http.security.ConfigResourceFilter;
+
+import javax.inject.Inject;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+/**
+ * Resource that exposes the names of the pod templates currently configured
for running peons in
+ * Kubernetes.
+ *
+ * <p>Pod templates only exist for the pod template adapter
("customTemplateAdapter"). For any other
+ * adapter this endpoint returns a 404.</p>
+ */
+@Path("/druid/indexer/v1/k8s/taskrunner/podTemplates")
+public class KubernetesTaskRunnerPodTemplateResource
+{
+ private final TaskAdapter taskAdapter;
+
+ @Inject
+ public KubernetesTaskRunnerPodTemplateResource(final TaskAdapter taskAdapter)
+ {
+ this.taskAdapter = taskAdapter;
+ }
+
+ /**
+ * Retrieves the names of the currently configured peon pod templates.
+ *
+ * @return a Response with the configured template names (200), or 404 when
the configured adapter
+ * has no pod templates.
+ */
+ @GET
+ @Produces(MediaType.APPLICATION_JSON)
+ @ResourceFilters(ConfigResourceFilter.class)
+ public Response getPodTemplateNames()
+ {
+ if (!(taskAdapter instanceof PodTemplateTaskAdapter)) {
+ return ServletResourceUtils.buildErrorResponseFrom(
+ DruidException.forPersona(DruidException.Persona.OPERATOR)
+ .ofCategory(DruidException.Category.NOT_FOUND)
+ .build(
+ "Pod templates are only available when the k8s
task adapter type is [%s]",
+ PodTemplateTaskAdapter.TYPE
+ )
+ );
+ }
+ return Response.ok(((PodTemplateTaskAdapter)
taskAdapter).getPodTemplateSelector().getPodTemplateNames()).build();
+ }
+}
diff --git
a/extensions-core/kubernetes-overlord-extensions/src/main/java/org/apache/druid/k8s/overlord/taskadapter/DynamicConfigPodTemplateSelector.java
b/extensions-core/kubernetes-overlord-extensions/src/main/java/org/apache/druid/k8s/overlord/taskadapter/DynamicConfigPodTemplateSelector.java
index 735eaf1dc5d..3ee10ae260b 100644
---
a/extensions-core/kubernetes-overlord-extensions/src/main/java/org/apache/druid/k8s/overlord/taskadapter/DynamicConfigPodTemplateSelector.java
+++
b/extensions-core/kubernetes-overlord-extensions/src/main/java/org/apache/druid/k8s/overlord/taskadapter/DynamicConfigPodTemplateSelector.java
@@ -32,8 +32,11 @@ import
org.apache.druid.k8s.overlord.common.DruidK8sConstants;
import java.io.File;
import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Properties;
import java.util.Set;
@@ -144,4 +147,12 @@ public class DynamicConfigPodTemplateSelector implements
PodTemplateSelector
return
Optional.of(effectiveConfig.getPodTemplateSelectStrategy().getPodTemplateForTask(task,
podTemplates));
}
+
+ @Override
+ public List<String> getPodTemplateNames()
+ {
+ List<String> names = new ArrayList<>(podTemplates.keySet());
+ Collections.sort(names);
+ return names;
+ }
}
diff --git
a/extensions-core/kubernetes-overlord-extensions/src/main/java/org/apache/druid/k8s/overlord/taskadapter/PodTemplateSelector.java
b/extensions-core/kubernetes-overlord-extensions/src/main/java/org/apache/druid/k8s/overlord/taskadapter/PodTemplateSelector.java
index 7795fe1eed4..e7f1a29ad26 100644
---
a/extensions-core/kubernetes-overlord-extensions/src/main/java/org/apache/druid/k8s/overlord/taskadapter/PodTemplateSelector.java
+++
b/extensions-core/kubernetes-overlord-extensions/src/main/java/org/apache/druid/k8s/overlord/taskadapter/PodTemplateSelector.java
@@ -22,6 +22,8 @@ package org.apache.druid.k8s.overlord.taskadapter;
import com.google.common.base.Optional;
import org.apache.druid.indexing.common.task.Task;
+import java.util.List;
+
/**
* Interface for selecting a Pod template based on a given task.
* Implementations of this interface are responsible for determining the
appropriate
@@ -37,4 +39,10 @@ public interface PodTemplateSelector
* is available for the given task.
*/
Optional<PodTemplateWithName> getPodTemplateForTask(Task task);
+
+ /**
+ * Returns the names of all currently configured pod templates.
+ * @return the configured template names.
+ */
+ List<String> getPodTemplateNames();
}
diff --git
a/extensions-core/kubernetes-overlord-extensions/src/main/java/org/apache/druid/k8s/overlord/taskadapter/PodTemplateTaskAdapter.java
b/extensions-core/kubernetes-overlord-extensions/src/main/java/org/apache/druid/k8s/overlord/taskadapter/PodTemplateTaskAdapter.java
index 0ad3385ca21..b7976e1dab3 100644
---
a/extensions-core/kubernetes-overlord-extensions/src/main/java/org/apache/druid/k8s/overlord/taskadapter/PodTemplateTaskAdapter.java
+++
b/extensions-core/kubernetes-overlord-extensions/src/main/java/org/apache/druid/k8s/overlord/taskadapter/PodTemplateTaskAdapter.java
@@ -103,6 +103,11 @@ public class PodTemplateTaskAdapter implements TaskAdapter
return TYPE;
}
+ public PodTemplateSelector getPodTemplateSelector()
+ {
+ return podTemplateSelector;
+ }
+
/**
* Create a {@link Job} from a {@link Task}
*
diff --git
a/extensions-core/kubernetes-overlord-extensions/src/test/java/org/apache/druid/k8s/overlord/execution/KubernetesTaskRunnerPodTemplateResourceTest.java
b/extensions-core/kubernetes-overlord-extensions/src/test/java/org/apache/druid/k8s/overlord/execution/KubernetesTaskRunnerPodTemplateResourceTest.java
new file mode 100644
index 00000000000..b24cadfcaaf
--- /dev/null
+++
b/extensions-core/kubernetes-overlord-extensions/src/test/java/org/apache/druid/k8s/overlord/execution/KubernetesTaskRunnerPodTemplateResourceTest.java
@@ -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.druid.k8s.overlord.execution;
+
+import com.google.common.collect.ImmutableList;
+import org.apache.druid.k8s.overlord.taskadapter.PodTemplateSelector;
+import org.apache.druid.k8s.overlord.taskadapter.PodTemplateTaskAdapter;
+import org.apache.druid.k8s.overlord.taskadapter.TaskAdapter;
+import org.easymock.EasyMock;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import javax.ws.rs.core.Response;
+import java.util.List;
+
+public class KubernetesTaskRunnerPodTemplateResourceTest
+{
+ @Test
+ public void test_getPodTemplateNames_returnsConfiguredTemplateNames()
+ {
+ List<String> names = ImmutableList.of("base", "index_kafka");
+
+ PodTemplateSelector selector =
EasyMock.createMock(PodTemplateSelector.class);
+ EasyMock.expect(selector.getPodTemplateNames()).andReturn(names);
+ PodTemplateTaskAdapter adapter =
EasyMock.createMock(PodTemplateTaskAdapter.class);
+ EasyMock.expect(adapter.getPodTemplateSelector()).andReturn(selector);
+ EasyMock.replay(selector, adapter);
+
+ Response result = new
KubernetesTaskRunnerPodTemplateResource(adapter).getPodTemplateNames();
+
+ Assertions.assertEquals(Response.Status.OK.getStatusCode(),
result.getStatus());
+ Assertions.assertEquals(names, result.getEntity());
+ }
+
+ @Test
+ public void
test_getPodTemplateNames_whenAdapterIsNotPodTemplateAdapter_returnsNotFound()
+ {
+ TaskAdapter adapter = EasyMock.createMock(TaskAdapter.class);
+ EasyMock.replay(adapter);
+
+ Response result = new
KubernetesTaskRunnerPodTemplateResource(adapter).getPodTemplateNames();
+
+ Assertions.assertEquals(Response.Status.NOT_FOUND.getStatusCode(),
result.getStatus());
+ }
+}
diff --git
a/extensions-core/kubernetes-overlord-extensions/src/test/java/org/apache/druid/k8s/overlord/taskadapter/DynamicConfigPodTemplateSelectorTest.java
b/extensions-core/kubernetes-overlord-extensions/src/test/java/org/apache/druid/k8s/overlord/taskadapter/DynamicConfigPodTemplateSelectorTest.java
index fbd0691efda..3c80f414516 100644
---
a/extensions-core/kubernetes-overlord-extensions/src/test/java/org/apache/druid/k8s/overlord/taskadapter/DynamicConfigPodTemplateSelectorTest.java
+++
b/extensions-core/kubernetes-overlord-extensions/src/test/java/org/apache/druid/k8s/overlord/taskadapter/DynamicConfigPodTemplateSelectorTest.java
@@ -49,6 +49,8 @@ import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
import java.util.Properties;
public class DynamicConfigPodTemplateSelectorTest
@@ -186,6 +188,25 @@ public class DynamicConfigPodTemplateSelectorTest
Assertions.assertEquals("base", podTemplateWithName.get().getName());
}
+ @Test
+ public void test_getPodTemplateNames() throws IOException
+ {
+ Path baseTemplatePath = Files.createFile(tempDir.resolve("base.yaml"));
+ mapper.writeValue(baseTemplatePath.toFile(), podTemplateSpec);
+
+ Path kafkaTemplatePath = Files.createFile(tempDir.resolve("kafka.yaml"));
+ mapper.writeValue(kafkaTemplatePath.toFile(), podTemplateSpec);
+
+ Properties props = new Properties();
+ props.setProperty("druid.indexer.runner.k8s.podTemplate.base",
baseTemplatePath.toString());
+ props.setProperty("druid.indexer.runner.k8s.podTemplate.index_kafka",
kafkaTemplatePath.toString());
+
+ DynamicConfigPodTemplateSelector selector = new
DynamicConfigPodTemplateSelector(props, effectiveConfig);
+
+ List<String> names = selector.getPodTemplateNames();
+ Assertions.assertEquals(Sets.newSet("base", "index_kafka"), new
HashSet<>(names));
+ }
+
@Test
public void
test_fromTask_withNoopPodTemplateInRuntimeProperties_withEmptyFile_raisesIAE()
throws IOException
{
diff --git
a/extensions-core/kubernetes-overlord-extensions/src/test/java/org/apache/druid/k8s/overlord/taskadapter/TestPodTemplateSelector.java
b/extensions-core/kubernetes-overlord-extensions/src/test/java/org/apache/druid/k8s/overlord/taskadapter/TestPodTemplateSelector.java
index 4c12c16f32b..02fd05b0b0b 100644
---
a/extensions-core/kubernetes-overlord-extensions/src/test/java/org/apache/druid/k8s/overlord/taskadapter/TestPodTemplateSelector.java
+++
b/extensions-core/kubernetes-overlord-extensions/src/test/java/org/apache/druid/k8s/overlord/taskadapter/TestPodTemplateSelector.java
@@ -23,6 +23,9 @@ import com.google.common.base.Optional;
import io.fabric8.kubernetes.api.model.PodTemplate;
import org.apache.druid.indexing.common.task.Task;
+import java.util.Collections;
+import java.util.List;
+
public class TestPodTemplateSelector implements PodTemplateSelector
{
@@ -38,4 +41,10 @@ public class TestPodTemplateSelector implements
PodTemplateSelector
{
return Optional.of(new PodTemplateWithName("base", basePodTemplate));
}
+
+ @Override
+ public List<String> getPodTemplateNames()
+ {
+ return Collections.singletonList("base");
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]