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

FrankChen021 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 4f5a5802a80 fix: support task ids containing spaces in Kubernetes peon 
tasks (#20833)
4f5a5802a80 is described below

commit 4f5a5802a808fc02c14bfc90332e65fb498c074d
Author: Frank Chen <[email protected]>
AuthorDate: Sat Nov 7 11:09:03 2026 +0800

    fix: support task ids containing spaces in Kubernetes peon tasks (#20833)
    
    * fix: support task ids containing spaces in Kubernetes peon tasks
    
    Task ids embed the datasource name, which may contain a space. With the
    Kubernetes task runner such tasks failed to start:
    
    - peon.sh did not quote TASK_DIR, so writing task.json failed. Quote
      TASK_DIR and TASK_JSON.
    - K8sTaskAdapter flattened the peon command into a single "sh -c" string,
      so --taskId was split and CliPeon fetched the payload from deep storage
      with a truncated id when TASK_JSON was omitted for oversized payloads.
      Pass the task id through the TASK_ID env variable instead, which peon.sh
      forwards to CliPeon as a single quoted --taskId argument.
    
    * docs: update stale TASK_ID comment in peon.sh
---
 distribution/docker/peon.sh                        |  4 +--
 .../k8s/overlord/common/PeonCommandContext.java    | 22 +++++++++++++
 .../k8s/overlord/taskadapter/K8sTaskAdapter.java   | 16 ++++++++--
 .../overlord/taskadapter/K8sTaskAdapterTest.java   | 36 ++++++++++------------
 4 files changed, 54 insertions(+), 24 deletions(-)

diff --git a/distribution/docker/peon.sh b/distribution/docker/peon.sh
index a3938733d91..28734493553 100755
--- a/distribution/docker/peon.sh
+++ b/distribution/docker/peon.sh
@@ -163,7 +163,7 @@ fi
 
 # take the ${TASK_JSON} environment variable and base64 decode, unzip and 
throw it in ${TASK_DIR}/task.json.
 # If TASK_JSON is not set, CliPeon will pull the task.json file from deep 
storage.
-mkdir -p ${TASK_DIR}; [ -n "$TASK_JSON" ] && echo ${TASK_JSON} | base64 -d | 
gzip -d > ${TASK_DIR}/task.json;
+mkdir -p "${TASK_DIR}"; [ -n "$TASK_JSON" ] && echo "${TASK_JSON}" | base64 -d 
| gzip -d > "${TASK_DIR}/task.json";
 
 # Combine options from jvm.config and those given as JAVA_OPTS
 # If a value is specified in both then JAVA_OPTS will take precedence when 
using OpenJDK
@@ -174,7 +174,7 @@ fi
 
 # Start peon using CliPeon, with variables `Main internal peon TASK_DIR 
ATTEMPT_ID`
 if [ -n "$TASK_ID" ]; then
-    # TASK_ID is only set from PodTemplateTaskAdapter
+    # TASK_ID is set by all K8s pod adapters; older Overlords passed --taskId 
in "$@" instead
     exec bin/run-java ${JAVA_OPTS} -cp 
$COMMON_CONF_DIR:$SERVICE_CONF_DIR:lib/*:$DRUID_ADDITIONAL_CLASSPATH 
org.apache.druid.cli.Main internal peon "${TASK_DIR}" 1 --taskId "${TASK_ID}" 
"$@"
 else
     exec bin/run-java ${JAVA_OPTS} -cp 
$COMMON_CONF_DIR:$SERVICE_CONF_DIR:lib/*:$DRUID_ADDITIONAL_CLASSPATH 
org.apache.druid.cli.Main internal peon "${TASK_DIR}" 1 "$@"
diff --git 
a/extensions-core/kubernetes-overlord-extensions/src/main/java/org/apache/druid/k8s/overlord/common/PeonCommandContext.java
 
b/extensions-core/kubernetes-overlord-extensions/src/main/java/org/apache/druid/k8s/overlord/common/PeonCommandContext.java
index b1b5bf9ed31..4a46fe727c1 100644
--- 
a/extensions-core/kubernetes-overlord-extensions/src/main/java/org/apache/druid/k8s/overlord/common/PeonCommandContext.java
+++ 
b/extensions-core/kubernetes-overlord-extensions/src/main/java/org/apache/druid/k8s/overlord/common/PeonCommandContext.java
@@ -19,6 +19,7 @@
 
 package org.apache.druid.k8s.overlord.common;
 
+import javax.annotation.Nullable;
 import java.io.File;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -32,6 +33,8 @@ public class PeonCommandContext
   private final File taskDir;
   private final boolean enableTls;
   private final int cpuMicroCore;
+  @Nullable
+  private final String taskId;
 
   public PeonCommandContext(List<String> command, List<String> javaOpts, File 
taskDir, int cpuMicroCore)
   {
@@ -45,12 +48,25 @@ public class PeonCommandContext
       int cpuMicroCore,
       boolean enableTls
   )
+  {
+    this(command, javaOpts, taskDir, cpuMicroCore, enableTls, null);
+  }
+
+  public PeonCommandContext(
+      List<String> command,
+      List<String> javaOpts,
+      File taskDir,
+      int cpuMicroCore,
+      boolean enableTls,
+      @Nullable String taskId
+  )
   {
     this.command = command;
     this.javaOpts = javaOpts;
     this.taskDir = taskDir;
     this.cpuMicroCore = cpuMicroCore;
     this.enableTls = enableTls;
+    this.taskId = taskId;
   }
 
   public List<String> getCommand()
@@ -83,4 +99,10 @@ public class PeonCommandContext
   {
     return enableTls;
   }
+
+  @Nullable
+  public String getTaskId()
+  {
+    return taskId;
+  }
 }
diff --git 
a/extensions-core/kubernetes-overlord-extensions/src/main/java/org/apache/druid/k8s/overlord/taskadapter/K8sTaskAdapter.java
 
b/extensions-core/kubernetes-overlord-extensions/src/main/java/org/apache/druid/k8s/overlord/taskadapter/K8sTaskAdapter.java
index cef4588e08a..2fdfb395794 100644
--- 
a/extensions-core/kubernetes-overlord-extensions/src/main/java/org/apache/druid/k8s/overlord/taskadapter/K8sTaskAdapter.java
+++ 
b/extensions-core/kubernetes-overlord-extensions/src/main/java/org/apache/druid/k8s/overlord/taskadapter/K8sTaskAdapter.java
@@ -157,7 +157,8 @@ public abstract class K8sTaskAdapter implements TaskAdapter
         javaOpts(task),
         taskConfig.getTaskDir(task.getId()),
         taskRunnerConfig.getCpuCoreInMicro(),
-        node.isEnableTlsPort()
+        node.isEnableTlsPort(),
+        task.getId()
     );
     PodSpec podSpec = pod.getSpec();
     massageSpec(podSpec, taskRunnerConfig.getPrimaryContainerName());
@@ -330,6 +331,17 @@ public abstract class K8sTaskAdapter implements TaskAdapter
             )).build()).build()
     );
 
+    // Pass the task id through the environment rather than as a command 
argument: the command is flattened into a
+    // single "sh -c" string, which would split task ids containing spaces. 
peon.sh forwards it to CliPeon as --taskId.
+    if (context.getTaskId() != null) {
+      envVars.add(
+          new EnvVarBuilder()
+              .withName(DruidK8sConstants.TASK_ID_ENV)
+              .withValue(context.getTaskId())
+              .build()
+      );
+    }
+
     if (taskContents.length() < DruidK8sConstants.MAX_ENV_VARIABLE_KBS) {
       envVars.add(
           new EnvVarBuilder()
@@ -505,8 +517,6 @@ public abstract class K8sTaskAdapter implements TaskAdapter
     command.add("--loadBroadcastDatasourceMode");
     command.add(task.getBroadcastDatasourceLoadingSpec().getMode().toString());
 
-    command.add("--taskId");
-    command.add(task.getId());
     log.info(
         "Peon Command for K8s job: %s",
         
ForkingTaskRunner.getMaskedCommand(startupLoggingConfig.getMaskProperties(), 
command)
diff --git 
a/extensions-core/kubernetes-overlord-extensions/src/test/java/org/apache/druid/k8s/overlord/taskadapter/K8sTaskAdapterTest.java
 
b/extensions-core/kubernetes-overlord-extensions/src/test/java/org/apache/druid/k8s/overlord/taskadapter/K8sTaskAdapterTest.java
index 7275e1278cb..c2182b2f689 100644
--- 
a/extensions-core/kubernetes-overlord-extensions/src/test/java/org/apache/druid/k8s/overlord/taskadapter/K8sTaskAdapterTest.java
+++ 
b/extensions-core/kubernetes-overlord-extensions/src/test/java/org/apache/druid/k8s/overlord/taskadapter/K8sTaskAdapterTest.java
@@ -75,7 +75,6 @@ import java.io.File;
 import java.io.IOException;
 import java.nio.charset.Charset;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.Optional;
@@ -323,36 +322,35 @@ class K8sTaskAdapterTest
         jsonMapper,
         taskLogs
     );
+    // task id contains a space, as it does for datasources whose name 
contains a space
     Task task = new NoopTask(
+        "noop_my ds_id",
         "id",
-        "id",
-        "datasource",
+        "my ds",
         0,
         0,
         ImmutableMap.of("context", RandomStringUtils.randomAlphanumeric((int) 
DruidK8sConstants.MAX_ENV_VARIABLE_KBS * 20))
     );
     Job job = adapter.fromTask(task);
+    final Container mainContainer = 
job.getSpec().getTemplate().getSpec().getContainers().get(0);
     // TASK_JSON should not be set in env variables
     Assertions.assertFalse(
-        job.getSpec()
-            .getTemplate()
-            .getSpec()
-            .getContainers()
-            .get(0).getEnv()
-            .stream().anyMatch(env -> 
env.getName().equals(DruidK8sConstants.TASK_JSON_ENV))
+        mainContainer.getEnv()
+                     .stream().anyMatch(env -> 
env.getName().equals(DruidK8sConstants.TASK_JSON_ENV))
     );
 
-    // --taskId <TASK_ID> should be passed to the peon command args
-    Assertions.assertTrue(
-        Arrays.stream(job.getSpec()
-            .getTemplate()
-            .getSpec()
-            .getContainers()
-            .get(0)
-            .getArgs()
-            .get(0).split(" ")).collect(Collectors.toSet())
-            .containsAll(ImmutableList.of("--taskId", task.getId()))
+    // TASK_ID should be passed through env, so that peon.sh can pass it to 
CliPeon as a single --taskId argument
+    Assertions.assertEquals(
+        Collections.singletonList(task.getId()),
+        mainContainer.getEnv()
+                     .stream()
+                     .filter(env -> 
env.getName().equals(DruidK8sConstants.TASK_ID_ENV))
+                     .map(EnvVar::getValue)
+                     .collect(Collectors.toList())
     );
+
+    // --taskId should not be in the "sh -c" command string, where a task id 
containing a space would be split
+    
Assertions.assertFalse(mainContainer.getArgs().get(0).contains("--taskId"));
   }
 
   @Test


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to