Skip to content

Commit 7b61748

Browse files
George Shiqi WuFrankChen021
George Shiqi Wu
authored andcommitted
Add annotation for pod template (#16772)
* Add annotation for pod template * pr comments * add test cases * add tests
1 parent 4baeb36 commit 7b61748

15 files changed

+291
-14
lines changed

extensions-contrib/kubernetes-overlord-extensions/src/main/java/org/apache/druid/k8s/overlord/common/DruidK8sConstants.java

+2
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ public class DruidK8sConstants
2828
public static final String TASK_TYPE = "task.type";
2929
public static final String TASK_GROUP_ID = "task.group.id";
3030
public static final String TASK_DATASOURCE = "task.datasource";
31+
public static final String TASK_JOB_TEMPLATE = "task.jobTemplate";
3132
public static final int PORT = 8100;
3233
public static final int TLS_PORT = 8091;
3334
public static final int DEFAULT_CPU_MILLICORES = 1000;
@@ -42,6 +43,7 @@ public class DruidK8sConstants
4243
public static final String DRUID_HOSTNAME_ENV = "HOSTNAME";
4344
public static final String LABEL_KEY = "druid.k8s.peons";
4445
public static final String DRUID_LABEL_PREFIX = "druid.";
46+
public static final String BASE_TEMPLATE_NAME = "base";
4547
public static final long MAX_ENV_VARIABLE_KBS = 130048; // 127 KB
4648
static final Predicate<Throwable> IS_TRANSIENT = e -> e instanceof KubernetesResourceNotFoundException;
4749
}

extensions-contrib/kubernetes-overlord-extensions/src/main/java/org/apache/druid/k8s/overlord/execution/PodTemplateSelectStrategy.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import com.fasterxml.jackson.annotation.JsonTypeInfo;
2424
import io.fabric8.kubernetes.api.model.PodTemplate;
2525
import org.apache.druid.indexing.common.task.Task;
26+
import org.apache.druid.k8s.overlord.taskadapter.PodTemplateWithName;
2627

2728
import javax.validation.constraints.NotNull;
2829
import java.util.Map;
@@ -42,7 +43,7 @@ public interface PodTemplateSelectStrategy
4243
* allows for customized resource allocation and management tailored to the task's specific requirements.
4344
*
4445
* @param task The task for which the Pod template is determined.
45-
* @return The pod template that should be used to run the task.
46+
* @return The PodTemplateWithName POJO that contains the name of the template selected and the template itself.
4647
*/
47-
@NotNull PodTemplate getPodTemplateForTask(Task task, Map<String, PodTemplate> templates);
48+
@NotNull PodTemplateWithName getPodTemplateForTask(Task task, Map<String, PodTemplate> templates);
4849
}

extensions-contrib/kubernetes-overlord-extensions/src/main/java/org/apache/druid/k8s/overlord/execution/SelectorBasedPodTemplateSelectStrategy.java

+8-3
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
import com.google.common.base.Preconditions;
2525
import io.fabric8.kubernetes.api.model.PodTemplate;
2626
import org.apache.druid.indexing.common.task.Task;
27+
import org.apache.druid.k8s.overlord.common.DruidK8sConstants;
28+
import org.apache.druid.k8s.overlord.taskadapter.PodTemplateWithName;
2729

2830
import java.util.List;
2931
import java.util.Map;
@@ -53,15 +55,18 @@ public SelectorBasedPodTemplateSelectStrategy(
5355
* @return the template if a selector matches, otherwise fallback to base template
5456
*/
5557
@Override
56-
public PodTemplate getPodTemplateForTask(Task task, Map<String, PodTemplate> templates)
58+
public PodTemplateWithName getPodTemplateForTask(Task task, Map<String, PodTemplate> templates)
5759
{
5860
String templateKey = selectors.stream()
5961
.filter(selector -> selector.evaluate(task))
6062
.findFirst()
6163
.map(Selector::getSelectionKey)
62-
.orElse("base");
64+
.orElse(DruidK8sConstants.BASE_TEMPLATE_NAME);
6365

64-
return templates.getOrDefault(templateKey, templates.get("base"));
66+
if (!templates.containsKey(templateKey)) {
67+
templateKey = DruidK8sConstants.BASE_TEMPLATE_NAME;
68+
}
69+
return new PodTemplateWithName(templateKey, templates.get(templateKey));
6570
}
6671

6772
@JsonProperty

extensions-contrib/kubernetes-overlord-extensions/src/main/java/org/apache/druid/k8s/overlord/execution/TaskTypePodTemplateSelectStrategy.java

+5-2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
import com.fasterxml.jackson.annotation.JsonCreator;
2323
import io.fabric8.kubernetes.api.model.PodTemplate;
2424
import org.apache.druid.indexing.common.task.Task;
25+
import org.apache.druid.k8s.overlord.common.DruidK8sConstants;
26+
import org.apache.druid.k8s.overlord.taskadapter.PodTemplateWithName;
2527

2628
import java.util.Map;
2729

@@ -40,9 +42,10 @@ public TaskTypePodTemplateSelectStrategy()
4042
}
4143

4244
@Override
43-
public PodTemplate getPodTemplateForTask(Task task, Map<String, PodTemplate> templates)
45+
public PodTemplateWithName getPodTemplateForTask(Task task, Map<String, PodTemplate> templates)
4446
{
45-
return templates.getOrDefault(task.getType(), templates.get("base"));
47+
String templateKey = templates.containsKey(task.getType()) ? task.getType() : DruidK8sConstants.BASE_TEMPLATE_NAME;
48+
return new PodTemplateWithName(templateKey, templates.get(templateKey));
4649
}
4750

4851
@Override

extensions-contrib/kubernetes-overlord-extensions/src/main/java/org/apache/druid/k8s/overlord/taskadapter/PodTemplateTaskAdapter.java

+4-2
Original file line numberDiff line numberDiff line change
@@ -138,19 +138,21 @@ public Job fromTask(Task task) throws IOException
138138
podTemplateSelectStrategy = dynamicConfig.getPodTemplateSelectStrategy();
139139
}
140140

141-
PodTemplate podTemplate = podTemplateSelectStrategy.getPodTemplateForTask(task, templates);
141+
PodTemplateWithName podTemplateWithName = podTemplateSelectStrategy.getPodTemplateForTask(task, templates);
142142

143143
return new JobBuilder()
144144
.withNewMetadata()
145145
.withName(new K8sTaskId(task).getK8sJobName())
146146
.addToLabels(getJobLabels(taskRunnerConfig, task))
147147
.addToAnnotations(getJobAnnotations(taskRunnerConfig, task))
148+
.addToAnnotations(DruidK8sConstants.TASK_JOB_TEMPLATE, podTemplateWithName.getName())
148149
.endMetadata()
149150
.withNewSpec()
150-
.withTemplate(podTemplate.getTemplate())
151+
.withTemplate(podTemplateWithName.getPodTemplate().getTemplate())
151152
.editTemplate()
152153
.editOrNewMetadata()
153154
.addToAnnotations(getPodTemplateAnnotations(task))
155+
.addToAnnotations(DruidK8sConstants.TASK_JOB_TEMPLATE, podTemplateWithName.getName())
154156
.addToLabels(getPodLabels(taskRunnerConfig, task))
155157
.endMetadata()
156158
.editSpec()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.apache.druid.k8s.overlord.taskadapter;
21+
22+
import io.fabric8.kubernetes.api.model.PodTemplate;
23+
24+
import javax.annotation.Nonnull;
25+
import java.util.Objects;
26+
27+
public class PodTemplateWithName
28+
{
29+
private final String name;
30+
private final PodTemplate podTemplate;
31+
32+
public PodTemplateWithName(String name, PodTemplate podTemplate)
33+
{
34+
this.name = name;
35+
this.podTemplate = podTemplate;
36+
}
37+
38+
@Nonnull
39+
public String getName()
40+
{
41+
return name;
42+
}
43+
44+
@Nonnull
45+
public PodTemplate getPodTemplate()
46+
{
47+
return podTemplate;
48+
}
49+
50+
@Override
51+
public boolean equals(Object o)
52+
{
53+
if (this == o) {
54+
return true;
55+
}
56+
if (o == null || getClass() != o.getClass()) {
57+
return false;
58+
}
59+
PodTemplateWithName that = (PodTemplateWithName) o;
60+
return Objects.equals(name, that.name) &&
61+
Objects.equals(podTemplate, that.podTemplate);
62+
}
63+
64+
@Override
65+
public int hashCode()
66+
{
67+
return Objects.hash(name, podTemplate);
68+
}
69+
70+
@Override
71+
public String toString()
72+
{
73+
return "PodTemplateWithName{" +
74+
"name='" + name + '\'' +
75+
", podTemplate=" + podTemplate +
76+
'}';
77+
}
78+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.apache.druid.k8s.overlord.common;
21+
22+
import io.fabric8.kubernetes.api.model.PodTemplate;
23+
import io.fabric8.kubernetes.api.model.PodTemplateBuilder;
24+
import org.apache.druid.k8s.overlord.taskadapter.PodTemplateWithName;
25+
import org.junit.jupiter.api.Test;
26+
27+
import static org.junit.jupiter.api.Assertions.assertEquals;
28+
import static org.junit.jupiter.api.Assertions.assertNotEquals;
29+
30+
public class PodTemplateWithNameTest
31+
{
32+
@Test
33+
void testEqualityToMakeCoverageHappy()
34+
{
35+
PodTemplateWithName podTemplateWithName = new PodTemplateWithName(
36+
"name",
37+
new PodTemplateBuilder().build()
38+
);
39+
PodTemplateWithName podTemplateWithName2 = podTemplateWithName;
40+
41+
assertEquals(podTemplateWithName, podTemplateWithName2);
42+
assertNotEquals(podTemplateWithName, null);
43+
assertNotEquals(podTemplateWithName, "string");
44+
assertEquals(podTemplateWithName.hashCode(), podTemplateWithName2.hashCode());
45+
}
46+
47+
@Test
48+
void testGettersToMakeCoverageHappy()
49+
{
50+
String name = "name";
51+
PodTemplate podTemplate = new PodTemplateBuilder().build();
52+
PodTemplateWithName podTemplateWithName = new PodTemplateWithName(
53+
name,
54+
podTemplate
55+
);
56+
57+
assertEquals(name, podTemplateWithName.getName());
58+
assertEquals(podTemplate, podTemplateWithName.getPodTemplate());
59+
}
60+
}

extensions-contrib/kubernetes-overlord-extensions/src/test/java/org/apache/druid/k8s/overlord/execution/SelectorBasedPodTemplateSelectStrategyTest.java

+11-3
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import io.fabric8.kubernetes.api.model.PodTemplate;
2828
import org.apache.druid.indexing.common.task.NoopTask;
2929
import org.apache.druid.indexing.common.task.Task;
30+
import org.apache.druid.k8s.overlord.taskadapter.PodTemplateWithName;
3031
import org.apache.druid.segment.TestHelper;
3132
import org.junit.Assert;
3233
import org.junit.Before;
@@ -97,7 +98,10 @@ public void testGetPodTemplate_ForTask_emptySelectorsFallbackToBaseTemplate()
9798
List<Selector> emptySelectors = Collections.emptyList();
9899
SelectorBasedPodTemplateSelectStrategy strategy = new SelectorBasedPodTemplateSelectStrategy(emptySelectors);
99100
Task task = NoopTask.create();
100-
Assert.assertEquals("base", strategy.getPodTemplateForTask(task, templates).getMetadata().getName());
101+
PodTemplateWithName podTemplateWithName = strategy.getPodTemplateForTask(task, templates);
102+
Assert.assertEquals("base", podTemplateWithName.getName());
103+
Assert.assertEquals("base", podTemplateWithName.getPodTemplate().getMetadata().getName());
104+
101105
}
102106

103107
@Test
@@ -107,7 +111,9 @@ public void testGetPodTemplate_ForTask_noMatchSelectorsFallbackToBaseTemplateIfN
107111
List<Selector> selectors = Collections.singletonList(noMatchSelector);
108112
SelectorBasedPodTemplateSelectStrategy strategy = new SelectorBasedPodTemplateSelectStrategy(selectors);
109113
Task task = NoopTask.create();
110-
Assert.assertEquals("base", strategy.getPodTemplateForTask(task, templates).getMetadata().getName());
114+
PodTemplateWithName podTemplateWithName = strategy.getPodTemplateForTask(task, templates);
115+
Assert.assertEquals("base", podTemplateWithName.getName());
116+
Assert.assertEquals("base", podTemplateWithName.getPodTemplate().getMetadata().getName());
111117
}
112118

113119
@Test
@@ -124,7 +130,9 @@ public void testGetPodTemplate_ForTask_withMatchSelectors()
124130
);
125131
SelectorBasedPodTemplateSelectStrategy strategy = new SelectorBasedPodTemplateSelectStrategy(selectors);
126132
Task task = NoopTask.create();
127-
Assert.assertEquals("match", strategy.getPodTemplateForTask(task, templates).getMetadata().getName());
133+
PodTemplateWithName podTemplateWithName = strategy.getPodTemplateForTask(task, templates);
134+
Assert.assertEquals("match", podTemplateWithName.getName());
135+
Assert.assertEquals("match", podTemplateWithName.getPodTemplate().getMetadata().getName());
128136
}
129137

130138
@Test

extensions-contrib/kubernetes-overlord-extensions/src/test/java/org/apache/druid/k8s/overlord/taskadapter/PodTemplateTaskAdapterTest.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ public void test_fromTask_withBasePodTemplateInRuntimeProperites() throws IOExce
172172
null
173173
);
174174
Job actual = adapter.fromTask(task);
175-
Job expected = K8sTestUtils.fileToResource("expectedNoopJob.yaml", Job.class);
175+
Job expected = K8sTestUtils.fileToResource("expectedNoopJobBase.yaml", Job.class);
176176

177177
assertJobSpecsEqual(actual, expected);
178178
}
@@ -216,7 +216,7 @@ public void test_fromTask_withBasePodTemplateInRuntimeProperites_andTlsEnabled()
216216
);
217217

218218
Job actual = adapter.fromTask(task);
219-
Job expected = K8sTestUtils.fileToResource("expectedNoopJobTlsEnabled.yaml", Job.class);
219+
Job expected = K8sTestUtils.fileToResource("expectedNoopJobTlsEnabledBase.yaml", Job.class);
220220

221221
assertJobSpecsEqual(actual, expected);
222222
}

extensions-contrib/kubernetes-overlord-extensions/src/test/resources/expectedNoopJob.yaml

+3
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,13 @@ metadata:
88
druid.task.type: "noop"
99
druid.task.group.id: "id"
1010
druid.task.datasource: "datasource"
11+
1112
annotations:
1213
task.id: "id"
1314
task.type: "noop"
1415
task.group.id: "id"
1516
task.datasource: "datasource"
17+
task.jobTemplate: noop
1618
spec:
1719
activeDeadlineSeconds: 14400
1820
backoffLimit: 0
@@ -32,6 +34,7 @@ spec:
3234
task.type: "noop"
3335
task.group.id: "id"
3436
task.datasource: "datasource"
37+
task.jobTemplate: noop
3538
spec:
3639
containers:
3740
- command:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
apiVersion: batch/v1
2+
kind: Job
3+
metadata:
4+
name: "id-3e70afe5cd823dfc7dd308eea616426b"
5+
labels:
6+
druid.k8s.peons: "true"
7+
druid.task.id: "id"
8+
druid.task.type: "noop"
9+
druid.task.group.id: "id"
10+
druid.task.datasource: "datasource"
11+
12+
annotations:
13+
task.id: "id"
14+
task.type: "noop"
15+
task.group.id: "id"
16+
task.datasource: "datasource"
17+
task.jobTemplate: base
18+
spec:
19+
activeDeadlineSeconds: 14400
20+
backoffLimit: 0
21+
ttlSecondsAfterFinished: 172800
22+
template:
23+
metadata:
24+
labels:
25+
druid.k8s.peons: "true"
26+
druid.task.id: "id"
27+
druid.task.type: "noop"
28+
druid.task.group.id: "id"
29+
druid.task.datasource: "datasource"
30+
annotations:
31+
task: "H4sIAAAAAAAAAD2MvQ4CIRCE32VqijsTG1qLi7W+wArEbHICrmC8EN7dJf40k/lmJtNQthxgEVPKMGCvXsXgKqnm4x89FTqlKm6MBzw+YCA1nvmm8W4/TQYuxRJeBbZ17cJ3ZhvoSbzShVcu2zLOf9cS7pUl+ANlclrCzr2/AQUK0FqZAAAA"
32+
tls.enabled: "false"
33+
task.id: "id"
34+
task.type: "noop"
35+
task.group.id: "id"
36+
task.datasource: "datasource"
37+
task.jobTemplate: base
38+
spec:
39+
containers:
40+
- command:
41+
- sleep
42+
- "3600"
43+
env:
44+
- name: "TASK_DIR"
45+
value: "/tmp"
46+
- name: "TASK_ID"
47+
value: "id"
48+
- name: "LOAD_BROADCAST_SEGMENTS"
49+
value: "false"
50+
- name: "TASK_JSON"
51+
valueFrom:
52+
fieldRef:
53+
fieldPath: "metadata.annotations['task']"
54+
image: one
55+
name: primary

0 commit comments

Comments
 (0)