This is an automated email from the ASF dual-hosted git repository.
frankchen 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 fd451827d60 Support Lazy Loading of Pod Templates (#17701)
fd451827d60 is described below
commit fd451827d6031e1a77cc16d47cdb1a4cf8466ffa
Author: Virushade <[email protected]>
AuthorDate: Wed Feb 19 19:42:38 2025 +0800
Support Lazy Loading of Pod Templates (#17701)
* Lazy loading for PodTemplate to allow changing template files without
restarting.
* Revert accidental changes to inspectionProfiles/Druid.xml
* Checkstyle
* Add another example for pod template configuration, and for lazy loading
of pod templates
* Add tls port to example
* Add unit test for lazy pod template loading
* Fix spell-checks
* Allow k8s-jobs.md to dynamically take in Druid Version
* Update docs/development/extensions-core/k8s-jobs.md
Co-authored-by: Frank Chen <[email protected]>
* Update docs/development/extensions-core/k8s-jobs.md
Co-authored-by: Frank Chen <[email protected]>
* Add description for why Supplier is used
---------
Co-authored-by: Frank Chen <[email protected]>
---
docs/development/extensions-core/k8s-jobs.md | 137 ++++++++++++++++++---
.../execution/PodTemplateSelectStrategy.java | 3 +-
.../SelectorBasedPodTemplateSelectStrategy.java | 6 +-
.../TaskTypePodTemplateSelectStrategy.java | 6 +-
.../DynamicConfigPodTemplateSelector.java | 36 ++++--
.../taskadapter/PodTemplateTaskAdapter.java | 2 +-
...SelectorBasedPodTemplateSelectStrategyTest.java | 11 +-
.../DynamicConfigPodTemplateSelectorTest.java | 101 +++++++++++++--
8 files changed, 251 insertions(+), 51 deletions(-)
diff --git a/docs/development/extensions-core/k8s-jobs.md
b/docs/development/extensions-core/k8s-jobs.md
index 14134af94aa..8b6940ea1df 100644
--- a/docs/development/extensions-core/k8s-jobs.md
+++ b/docs/development/extensions-core/k8s-jobs.md
@@ -28,7 +28,7 @@ Consider this an [EXPERIMENTAL](../experimental.md) feature
mostly because it ha
## How it works
-The K8s extension builds a pod spec for each task using the specified pod
adapter. All jobs are natively restorable, they are decoupled from the Druid
deployment, thus restarting pods or doing upgrades has no affect on tasks in
flight. They will continue to run and when the overlord comes back up it will
start tracking them again.
+The K8s extension builds a pod spec for each task using the specified pod
adapter. All jobs are natively restorable, they are decoupled from the Druid
deployment, thus restarting pods or doing upgrades has no effect on tasks in
flight. They will continue to run and when the overlord comes back up it will
start tracking them again.
## Configuration
@@ -363,6 +363,19 @@ The custom template pod adapter allows you to specify a
pod template file per ta
The base pod template must be specified as the runtime property
`druid.indexer.runner.k8s.podTemplate.base: /path/to/basePodSpec.yaml`
+The below runtime properties need to be passed to the Job's peon process.
+
+```
+druid.port=8100 (what port the peon should run on)
+druid.peon.mode=remote
+druid.service=druid/peon (for metrics reporting)
+druid.indexer.task.baseTaskDir=/druid/data (this should match the argument to
the ./peon.sh run command in the PodTemplate)
+druid.indexer.runner.type=k8s
+druid.indexer.task.encapsulatedTask=true
+```
+
+#### Example 1: Using a Pod Template that retrieves values from a ConfigMap
+
<details>
<summary>Example Pod Template that uses the regular druid docker
image</summary>
@@ -372,7 +385,7 @@ kind: "PodTemplate"
template:
metadata:
annotations:
- sidecar.istio.io/proxyCPU: "512m" # to handle a injected istio sidecar
+ sidecar.istio.io/proxyCPU: "512m" # to handle an injected istio sidecar
labels:
app.kubernetes.io/name: "druid-realtime-backend"
spec:
@@ -436,28 +449,17 @@ template:
```
</details>
-The below runtime properties need to be passed to the Job's peon process.
-
-```
-druid.port=8100 (what port the peon should run on)
-druid.peon.mode=remote
-druid.service=druid/peon (for metrics reporting)
-druid.indexer.task.baseTaskDir=/druid/data (this should match the argument to
the ./peon.sh run command in the PodTemplate)
-druid.indexer.runner.type=k8s
-druid.indexer.task.encapsulatedTask=true
-```
-
-Any runtime property or JVM config used by the peon process can also be
passed. E.G. below is a example of a ConfigMap that can be used to generate the
`nodetype-config-volume` mount in the above template.
+Any runtime property or JVM config used by the peon process can also be
passed. E.G. below is an example of a ConfigMap that can be used to generate
the `nodetype-config-volume` mount in the above template.
<details>
<summary>Example ConfigMap</summary>
-```
+```yaml
+apiVersion: v1
kind: ConfigMap
metadata:
name: druid-tiny-cluster-peons-config
namespace: default
-apiVersion: v1
data:
jvm.config: |-
-server
@@ -494,8 +496,107 @@ data:
```
</details>
+#### Example 2: Using a ConfigMap to upload the Pod Template file
+
+Alternatively, we can mount the ConfigMap onto Overlord services, and use the
ConfigMap to generate the pod template files we want.
+
+<details>
+<summary>Mounting to Overlord deployment</summary>
+
+```yaml
+ volumeMounts:
+ - name: druid-pod-templates
+ mountPath: /path/to/podTemplate/directory
+
+ volumes:
+ - name: druid-pod-templates
+ configMap:
+ name: druid-pod-templates
+```
+</details>
+
+<details>
+<summary>Example ConfigMap that generates the Base Pod Template</summary>
+
+```yaml
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: druid-pod-templates
+data:
+ basePodSpec.yaml: |-
+ apiVersion: "v1"
+ kind: "PodTemplate"
+ template:
+ metadata:
+ labels:
+ app.kubernetes.io/name: "druid-realtime-backend"
+ annotations:
+ sidecar.istio.io/proxyCPU: "512m"
+ spec:
+ containers:
+ - name: main
+ image: apache/druid:{{DRUIDVERSION}}
+ command:
+ - sh
+ - -c
+ - |
+ /peon.sh /druid/data 1
+ env:
+ - name: druid_port
+ value: 8100
+ - name: druid_plaintextPort
+ value: 8100
+ - name: druid_tlsPort
+ value: 8091
+ - name: druid_peon_mode
+ value: remote
+ - name: druid_service
+ value: "druid/peon"
+ - name: druid_indexer_task_baseTaskDir
+ value: /druid/data
+ - name: druid_indexer_runner_type
+ value: k8s
+ - name: druid_indexer_task_encapsulatedTask
+ value: true
+ ports:
+ - containerPort: 8091
+ name: druid-tls-port
+ protocol: TCP
+ - containerPort: 8100
+ name: druid-port
+ protocol: TCP
+ resources:
+ limits:
+ cpu: "1"
+ memory: 2400M
+ requests:
+ cpu: "1"
+ memory: 2400M
+ restartPolicy: "Never"
+ securityContext:
+ fsGroup: 1000
+ runAsGroup: 1000
+ runAsUser: 1000
+ tolerations:
+ - effect: NoExecute
+ key: node.kubernetes.io/not-ready
+ operator: Exists
+ tolerationSeconds: 300
+ - effect: NoExecute
+ key: node.kubernetes.io/unreachable
+ operator: Exists
+ tolerationSeconds: 300
+
+```
+</details>
+
+#### Lazy Loading of Pod Templates
+
+Whenever the Overlord wants to spin up a Kubernetes task pod, it will first
read the relevant pod template file, and then create a task pod according to
the specifications of the pod template file. This is helpful when you want to
make configuration changes to the task pods (e.g. increase/decrease CPU limit
or resources). You can edit the pod template files directly, and the next task
pod spun up by the Overlord will reflect these changes in its configurations.
+
#### Pod template selection
-
+
The pod template adapter can select which pod template should be used for a
task using the [task runner execution config](#dynamic-config)
##### Select based on task type
@@ -512,7 +613,7 @@ Task specific pod templates can be specified as the runtime
property
`druid.indexer.runner.k8s.podTemplate.{taskType}:
/path/to/taskSpecificPodSpec.yaml` where {taskType} is the name of the
task type. For example, `index_parallel`.
-If you are trying to use the default image's environment variable parsing
feature to set runtime properties, you need to add a extra escape underscore
when specifying pod templates.
+If you are trying to use the default image's environment variable parsing
feature to set runtime properties, you need to add an extra escape underscore
when specifying pod templates.
For example, set the environment variable
`druid_indexer_runner_k8s_podTemplate_index__kafka` when you set the runtime
property `druid.indexer.runner.k8s.podTemplate.index_kafka`
diff --git
a/extensions-core/kubernetes-overlord-extensions/src/main/java/org/apache/druid/k8s/overlord/execution/PodTemplateSelectStrategy.java
b/extensions-core/kubernetes-overlord-extensions/src/main/java/org/apache/druid/k8s/overlord/execution/PodTemplateSelectStrategy.java
index 885a4e3e59a..6548675e41f 100644
---
a/extensions-core/kubernetes-overlord-extensions/src/main/java/org/apache/druid/k8s/overlord/execution/PodTemplateSelectStrategy.java
+++
b/extensions-core/kubernetes-overlord-extensions/src/main/java/org/apache/druid/k8s/overlord/execution/PodTemplateSelectStrategy.java
@@ -21,6 +21,7 @@ package org.apache.druid.k8s.overlord.execution;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.google.common.base.Supplier;
import io.fabric8.kubernetes.api.model.PodTemplate;
import org.apache.druid.indexing.common.task.Task;
import org.apache.druid.k8s.overlord.taskadapter.PodTemplateWithName;
@@ -45,5 +46,5 @@ public interface PodTemplateSelectStrategy
* @param task The task for which the Pod template is determined.
* @return The PodTemplateWithName POJO that contains the name of the
template selected and the template itself.
*/
- @NotNull PodTemplateWithName getPodTemplateForTask(Task task, Map<String,
PodTemplate> templates);
+ @NotNull PodTemplateWithName getPodTemplateForTask(Task task, Map<String,
Supplier<PodTemplate>> templates);
}
diff --git
a/extensions-core/kubernetes-overlord-extensions/src/main/java/org/apache/druid/k8s/overlord/execution/SelectorBasedPodTemplateSelectStrategy.java
b/extensions-core/kubernetes-overlord-extensions/src/main/java/org/apache/druid/k8s/overlord/execution/SelectorBasedPodTemplateSelectStrategy.java
index bf3082a79b1..f760a9ff426 100644
---
a/extensions-core/kubernetes-overlord-extensions/src/main/java/org/apache/druid/k8s/overlord/execution/SelectorBasedPodTemplateSelectStrategy.java
+++
b/extensions-core/kubernetes-overlord-extensions/src/main/java/org/apache/druid/k8s/overlord/execution/SelectorBasedPodTemplateSelectStrategy.java
@@ -22,6 +22,7 @@ package org.apache.druid.k8s.overlord.execution;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.base.Preconditions;
+import com.google.common.base.Supplier;
import io.fabric8.kubernetes.api.model.PodTemplate;
import org.apache.druid.indexing.common.task.Task;
import org.apache.druid.k8s.overlord.common.DruidK8sConstants;
@@ -55,7 +56,7 @@ public class SelectorBasedPodTemplateSelectStrategy
implements PodTemplateSelect
* @return the template if a selector matches, otherwise fallback to base
template
*/
@Override
- public PodTemplateWithName getPodTemplateForTask(Task task, Map<String,
PodTemplate> templates)
+ public PodTemplateWithName getPodTemplateForTask(Task task, Map<String,
Supplier<PodTemplate>> templates)
{
String templateKey = selectors.stream()
.filter(selector -> selector.evaluate(task))
@@ -66,7 +67,8 @@ public class SelectorBasedPodTemplateSelectStrategy
implements PodTemplateSelect
if (!templates.containsKey(templateKey)) {
templateKey = DruidK8sConstants.BASE_TEMPLATE_NAME;
}
- return new PodTemplateWithName(templateKey, templates.get(templateKey));
+ Supplier<PodTemplate> podTemplateSupplier = templates.get(templateKey);
+ return new PodTemplateWithName(templateKey, podTemplateSupplier.get());
}
@JsonProperty
diff --git
a/extensions-core/kubernetes-overlord-extensions/src/main/java/org/apache/druid/k8s/overlord/execution/TaskTypePodTemplateSelectStrategy.java
b/extensions-core/kubernetes-overlord-extensions/src/main/java/org/apache/druid/k8s/overlord/execution/TaskTypePodTemplateSelectStrategy.java
index bda7788e3c4..7635970bad1 100644
---
a/extensions-core/kubernetes-overlord-extensions/src/main/java/org/apache/druid/k8s/overlord/execution/TaskTypePodTemplateSelectStrategy.java
+++
b/extensions-core/kubernetes-overlord-extensions/src/main/java/org/apache/druid/k8s/overlord/execution/TaskTypePodTemplateSelectStrategy.java
@@ -20,6 +20,7 @@
package org.apache.druid.k8s.overlord.execution;
import com.fasterxml.jackson.annotation.JsonCreator;
+import com.google.common.base.Supplier;
import io.fabric8.kubernetes.api.model.PodTemplate;
import org.apache.druid.indexing.common.task.Task;
import org.apache.druid.k8s.overlord.common.DruidK8sConstants;
@@ -42,10 +43,11 @@ public class TaskTypePodTemplateSelectStrategy implements
PodTemplateSelectStrat
}
@Override
- public PodTemplateWithName getPodTemplateForTask(Task task, Map<String,
PodTemplate> templates)
+ public PodTemplateWithName getPodTemplateForTask(Task task, Map<String,
Supplier<PodTemplate>> templates)
{
String templateKey = templates.containsKey(task.getType()) ?
task.getType() : DruidK8sConstants.BASE_TEMPLATE_NAME;
- return new PodTemplateWithName(templateKey, templates.get(templateKey));
+ Supplier<PodTemplate> podSupplier = templates.get(templateKey);
+ return new PodTemplateWithName(templateKey, podSupplier.get());
}
@Override
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 a42f6e6e242..92832b2ff66 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
@@ -43,8 +43,9 @@ public class DynamicConfigPodTemplateSelector implements
PodTemplateSelector
+ ".k8s.podTemplate.";
private final Properties properties;
- private HashMap<String, PodTemplate> podTemplates;
- private Supplier<KubernetesTaskRunnerDynamicConfig> dynamicConfigRef;
+ private final Supplier<KubernetesTaskRunnerDynamicConfig> dynamicConfigRef;
+ // Supplier allows Overlord to read the most recent pod template file
without calling initializeTemplatesFromFileSystem() again.
+ private HashMap<String, Supplier<PodTemplate>> podTemplates;
public DynamicConfigPodTemplateSelector(
Properties properties,
@@ -56,25 +57,25 @@ public class DynamicConfigPodTemplateSelector implements
PodTemplateSelector
initializeTemplatesFromFileSystem();
}
- private void initializeTemplatesFromFileSystem()
+ private void initializeTemplatesFromFileSystem() throws IAE
{
- Set<String> taskAdapterTemplateKeys = getTaskAdapterTemplates(properties);
+ Set<String> taskAdapterTemplateKeys =
getTaskAdapterTemplatesKeys(properties);
if (!taskAdapterTemplateKeys.contains("base")) {
throw new IAE(
"Pod template task adapter requires a base pod template to be
specified under druid.indexer.runner.k8s.podTemplate.base");
}
- HashMap<String, PodTemplate> podTemplateMap = new HashMap<>();
+ HashMap<String, Supplier<PodTemplate>> podTemplateMap = new HashMap<>();
for (String taskAdapterTemplateKey : taskAdapterTemplateKeys) {
- Optional<PodTemplate> template = loadPodTemplate(taskAdapterTemplateKey,
properties);
- if (template.isPresent()) {
- podTemplateMap.put(taskAdapterTemplateKey, template.get());
- }
+ Supplier<PodTemplate> templateSupplier = () ->
loadPodTemplate(taskAdapterTemplateKey, properties);
+ validateTemplateSupplier(templateSupplier);
+ podTemplateMap.put(taskAdapterTemplateKey, templateSupplier);
}
+
podTemplates = podTemplateMap;
}
- private Set<String> getTaskAdapterTemplates(Properties properties)
+ private Set<String> getTaskAdapterTemplatesKeys(Properties properties)
{
Set<String> taskAdapterTemplates = new HashSet<>();
@@ -88,25 +89,34 @@ public class DynamicConfigPodTemplateSelector implements
PodTemplateSelector
return taskAdapterTemplates;
}
- private Optional<PodTemplate> loadPodTemplate(String key, Properties
properties)
+ private PodTemplate loadPodTemplate(String key, Properties properties)
throws IAE
{
String property = TASK_PROPERTY + key;
String podTemplateFile = properties.getProperty(property);
if (podTemplateFile == null) {
throw new IAE("Pod template file not specified for [%s]", property);
-
}
+
try {
- return Optional.of(Serialization.unmarshal(
+ // Use Optional to assert unmarshal result is non-null.
+ Optional<PodTemplate> maybeTemplate =
Optional.of(Serialization.unmarshal(
Files.newInputStream(new File(podTemplateFile).toPath()),
PodTemplate.class
));
+
+ return maybeTemplate.get();
}
catch (Exception e) {
throw new IAE(e, "Failed to load pod template file for [%s] at [%s]",
property, podTemplateFile);
}
}
+ @SuppressWarnings("ResultOfMethodCallIgnored")
+ private void validateTemplateSupplier(Supplier<PodTemplate>
templateSupplier) throws IAE
+ {
+ templateSupplier.get();
+ }
+
@Override
public Optional<PodTemplateWithName> getPodTemplateForTask(Task task)
{
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 929f7ac1e7d..168d944bfd8 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
@@ -120,7 +120,7 @@ public class PodTemplateTaskAdapter implements TaskAdapter
task.getId()
);
}
- PodTemplateWithName podTemplateWithName =
podTemplateSelector.getPodTemplateForTask(task).get();
+ PodTemplateWithName podTemplateWithName = selectedPodTemplate.get();
return new JobBuilder()
.withNewMetadata()
diff --git
a/extensions-core/kubernetes-overlord-extensions/src/test/java/org/apache/druid/k8s/overlord/execution/SelectorBasedPodTemplateSelectStrategyTest.java
b/extensions-core/kubernetes-overlord-extensions/src/test/java/org/apache/druid/k8s/overlord/execution/SelectorBasedPodTemplateSelectStrategyTest.java
index 81589c75128..00b3096074f 100644
---
a/extensions-core/kubernetes-overlord-extensions/src/test/java/org/apache/druid/k8s/overlord/execution/SelectorBasedPodTemplateSelectStrategyTest.java
+++
b/extensions-core/kubernetes-overlord-extensions/src/test/java/org/apache/druid/k8s/overlord/execution/SelectorBasedPodTemplateSelectStrategyTest.java
@@ -20,6 +20,7 @@
package org.apache.druid.k8s.overlord.execution;
import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
@@ -41,14 +42,14 @@ import java.util.Set;
public class SelectorBasedPodTemplateSelectStrategyTest
{
- private Map<String, PodTemplate> templates;
+ private Map<String, Supplier<PodTemplate>> templates;
@Before
public void setup()
{
templates = ImmutableMap.of(
"mock",
- new PodTemplate(null, null, new ObjectMeta()
+ () -> new PodTemplate(null, null, new ObjectMeta()
{
@Override
public String getName()
@@ -57,7 +58,7 @@ public class SelectorBasedPodTemplateSelectStrategyTest
}
}, null),
"no_match",
- new PodTemplate(null, null, new ObjectMeta()
+ () -> new PodTemplate(null, null, new ObjectMeta()
{
@Override
public String getName()
@@ -66,7 +67,7 @@ public class SelectorBasedPodTemplateSelectStrategyTest
}
}, null),
"match",
- new PodTemplate(null, null, new ObjectMeta()
+ () -> new PodTemplate(null, null, new ObjectMeta()
{
@Override
public String getName()
@@ -75,7 +76,7 @@ public class SelectorBasedPodTemplateSelectStrategyTest
}
}, null),
"base",
- new PodTemplate(null, "base", new ObjectMeta()
+ () -> new PodTemplate(null, "base", new ObjectMeta()
{
@Override
public String getName()
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 0ac7e0ef55a..106a98fa6a8 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
@@ -70,10 +70,14 @@ public class DynamicConfigPodTemplateSelectorTest
"No base prop should throw an IAE",
IAE.class,
() -> new DynamicConfigPodTemplateSelector(
- new Properties(),
- dynamicConfigRef
- ));
- Assertions.assertEquals(exception.getMessage(), "Pod template task adapter
requires a base pod template to be specified under
druid.indexer.runner.k8s.podTemplate.base");
+ new Properties(),
+ dynamicConfigRef
+ )
+ );
+ Assertions.assertEquals(
+ exception.getMessage(),
+ "Pod template task adapter requires a base pod template to be
specified under druid.indexer.runner.k8s.podTemplate.base"
+ );
}
@Test
@@ -90,7 +94,8 @@ public class DynamicConfigPodTemplateSelectorTest
() -> new DynamicConfigPodTemplateSelector(
props,
dynamicConfigRef
- ));
+ )
+ );
Assertions.assertTrue(exception.getMessage().contains("Failed to load pod
template file for"));
}
@@ -144,7 +149,8 @@ public class DynamicConfigPodTemplateSelectorTest
dynamicConfigRef
);
- Task kafkaTask = new NoopTask("id", "id", "datasource", 0, 0, null) {
+ Task kafkaTask = new NoopTask("id", "id", "datasource", 0, 0, null)
+ {
@Override
public String getType()
{
@@ -155,13 +161,21 @@ public class DynamicConfigPodTemplateSelectorTest
Task noopTask = new NoopTask("id", "id", "datasource", 0, 0, null);
Optional<PodTemplateWithName> podTemplateWithName =
selector.getPodTemplateForTask(kafkaTask);
Assertions.assertTrue(podTemplateWithName.isPresent());
- Assertions.assertEquals(1,
podTemplateWithName.get().getPodTemplate().getTemplate().getSpec().getVolumes().size(),
1);
+ Assertions.assertEquals(
+ 1,
+
podTemplateWithName.get().getPodTemplate().getTemplate().getSpec().getVolumes().size(),
+ 1
+ );
Assertions.assertEquals("index_kafka",
podTemplateWithName.get().getName());
podTemplateWithName = selector.getPodTemplateForTask(noopTask);
Assertions.assertTrue(podTemplateWithName.isPresent());
- Assertions.assertEquals(0,
podTemplateWithName.get().getPodTemplate().getTemplate().getSpec().getVolumes().size(),
1);
+ Assertions.assertEquals(
+ 0,
+
podTemplateWithName.get().getPodTemplate().getTemplate().getSpec().getVolumes().size(),
+ 1
+ );
Assertions.assertEquals("base", podTemplateWithName.get().getName());
}
@@ -230,7 +244,7 @@ public class DynamicConfigPodTemplateSelectorTest
props.setProperty("druid.indexer.runner.k8s.podTemplate.lowThroughput",
lowThroughputTemplatePath.toString());
dynamicConfigRef = () -> new DefaultKubernetesTaskRunnerDynamicConfig(new
SelectorBasedPodTemplateSelectStrategy(
Collections.singletonList(
- new Selector("lowThrougput", null, null, Sets.newSet(dataSource)
+ new Selector("lowThroughput", null, null, Sets.newSet(dataSource)
)
)
));
@@ -250,4 +264,73 @@ public class DynamicConfigPodTemplateSelectorTest
Assertions.assertTrue(actual.isPresent());
Assertions.assertEquals(0,
actual.get().getPodTemplate().getTemplate().getSpec().getVolumes().size(), 1);
}
+
+ @Test
+ public void test_fromTask_LazyLoadInvalidPodTemplateThrowsError() throws
IOException
+ {
+ Path baseTemplatePath = Files.createFile(tempDir.resolve("base.yaml"));
+ mapper.writeValue(baseTemplatePath.toFile(), podTemplateSpec);
+
+ Properties props = new Properties();
+ props.setProperty("druid.indexer.runner.k8s.podTemplate.base",
baseTemplatePath.toString());
+
+ DynamicConfigPodTemplateSelector adapter = new
DynamicConfigPodTemplateSelector(
+ props,
+ dynamicConfigRef
+ );
+
+ Task task = new NoopTask("id", "id", "datasource", 0, 0, null);
+ Optional<PodTemplateWithName> actual = adapter.getPodTemplateForTask(task);
+ PodTemplate expected =
K8sTestUtils.fileToResource("expectedNoopPodTemplate.yaml", PodTemplate.class);
+
+ Assertions.assertTrue(actual.isPresent());
+ Assertions.assertEquals("base", actual.get().getName());
+ Assertions.assertEquals(expected, actual.get().getPodTemplate());
+
+ // Now we change the file to an empty file, and expect an assertion.
+ mapper.writeValue(baseTemplatePath.toFile(), null);
+
+ Exception exception = Assert.assertThrows(
+ "Empty base pod template should throw a exception",
+ IAE.class,
+ () -> adapter.getPodTemplateForTask(task)
+ );
+
+ Assertions.assertTrue(exception.getMessage().contains("Failed to load pod
template file"));
+ }
+
+ @Test
+ public void test_fromTask_LazyLoadPodTemplateChangesPodSpecs() throws
IOException
+ {
+ Path baseTemplatePath = Files.createFile(tempDir.resolve("base.yaml"));
+ PodTemplate initialPodTemplate =
K8sTestUtils.fileToResource("ephemeralPodSpec.yaml", PodTemplate.class);
+ mapper.writeValue(baseTemplatePath.toFile(), initialPodTemplate);
+
+ Properties props = new Properties();
+ props.setProperty("druid.indexer.runner.k8s.podTemplate.base",
baseTemplatePath.toString());
+
+ DynamicConfigPodTemplateSelector adapter = new
DynamicConfigPodTemplateSelector(
+ props,
+ dynamicConfigRef
+ );
+
+ Task task = new NoopTask("id", "id", "datasource", 0, 0, null);
+ Optional<PodTemplateWithName> actual = adapter.getPodTemplateForTask(task);
+
+ // Suppose our current pod template does not match with this expected
result.
+ PodTemplate expected =
K8sTestUtils.fileToResource("expectedNoopPodTemplate.yaml", PodTemplate.class);
+
+ Assertions.assertTrue(actual.isPresent());
+ Assertions.assertEquals("base", actual.get().getName());
+ Assertions.assertNotEquals(expected, actual.get().getPodTemplate());
+
+ // Check if we can match out expected results after we change the pod
template file.
+ PodTemplate editedPodTemplate = podTemplateSpec;
+ mapper.writeValue(baseTemplatePath.toFile(), editedPodTemplate);
+ actual = adapter.getPodTemplateForTask(task);
+
+ Assertions.assertTrue(actual.isPresent());
+ Assertions.assertEquals("base", actual.get().getName());
+ Assertions.assertEquals(expected, actual.get().getPodTemplate());
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]