-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Fix omjob pod/label naming length constraints #27143
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
ffa017e
3330f8f
b15d968
1dc343f
f222ae1
e46a854
050659c
0688cde
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
|
|
@@ -37,6 +37,7 @@ | |||
| import org.openmetadata.operator.model.OMJobSpec; | ||||
| import org.openmetadata.operator.model.OMJobStatus; | ||||
| import org.openmetadata.operator.util.EnvVarUtils; | ||||
| import org.openmetadata.operator.util.KubernetesNameBuilder; | ||||
| import org.openmetadata.operator.util.LabelBuilder; | ||||
| import org.openmetadata.schema.entity.services.ingestionPipelines.PipelineStatusType; | ||||
| import org.slf4j.Logger; | ||||
|
|
@@ -51,6 +52,7 @@ public class PodManager { | |||
|
|
||||
| private static final Logger LOG = LoggerFactory.getLogger(PodManager.class); | ||||
| private static final String PIPELINE_STATUS = "pipelineStatus"; | ||||
| private static final int MAX_POD_NAME_LENGTH = 253; | ||||
|
||||
| private static final int MAX_POD_NAME_LENGTH = 253; |
Copilot
AI
Apr 11, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
buildPodName truncates the OMJob name when it would exceed the 253-char DNS limit, but truncation is prefix-only and can cause pod-name collisions between different long OMJob names that only differ near the end. That can break the idempotency checks (withName(podName).get()) and/or cause create conflicts. Consider using a hash-based truncation scheme when truncation is required (similar to LabelBuilder.sanitizeLabelValue) so the generated pod name remains unique within the length limit.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| /* | ||
| * Copyright 2021 Collate. | ||
|
Darshan3690 marked this conversation as resolved.
|
||
| * Licensed 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.openmetadata.operator.util; | ||
|
|
||
| import java.nio.charset.StandardCharsets; | ||
| import java.security.MessageDigest; | ||
| import java.security.NoSuchAlgorithmException; | ||
|
|
||
| public class HashUtils { | ||
| private static final int HASH_LENGTH = 6; | ||
|
|
||
| private HashUtils() { | ||
| // Utility class | ||
| } | ||
|
|
||
| /** | ||
| * Generates a 6-character SHA-256 hash of the input string for deterministic name | ||
| * truncation. | ||
| * | ||
| * @param input the string to hash | ||
| * @return a 6-character hex string | ||
| * @throws IllegalArgumentException if SHA-256 is not available | ||
| */ | ||
| public static String hash(String input) { | ||
| try { | ||
| MessageDigest digest = MessageDigest.getInstance("SHA-256"); | ||
| byte[] encoded = digest.digest(input.getBytes(StandardCharsets.UTF_8)); | ||
| StringBuilder hex = new StringBuilder(); | ||
| for (byte value : encoded) { | ||
| hex.append(String.format("%02x", value & 0xff)); | ||
| } | ||
| return hex.substring(0, HASH_LENGTH); | ||
| } catch (NoSuchAlgorithmException e) { | ||
| throw new IllegalArgumentException("SHA-256 algorithm not available", e); | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,76 @@ | ||
| /* | ||
| * Copyright 2021 Collate | ||
| * Licensed 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.openmetadata.operator.util; | ||
|
|
||
| /** | ||
| * Utility for building deterministic Kubernetes resource names within a length limit. | ||
| */ | ||
| public final class KubernetesNameBuilder { | ||
|
|
||
| private static final int HASH_LENGTH = 6; | ||
|
|
||
| private KubernetesNameBuilder() { | ||
| // Utility class | ||
| } | ||
|
|
||
| public static String fitNameWithHash( | ||
| String baseName, int maxBaseLength, String fallbackBaseName) { | ||
|
gitar-bot[bot] marked this conversation as resolved.
|
||
| if (maxBaseLength < 1) { | ||
| throw new IllegalArgumentException( | ||
| "Kubernetes resource name must allow at least one character"); | ||
| } | ||
|
|
||
| if (fallbackBaseName == null || fallbackBaseName.isEmpty()) { | ||
| throw new IllegalArgumentException("fallbackBaseName must not be null or empty"); | ||
| } | ||
|
|
||
| String candidate = baseName == null ? "" : baseName; | ||
| if (candidate.length() > maxBaseLength) { | ||
| String hash = HashUtils.hash(candidate).substring(0, Math.min(HASH_LENGTH, maxBaseLength)); | ||
| int maxPrefixLength = maxBaseLength - hash.length() - 1; | ||
|
pmbrull marked this conversation as resolved.
|
||
|
|
||
| if (maxPrefixLength > 0) { | ||
| String prefix = trimTrailingSeparators(candidate.substring(0, maxPrefixLength)); | ||
| if (!prefix.isEmpty()) { | ||
| return prefix + "-" + hash; | ||
| } | ||
|
|
||
| String fallbackPrefix = | ||
| trimTrailingSeparators( | ||
| fallbackBaseName.substring( | ||
| 0, Math.min(fallbackBaseName.length(), maxPrefixLength))); | ||
| if (!fallbackPrefix.isEmpty()) { | ||
| return fallbackPrefix + "-" + hash; | ||
| } | ||
| } | ||
|
|
||
| return hash; | ||
| } | ||
|
|
||
| if (candidate.isEmpty()) { | ||
| candidate = fallbackBaseName; | ||
| } | ||
|
|
||
| if (candidate.length() > maxBaseLength) { | ||
| throw new IllegalStateException( | ||
| "Fallback name exceeds max base length (" + maxBaseLength + ")"); | ||
| } | ||
|
|
||
| return candidate; | ||
| } | ||
|
|
||
| private static String trimTrailingSeparators(String value) { | ||
| return value.replaceAll("[^a-z0-9]+$", ""); | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.