package com.hubspot.singularity; import java.util.Calendar; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Set; import java.util.UUID; import com.google.common.base.Optional; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; import com.google.common.collect.Sets; public class SingularityS3FormatHelper { public static final String DEFAULT_GROUP_NAME = "default"; private static final List<String> DISALLOWED_FOR_TASK = ImmutableList.of("%index", "%s", "%filename", "%fileext"); private static final List<String> DISALLOWED_FOR_DEPLOY = ImmutableList.copyOf(Iterables.concat(DISALLOWED_FOR_TASK, ImmutableList.of("%host"))); private static final List<String> DISALLOWED_FOR_REQUEST = ImmutableList.copyOf(Iterables.concat(DISALLOWED_FOR_DEPLOY, ImmutableList.of("%tag", "%deployId"))); public static String getS3KeyFormat(String s3KeyFormat, String requestId, String group) { s3KeyFormat = s3KeyFormat.replace("%requestId", requestId); s3KeyFormat = s3KeyFormat.replace("%group", group); return s3KeyFormat; } public static String getS3KeyFormat(String s3KeyFormat, String requestId, String deployId, Optional<String> loggingTag, String group) { s3KeyFormat = getS3KeyFormat(s3KeyFormat, requestId, group); s3KeyFormat = s3KeyFormat.replace("%tag", loggingTag.or("")); s3KeyFormat = s3KeyFormat.replace("%deployId", deployId); return s3KeyFormat; } public static String getS3KeyFormat(String s3KeyFormat, SingularityTaskId taskId, Optional<String> loggingTag, String group) { s3KeyFormat = getS3KeyFormat(s3KeyFormat, taskId.getRequestId(), taskId.getDeployId(), loggingTag, group); s3KeyFormat = s3KeyFormat.replace("%host", taskId.getSanitizedHost()); s3KeyFormat = s3KeyFormat.replace("%taskId", taskId.toString()); return s3KeyFormat; } public static String getKey(String s3KeyFormat, int sequence, long timestamp, String filename, String hostname) { final Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(timestamp); if (s3KeyFormat.contains("%filename")) { s3KeyFormat = s3KeyFormat.replace("%filename", filename); } if (s3KeyFormat.contains("%fileext")) { int lastPeriod = filename.lastIndexOf("."); if (lastPeriod > -1) { s3KeyFormat = s3KeyFormat.replace("%fileext", filename.substring(lastPeriod)); } } if (s3KeyFormat.contains("%guid")) { s3KeyFormat = s3KeyFormat.replace("%guid", UUID.randomUUID().toString()); } if (s3KeyFormat.contains("%host")) { s3KeyFormat = s3KeyFormat.replace("%host", hostname); } if (s3KeyFormat.contains("%Y")) { s3KeyFormat = s3KeyFormat.replace("%Y", getYear(calendar.get(Calendar.YEAR))); } if (s3KeyFormat.contains("%m")) { s3KeyFormat = s3KeyFormat.replace("%m", getDayOrMonth(getMonth(calendar))); } if (s3KeyFormat.contains("%d")) { s3KeyFormat = s3KeyFormat.replace("%d", getDayOrMonth(calendar.get(Calendar.DAY_OF_MONTH))); } if (s3KeyFormat.contains("%s")) { s3KeyFormat = s3KeyFormat.replace("%s", Long.toString(timestamp)); } if (s3KeyFormat.contains("%index")) { s3KeyFormat = s3KeyFormat.replace("%index", Integer.toString(sequence)); } return s3KeyFormat; } public static String trimKeyFormat(String s3KeyFormat, List<String> disallowedKeys) { int lowestIndex = s3KeyFormat.length(); for (String disallowedKey : disallowedKeys) { int index = s3KeyFormat.indexOf(disallowedKey); if (index != -1 && index < lowestIndex) { lowestIndex = index; } } if (lowestIndex == -1) { return s3KeyFormat; } return s3KeyFormat.substring(0, lowestIndex); } private static int getMonth(Calendar calender) { return calender.get(Calendar.MONTH) + 1; } private static String getYear(int year) { return Integer.toString(year); } private static String getDayOrMonth(int value) { return String.format("%02d", value); } public static Collection<String> getS3KeyPrefixes(String s3KeyFormat, String requestId, String deployId, Optional<String> tag, long start, long end, String group) { String keyFormat = getS3KeyFormat(s3KeyFormat, requestId, deployId, tag, group); keyFormat = trimTaskId(keyFormat, requestId + "-" + deployId); return getS3KeyPrefixes(keyFormat, DISALLOWED_FOR_DEPLOY, start, end); } private static String trimTaskId(String s3KeyFormat, String replaceWith) { int index = s3KeyFormat.indexOf("%taskId"); if (index > -1) { s3KeyFormat = s3KeyFormat.substring(0, index) + replaceWith; } return s3KeyFormat; } public static Collection<String> getS3KeyPrefixes(String s3KeyFormat, String requestId, long start, long end, String group) { s3KeyFormat = getS3KeyFormat(s3KeyFormat, requestId, group); s3KeyFormat = trimTaskId(s3KeyFormat, requestId); return getS3KeyPrefixes(s3KeyFormat, DISALLOWED_FOR_REQUEST, start, end); } private static Collection<String> getS3KeyPrefixes(String s3KeyFormat, List<String> disallowedKeys, long start, long end) { String trimKeyFormat = trimKeyFormat(s3KeyFormat, disallowedKeys); int indexOfY = trimKeyFormat.indexOf("%Y"); int indexOfM = trimKeyFormat.indexOf("%m"); int indexOfD = trimKeyFormat.indexOf("%d"); if (indexOfY == -1 && indexOfM == -1 && indexOfD == -1) { return Collections.singleton(trimKeyFormat); } if (indexOfY > -1) { trimKeyFormat = trimKeyFormat.replace("%Y", "YYYY"); if (indexOfM > -1) { indexOfM += 2; } if (indexOfD > -1) { indexOfD += 2; } } StringBuilder keyBuilder = new StringBuilder(trimKeyFormat); Set<String> keyPrefixes = Sets.newHashSet(); Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(start); calendar.set(Calendar.SECOND, 0); calendar.set(Calendar.MILLISECOND, 0); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.HOUR_OF_DAY, 0); while (calendar.getTimeInMillis() < end) { if (indexOfY > -1) { keyBuilder.replace(indexOfY, indexOfY + 4, getYear(calendar.get(Calendar.YEAR))); } if (indexOfM > -1) { keyBuilder.replace(indexOfM, indexOfM + 2, getDayOrMonth(getMonth(calendar))); } if (indexOfD > -1) { keyBuilder.replace(indexOfD, indexOfD + 2, getDayOrMonth(calendar.get(Calendar.DAY_OF_MONTH))); } keyPrefixes.add(keyBuilder.toString()); if (indexOfD > -1) { calendar.add(Calendar.DAY_OF_YEAR, 1); } else if (indexOfM > -1) { calendar.set(Calendar.DAY_OF_MONTH, 1); calendar.add(Calendar.MONTH, 1); } else { calendar.set(Calendar.MONTH, 0); calendar.add(Calendar.YEAR, 1); } } return keyPrefixes; } public static Collection<String> getS3KeyPrefixes(String s3KeyFormat, SingularityTaskId taskId, Optional<String> tag, long start, long end, String group) { String keyFormat = getS3KeyFormat(s3KeyFormat, taskId, tag, group); return getS3KeyPrefixes(keyFormat, DISALLOWED_FOR_TASK, start, end); } }