Skip to content
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

Add random suffix to IT resource IDs to avoid collision #31154

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public class ResourceManagerUtils {
private static final int MAX_PROJECT_ID_LENGTH = 30;
private static final Pattern ILLEGAL_PROJECT_CHARS = Pattern.compile("[^a-zA-Z0-9-!:\\.']");
private static final String TIME_ZONE = "UTC";
private static final String DEFAULT_TIME_FORMAT = "yyyyMMdd-HHmmss";

/**
* Generates a new id string from an existing one.
Expand All @@ -66,15 +67,37 @@ public static String generateNewId(String id, int targetLength) {

/**
* Generates a generic resource id from a given string, avoiding characters specified in the
* illegalChars Pattern. The length of the generated string ID will not exceed the length
* specified by targetLength.
* illegalChars Pattern. A randomly generated suffix will be appended to ensure unique ID. The
* length of the generated string ID will not exceed the length specified by targetLength.
*
* @param baseString the base ID to generate the resource ID from.
* @param illegalChars a pattern of characters to remove from the generated ID.
* @param replaceChar the character to replace all illegal characters with.
* @param targetLength the max length of the generated ID.
* @return the generated resource ID.
*/
public static String generateResourceId(
String baseString, Pattern illegalChars, String replaceChar, int targetLength) {
return generateResourceId(
baseString,
illegalChars,
replaceChar,
targetLength,
DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT));
}

/**
* Generates a generic resource id from a given string, avoiding characters specified in the
* illegalChars Pattern. A randomly generated suffix will be appended to ensure unique ID. The
* length of the generated string ID will not exceed the length specified by targetLength.
*
* @param baseString the base ID to generate the resource ID from.
* @param illegalChars a pattern of characters to remove from the generated ID.
* @param replaceChar the character to replace all illegal characters with.
* @param targetLength the max length of the generated ID.
* @param timeFormat a time formatter used as part of the generated suffix.
* @return the generated resource ID.
*/
public static String generateResourceId(
String baseString,
Pattern illegalChars,
Expand All @@ -88,13 +111,18 @@ public static String generateResourceId(
String illegalCharsRemoved =
illegalChars.matcher(baseString.toLowerCase()).replaceAll(replaceChar);

// finally, append the date/time and return the substring that does not exceed the length limit
// finally, append the date/time and return the substring that does not exceed the length limit.
// add random characters to end to ensure minimal collision.
LocalDateTime localDateTime = LocalDateTime.now(ZoneId.of(TIME_ZONE));
String timeAddOn = localDateTime.format(timeFormat);
String timeAddOn = replaceChar + localDateTime.format(timeFormat);
String randomAddOn = replaceChar + RandomStringUtils.randomAlphanumeric(6);
return illegalCharsRemoved.subSequence(
0, min(targetLength - timeAddOn.length() - 1, illegalCharsRemoved.length()))
+ replaceChar
+ localDateTime.format(timeFormat);
0,
min(
targetLength - timeAddOn.length() - randomAddOn.length(),
illegalCharsRemoved.length()))
+ timeAddOn
+ randomAddOn;
}

/** Generates random letter for padding. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public class ResourceManagerUtilsTest {
private static final String REPLACE_INSTANCE_CHAR = "-";
public static final int MAX_INSTANCE_ID_LENGTH = 36;
private static final DateTimeFormatter TIME_FORMAT =
DateTimeFormatter.ofPattern("yyyyMMdd-HHmmss-SSSSSS");
DateTimeFormatter.ofPattern("yyyyMMdd-HHmmss");

@Test
public void testGenerateResourceIdShouldReplaceDollarSignWithHyphen() {
Expand All @@ -48,7 +48,18 @@ public void testGenerateResourceIdShouldReplaceDollarSignWithHyphen() {
MAX_INSTANCE_ID_LENGTH,
TIME_FORMAT);

assertThat(actual).matches("test-instance-\\d{8}-\\d{6}-\\d{6}");
assertThat(actual).matches("test-instance-\\d{8}-\\d{6}-[a-zA-Z0-9]{6}");
}

@Test
public void testGenerateResourceIdShouldReplaceDollarSignWithHyphenWithoutTimeFormatter() {
String testBaseString = "test$instance";

String actual =
generateResourceId(
testBaseString, ILLEGAL_INSTANCE_CHARS, REPLACE_INSTANCE_CHAR, MAX_INSTANCE_ID_LENGTH);

assertThat(actual).matches("test-instance-\\d{8}-\\d{6}-[a-zA-Z0-9]{6}");
}

@Test
Expand All @@ -63,7 +74,7 @@ public void testGenerateResourceIdShouldReplaceDotWithHyphen() {
MAX_INSTANCE_ID_LENGTH,
TIME_FORMAT);

assertThat(actual).matches("test-instance-\\d{8}-\\d{6}-\\d{6}");
assertThat(actual).matches("test-instance-\\d{8}-\\d{6}-[a-zA-Z0-9]{6}");
}

@Test
Expand All @@ -78,7 +89,7 @@ public void testGenerateResourceIdShouldReplaceUnderscoreWithHyphen() {
MAX_INSTANCE_ID_LENGTH,
TIME_FORMAT);

assertThat(actual).matches("test-inst-\\d{8}-\\d{6}-\\d{6}");
assertThat(actual).matches("test-inst-\\d{8}-\\d{6}-[a-zA-Z0-9]{6}");
}

@Test
Expand All @@ -93,7 +104,7 @@ public void testGenerateResourceIdShouldReplaceUpperCaseLettersWithLowerCase() {
MAX_INSTANCE_ID_LENGTH,
TIME_FORMAT);

assertThat(actual).matches("test-instance-\\d{8}-\\d{6}-\\d{6}");
assertThat(actual).matches("test-instance-\\d{8}-\\d{6}-[a-zA-Z0-9]{6}");
}

@Test
Expand Down Expand Up @@ -138,7 +149,7 @@ public void testGenerateResourceIdWhenInputLengthIsLongerThanTargetLength() {
MAX_INSTANCE_ID_LENGTH,
TIME_FORMAT);

assertThat(actual).matches("test-instance-\\d{8}-\\d{6}-\\d{6}");
assertThat(actual).matches("test-instance-\\d{8}-\\d{6}-[a-zA-Z0-9]{6}");
}

@Test
Expand Down
Loading