/** * POST TITLE: Helm Template Functions Implementation in Java * * Complete Java implementation of Helm template functions for Kubernetes manifest generation */ import java.util.*; import java.util.regex.*; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.text.SimpleDateFormat; public class HelmTemplateEngine { private Map<String, Object> values; private Map<String, Object> builtInObjects; private Map<String, TemplateFunction> functions; public HelmTemplateEngine() { this.values = new HashMap<>(); this.builtInObjects = new HashMap<>(); this.functions = registerBuiltInFunctions(); } /** * Template Function Interface */ @FunctionalInterface public interface TemplateFunction { Object apply(List<Object> args, Map<String, Object> context); } /** * Built-in Objects (like .Values, .Chart, .Release) */ public static class BuiltInObjects { private Map<String, Object> values; private Map<String, Object> chart; private Map<String, Object> release; private Map<String, Object> files; private Map<String, Object> capabilities; private Map<String, Object> template; public BuiltInObjects() { this.values = new HashMap<>(); this.chart = new HashMap<>(); this.release = new HashMap<>(); this.files = new HashMap<>(); this.capabilities = new HashMap<>(); this.template = new HashMap<>(); // Initialize with default values initializeDefaults(); } private void initializeDefaults() { chart.put("name", "my-chart"); chart.put("version", "1.0.0"); chart.put("description", "A Helm chart for Kubernetes"); chart.put("apiVersion", "v2"); release.put("name", "my-release"); release.put("namespace", "default"); release.put("service", "Helm"); release.put("isUpgrade", false); release.put("isInstall", true); capabilities.put("kubeVersion", "1.25.0"); capabilities.put("helmVersion", "3.12.0"); } // Getters public Map<String, Object> getValues() { return values; } public Map<String, Object> getChart() { return chart; } public Map<String, Object> getRelease() { return release; } public Map<String, Object> getFiles() { return files; } public Map<String, Object> getCapabilities() { return capabilities; } public Map<String, Object> getTemplate() { return template; } } /** * Register all built-in Helm template functions */ private Map<String, TemplateFunction> registerBuiltInFunctions() { Map<String, TemplateFunction> funcs = new HashMap<>(); // String functions funcs.put("upper", this::upper); funcs.put("lower", this::lower); funcs.put("title", this::title); funcs.put("nindent", this::nindent); funcs.put("indent", this::indent); funcs.put("trim", this::trim); funcs.put("trimAll", this::trimAll); funcs.put("trimSuffix", this::trimSuffix); funcs.put("trimPrefix", this::trimPrefix); funcs.put("contains", this::contains); funcs.put("hasPrefix", this::hasPrefix); funcs.put("hasSuffix", this::hasSuffix); funcs.put("replace", this::replace); funcs.put("repeat", this::repeat); funcs.put("toString", this::toString); // Crypto and encoding functions funcs.put("b64enc", this::b64enc); funcs.put("b64dec", this::b64dec); funcs.put("sha256sum", this::sha256sum); // Date functions funcs.put("now", this::now); funcs.put("date", this::date); funcs.put("unixEpoch", this::unixEpoch); // List functions funcs.put("list", this::list); funcs.put("first", this::first); funcs.put("last", this::last); funcs.put("initial", this::initial); funcs.put("rest", this::rest); funcs.put("append", this::append); funcs.put("prepend", this::prepend); funcs.put("reverse", this::reverse); funcs.put("uniq", this::uniq); funcs.put("without", this::without); funcs.put("has", this::has); funcs.put("compact", this::compact); funcs.put("dict", this::dict); // Math functions funcs.put("add", this::add); funcs.put("sub", this::sub); funcs.put("mul", this::mul); funcs.put("div", this::div); funcs.put("mod", this::mod); funcs.put("max", this::max); funcs.put("min", this::min); funcs.put("ceil", this::ceil); funcs.put("floor", this::floor); funcs.put("round", this::round); // Type conversion functions funcs.put("int", this::toInt); funcs.put("float", this::toFloat); funcs.put("toString", this::toString); funcs.put("toJson", this::toJson); funcs.put("toYaml", this::toYaml); // Kubernetes-specific functions funcs.put("toToml", this::toToml); funcs.put("required", this::required); funcs.put("fail", this::fail); funcs.put("coalesce", this::coalesce); funcs.put("deepCopy", this::deepCopy); funcs.put("mustMerge", this::mustMerge); funcs.put("mustToJson", this::mustToJson); funcs.put("mustToYaml", this::mustToYaml); // Flow control functions funcs.put("default", this::defaultFunc); funcs.put("empty", this::empty); funcs.put("ternary", this::ternary); return funcs; } /** * STRING FUNCTIONS */ private Object upper(List<Object> args, Map<String, Object> context) { validateArgs(args, 1, "upper"); return args.get(0).toString().toUpperCase(); } private Object lower(List<Object> args, Map<String, Object> context) { validateArgs(args, 1, "lower"); return args.get(0).toString().toLowerCase(); } private Object title(List<Object> args, Map<String, Object> context) { validateArgs(args, 1, "title"); String str = args.get(0).toString(); if (str.isEmpty()) return str; return Character.toUpperCase(str.charAt(0)) + str.substring(1).toLowerCase(); } private Object nindent(List<Object> args, Map<String, Object> context) { validateArgs(args, 1, "nindent"); int spaces = ((Number) args.get(0)).intValue(); String indent = " ".repeat(spaces); return "\n" + indent; } private Object indent(List<Object> args, Map<String, Object> context) { validateArgs(args, 2, "indent"); int spaces = ((Number) args.get(0)).intValue(); String text = args.get(1).toString(); String indent = " ".repeat(spaces); return Arrays.stream(text.split("\n")) .map(line -> indent + line) .reduce((a, b) -> a + "\n" + b) .orElse(""); } private Object trim(List<Object> args, Map<String, Object> context) { validateArgs(args, 1, "trim"); return args.get(0).toString().trim(); } private Object trimAll(List<Object> args, Map<String, Object> context) { validateArgs(args, 2, "trimAll"); String cutset = args.get(0).toString(); String str = args.get(1).toString(); Pattern pattern = Pattern.compile("^[" + Pattern.quote(cutset) + "]+|[" + Pattern.quote(cutset) + "]+$"); return pattern.matcher(str).replaceAll(""); } private Object trimSuffix(List<Object> args, Map<String, Object> context) { validateArgs(args, 2, "trimSuffix"); String suffix = args.get(0).toString(); String str = args.get(1).toString(); return str.endsWith(suffix) ? str.substring(0, str.length() - suffix.length()) : str; } private Object trimPrefix(List<Object> args, Map<String, Object> context) { validateArgs(args, 2, "trimPrefix"); String prefix = args.get(0).toString(); String str = args.get(1).toString(); return str.startsWith(prefix) ? str.substring(prefix.length()) : str; } private Object contains(List<Object> args, Map<String, Object> context) { validateArgs(args, 2, "contains"); String substr = args.get(0).toString(); String str = args.get(1).toString(); return str.contains(substr); } private Object hasPrefix(List<Object> args, Map<String, Object> context) { validateArgs(args, 2, "hasPrefix"); String prefix = args.get(0).toString(); String str = args.get(1).toString(); return str.startsWith(prefix); } private Object hasSuffix(List<Object> args, Map<String, Object> context) { validateArgs(args, 2, "hasSuffix"); String suffix = args.get(0).toString(); String str = args.get(1).toString(); return str.endsWith(suffix); } private Object replace(List<Object> args, Map<String, Object> context) { validateArgs(args, 3, "replace"); String oldStr = args.get(0).toString(); String newStr = args.get(1).toString(); String str = args.get(2).toString(); return str.replace(oldStr, newStr); } private Object repeat(List<Object> args, Map<String, Object> context) { validateArgs(args, 2, "repeat"); int count = ((Number) args.get(0)).intValue(); String str = args.get(1).toString(); return str.repeat(count); } /** * CRYPTO AND ENCODING FUNCTIONS */ private Object b64enc(List<Object> args, Map<String, Object> context) { validateArgs(args, 1, "b64enc"); String str = args.get(0).toString(); return Base64.getEncoder().encodeToString(str.getBytes(StandardCharsets.UTF_8)); } private Object b64dec(List<Object> args, Map<String, Object> context) { validateArgs(args, 1, "b64dec"); String str = args.get(0).toString(); return new String(Base64.getDecoder().decode(str), StandardCharsets.UTF_8); } private Object sha256sum(List<Object> args, Map<String, Object> context) { validateArgs(args, 1, "sha256sum"); try { String str = args.get(0).toString(); MessageDigest digest = MessageDigest.getInstance("SHA-256"); byte[] hash = digest.digest(str.getBytes(StandardCharsets.UTF_8)); StringBuilder hexString = new StringBuilder(); for (byte b : hash) { hexString.append(String.format("%02x", b)); } return hexString.toString(); } catch (Exception e) { throw new RuntimeException("SHA-256 calculation failed", e); } } /** * DATE FUNCTIONS */ private Object now(List<Object> args, Map<String, Object> context) { return new Date(); } private Object date(List<Object> args, Map<String, Object> context) { validateArgs(args, 2, "date"); String format = args.get(0).toString(); Object dateObj = args.get(1); Date date; if (dateObj instanceof Date) { date = (Date) dateObj; } else if (dateObj instanceof String) { // Parse date from string (simplified) date = new Date(); } else if (dateObj instanceof Number) { long timestamp = ((Number) dateObj).longValue(); date = new Date(timestamp * 1000); // Assuming seconds } else { date = new Date(); } return new SimpleDateFormat(format).format(date); } private Object unixEpoch(List<Object> args, Map<String, Object> context) { Object dateObj = args.isEmpty() ? new Date() : args.get(0); Date date; if (dateObj instanceof Date) { date = (Date) dateObj; } else if (dateObj instanceof String) { // Parse date from string (simplified) date = new Date(); } else { date = new Date(); } return date.getTime() / 1000; // Convert to seconds } /** * LIST FUNCTIONS */ private Object list(List<Object> args, Map<String, Object> context) { return new ArrayList<>(args); } private Object first(List<Object> args, Map<String, Object> context) { validateArgs(args, 1, "first"); List<Object> list = (List<Object>) args.get(0); return list.isEmpty() ? null : list.get(0); } private Object last(List<Object> args, Map<String, Object> context) { validateArgs(args, 1, "last"); List<Object> list = (List<Object>) args.get(0); return list.isEmpty() ? null : list.get(list.size() - 1); } private Object initial(List<Object> args, Map<String, Object> context) { validateArgs(args, 1, "initial"); List<Object> list = (List<Object>) args.get(0); return list.isEmpty() ? new ArrayList<>() : list.subList(0, list.size() - 1); } private Object rest(List<Object> args, Map<String, Object> context) { validateArgs(args, 1, "rest"); List<Object> list = (List<Object>) args.get(0); return list.isEmpty() ? new ArrayList<>() : list.subList(1, list.size()); } private Object append(List<Object> args, Map<String, Object> context) { validateArgs(args, 2, "append"); List<Object> list = new ArrayList<>((List<Object>) args.get(0)); list.add(args.get(1)); return list; } private Object prepend(List<Object> args, Map<String, Object> context) { validateArgs(args, 2, "prepend"); List<Object> list = new ArrayList<>((List<Object>) args.get(0)); list.add(0, args.get(1)); return list; } private Object reverse(List<Object> args, Map<String, Object> context) { validateArgs(args, 1, "reverse"); List<Object> list = new ArrayList<>((List<Object>) args.get(0)); Collections.reverse(list); return list; } private Object uniq(List<Object> args, Map<String, Object> context) { validateArgs(args, 1, "uniq"); List<Object> list = (List<Object>) args.get(0); return new ArrayList<>(new LinkedHashSet<>(list)); } private Object without(List<Object> args, Map<String, Object> context) { validateArgs(args, 2, "without"); List<Object> list = new ArrayList<>((List<Object>) args.get(0)); Object item = args.get(1); list.remove(item); return list; } private Object has(List<Object> args, Map<String, Object> context) { validateArgs(args, 2, "has"); List<Object> list = (List<Object>) args.get(0); Object item = args.get(1); return list.contains(item); } private Object compact(List<Object> args, Map<String, Object> context) { validateArgs(args, 1, "compact"); List<Object> list = (List<Object>) args.get(0); return list.stream() .filter(obj -> obj != null && !obj.toString().isEmpty()) .collect(ArrayList::new, ArrayList::add, ArrayList::addAll); } private Object dict(List<Object> args, Map<String, Object> context) { if (args.size() % 2 != 0) { throw new IllegalArgumentException("dict requires even number of arguments"); } Map<String, Object> map = new HashMap<>(); for (int i = 0; i < args.size(); i += 2) { map.put(args.get(i).toString(), args.get(i + 1)); } return map; } /** * MATH FUNCTIONS */ private Object add(List<Object> args, Map<String, Object> context) { validateArgs(args, 2, "add"); Number a = (Number) args.get(0); Number b = (Number) args.get(1); return a.doubleValue() + b.doubleValue(); } private Object sub(List<Object> args, Map<String, Object> context) { validateArgs(args, 2, "sub"); Number a = (Number) args.get(0); Number b = (Number) args.get(1); return a.doubleValue() - b.doubleValue(); } private Object mul(List<Object> args, Map<String, Object> context) { validateArgs(args, 2, "mul"); Number a = (Number) args.get(0); Number b = (Number) args.get(1); return a.doubleValue() * b.doubleValue(); } private Object div(List<Object> args, Map<String, Object> context) { validateArgs(args, 2, "div"); Number a = (Number) args.get(0); Number b = (Number) args.get(1); if (b.doubleValue() == 0) { throw new ArithmeticException("Division by zero"); } return a.doubleValue() / b.doubleValue(); } private Object mod(List<Object> args, Map<String, Object> context) { validateArgs(args, 2, "mod"); Number a = (Number) args.get(0); Number b = (Number) args.get(1); return a.intValue() % b.intValue(); } private Object max(List<Object> args, Map<String, Object> context) { validateArgs(args, 1, "max"); List<Number> numbers = (List<Number>) args.get(0); return numbers.stream() .mapToDouble(Number::doubleValue) .max() .orElseThrow(() -> new IllegalArgumentException("Empty list")); } private Object min(List<Object> args, Map<String, Object> context) { validateArgs(args, 1, "min"); List<Number> numbers = (List<Number>) args.get(0); return numbers.stream() .mapToDouble(Number::doubleValue) .min() .orElseThrow(() -> new IllegalArgumentException("Empty list")); } private Object ceil(List<Object> args, Map<String, Object> context) { validateArgs(args, 1, "ceil"); Number num = (Number) args.get(0); return Math.ceil(num.doubleValue()); } private Object floor(List<Object> args, Map<String, Object> context) { validateArgs(args, 1, "floor"); Number num = (Number) args.get(0); return Math.floor(num.doubleValue()); } private Object round(List<Object> args, Map<String, Object> context) { validateArgs(args, 1, "round"); Number num = (Number) args.get(0); return Math.round(num.doubleValue()); } /** * TYPE CONVERSION FUNCTIONS */ private Object toInt(List<Object> args, Map<String, Object> context) { validateArgs(args, 1, "toInt"); Object obj = args.get(0); if (obj instanceof Number) { return ((Number) obj).intValue(); } return Integer.parseInt(obj.toString()); } private Object toFloat(List<Object> args, Map<String, Object> context) { validateArgs(args, 1, "toFloat"); Object obj = args.get(0); if (obj instanceof Number) { return ((Number) obj).doubleValue(); } return Double.parseDouble(obj.toString()); } private Object toString(List<Object> args, Map<String, Object> context) { validateArgs(args, 1, "toString"); return args.get(0).toString(); } private Object toJson(List<Object> args, Map<String, Object> context) { validateArgs(args, 1, "toJson"); // Simplified JSON serialization return serializeToJson(args.get(0)); } private Object toYaml(List<Object> args, Map<String, Object> context) { validateArgs(args, 1, "toYaml"); // Simplified YAML serialization return serializeToYaml(args.get(0)); } /** * FLOW CONTROL FUNCTIONS */ private Object defaultFunc(List<Object> args, Map<String, Object> context) { validateArgs(args, 2, "default"); Object defaultValue = args.get(0); Object value = args.get(1); return isEmpty(value) ? defaultValue : value; } private Object empty(List<Object> args, Map<String, Object> context) { validateArgs(args, 1, "empty"); return isEmpty(args.get(0)); } private Object ternary(List<Object> args, Map<String, Object> context) { validateArgs(args, 3, "ternary"); boolean condition = Boolean.TRUE.equals(args.get(0)); return condition ? args.get(1) : args.get(2); } /** * KUBERNETES-SPECIFIC FUNCTIONS */ private Object toToml(List<Object> args, Map<String, Object> context) { validateArgs(args, 1, "toToml"); // Simplified TOML serialization return serializeToToml(args.get(0)); } private Object required(List<Object> args, Map<String, Object> context) { validateArgs(args, 2, "required"); String message = args.get(0).toString(); Object value = args.get(1); if (isEmpty(value)) { throw new IllegalArgumentException("Required value missing: " + message); } return value; } private Object fail(List<Object> args, Map<String, Object> context) { validateArgs(args, 1, "fail"); String message = args.get(0).toString(); throw new RuntimeException("Template failed: " + message); } private Object coalesce(List<Object> args, Map<String, Object> context) { for (Object arg : args) { if (!isEmpty(arg)) { return arg; } } return null; } private Object deepCopy(List<Object> args, Map<String, Object> context) { validateArgs(args, 1, "deepCopy"); return deepCopyObject(args.get(0)); } private Object mustMerge(List<Object> args, Map<String, Object> context) { validateArgs(args, 2, "mustMerge"); Map<String, Object> base = (Map<String, Object>) args.get(0); Map<String, Object> overlay = (Map<String, Object>) args.get(1); return mergeMaps(base, overlay); } private Object mustToJson(List<Object> args, Map<String, Object> context) { validateArgs(args, 1, "mustToJson"); try { return serializeToJson(args.get(0)); } catch (Exception e) { throw new RuntimeException("Failed to convert to JSON", e); } } private Object mustToYaml(List<Object> args, Map<String, Object> context) { validateArgs(args, 1, "mustToYaml"); try { return serializeToYaml(args.get(0)); } catch (Exception e) { throw new RuntimeException("Failed to convert to YAML", e); } } /** * Utility Methods */ private void validateArgs(List<Object> args, int expected, String functionName) { if (args.size() < expected) { throw new IllegalArgumentException( String.format("Function %s requires at least %d arguments, got %d", functionName, expected, args.size())); } } private boolean isEmpty(Object obj) { if (obj == null) return true; if (obj instanceof String) return ((String) obj).trim().isEmpty(); if (obj instanceof Collection) return ((Collection<?>) obj).isEmpty(); if (obj instanceof Map) return ((Map<?, ?>) obj).isEmpty(); return false; } private Object deepCopyObject(Object obj) { // Simplified deep copy - in production use serialization if (obj instanceof Map) { Map<?, ?> original = (Map<?, ?>) obj; Map<Object, Object> copy = new HashMap<>(); for (Map.Entry<?, ?> entry : original.entrySet()) { copy.put(deepCopyObject(entry.getKey()), deepCopyObject(entry.getValue())); } return copy; } else if (obj instanceof List) { List<?> original = (List<?>) obj; List<Object> copy = new ArrayList<>(); for (Object item : original) { copy.add(deepCopyObject(item)); } return copy; } else { return obj; // Primitive types are immutable } } private Map<String, Object> mergeMaps(Map<String, Object> base, Map<String, Object> overlay) { Map<String, Object> result = new HashMap<>(base); for (Map.Entry<String, Object> entry : overlay.entrySet()) { if (entry.getValue() instanceof Map && base.get(entry.getKey()) instanceof Map) { // Recursive merge for nested maps result.put(entry.getKey(), mergeMaps((Map<String, Object>) base.get(entry.getKey()), (Map<String, Object>) entry.getValue())); } else { result.put(entry.getKey(), entry.getValue()); } } return result; } private String serializeToJson(Object obj) { // Simplified JSON serialization - use Jackson/Gson in production if (obj instanceof Map) { Map<?, ?> map = (Map<?, ?>) obj; StringBuilder sb = new StringBuilder("{"); for (Map.Entry<?, ?> entry : map.entrySet()) { if (sb.length() > 1) sb.append(","); sb.append("\"").append(entry.getKey()).append("\":") .append(serializeToJson(entry.getValue())); } sb.append("}"); return sb.toString(); } else if (obj instanceof List) { List<?> list = (List<?>) obj; StringBuilder sb = new StringBuilder("["); for (Object item : list) { if (sb.length() > 1) sb.append(","); sb.append(serializeToJson(item)); } sb.append("]"); return sb.toString(); } else if (obj instanceof String) { return "\"" + obj.toString().replace("\"", "\\\"") + "\""; } else { return String.valueOf(obj); } } private String serializeToYaml(Object obj) { // Simplified YAML serialization return serializeToYaml(obj, 0); } private String serializeToYaml(Object obj, int indent) { String indentStr = " ".repeat(indent); if (obj instanceof Map) { Map<?, ?> map = (Map<?, ?>) obj; StringBuilder sb = new StringBuilder(); for (Map.Entry<?, ?> entry : map.entrySet()) { if (sb.length() > 0) sb.append("\n"); sb.append(indentStr).append(entry.getKey()).append(": "); if (entry.getValue() instanceof Map || entry.getValue() instanceof List) { sb.append("\n").append(serializeToYaml(entry.getValue(), indent + 1)); } else { sb.append(serializeToYaml(entry.getValue(), 0)); } } return sb.toString(); } else if (obj instanceof List) { List<?> list = (List<?>) obj; StringBuilder sb = new StringBuilder(); for (Object item : list) { if (sb.length() > 0) sb.append("\n"); sb.append(indentStr).append("- ").append(serializeToYaml(item, indent + 1)); } return sb.toString(); } else if (obj instanceof String) { String str = obj.toString(); if (str.contains("\n") || str.contains(":") || str.trim().isEmpty()) { return "|\n" + indentStr + " " + str.replace("\n", "\n" + indentStr + " "); } return str; } else { return String.valueOf(obj); } } private String serializeToToml(Object obj) { // Simplified TOML serialization if (obj instanceof Map) { Map<?, ?> map = (Map<?, ?>) obj; StringBuilder sb = new StringBuilder(); for (Map.Entry<?, ?> entry : map.entrySet()) { if (sb.length() > 0) sb.append("\n"); sb.append(entry.getKey()).append(" = ").append(serializeToToml(entry.getValue())); } return sb.toString(); } else if (obj instanceof String) { return "\"" + obj.toString().replace("\"", "\\\"") + "\""; } else { return String.valueOf(obj); } } /** * Template Execution Engine */ public String executeTemplate(String template, Map<String, Object> context) { // Simplified template engine - in reality would use proper parsing Pattern pattern = Pattern.compile("\\{\\{([^}]+)\\}\\}"); Matcher matcher = pattern.matcher(template); StringBuffer result = new StringBuffer(); while (matcher.find()) { String expression = matcher.group(1).trim(); Object value = evaluateExpression(expression, context); matcher.appendReplacement(result, Matcher.quoteReplacement(String.valueOf(value))); } matcher.appendTail(result); return result.toString(); } private Object evaluateExpression(String expression, Map<String, Object> context) { // Check if it's a function call if (expression.contains("(") && expression.endsWith(")")) { return evaluateFunctionCall(expression, context); } // Otherwise, treat as variable reference return resolveVariable(expression, context); } private Object evaluateFunctionCall(String expression, Map<String, Object> context) { int parenIndex = expression.indexOf('('); String functionName = expression.substring(0, parenIndex).trim(); String argsStr = expression.substring(parenIndex + 1, expression.length() - 1); List<Object> args = parseArguments(argsStr, context); TemplateFunction function = functions.get(functionName); if (function == null) { throw new IllegalArgumentException("Unknown function: " + functionName); } return function.apply(args, context); } private List<Object> parseArguments(String argsStr, Map<String, Object> context) { // Simplified argument parsing List<Object> args = new ArrayList<>(); String[] parts = argsStr.split("\\s*,\\s*"); for (String part : parts) { part = part.trim(); if (part.startsWith("\"") && part.endsWith("\"")) { // String literal args.add(part.substring(1, part.length() - 1)); } else if (part.matches("-?\\d+")) { // Integer args.add(Integer.parseInt(part)); } else if (part.matches("-?\\d+\\.\\d+")) { // Float args.add(Double.parseDouble(part)); } else if (part.equals("true") || part.equals("false")) { // Boolean args.add(Boolean.parseBoolean(part)); } else { // Variable reference args.add(resolveVariable(part, context)); } } return args; } private Object resolveVariable(String path, Map<String, Object> context) { String[] parts = path.split("\\."); Object current = context; for (String part : parts) { if (current instanceof Map) { current = ((Map<String, Object>) current).get(part); } else { return null; // Path not found } } return current; } /** * Demo and Usage Examples */ public static void main(String[] args) { HelmTemplateEngine engine = new HelmTemplateEngine(); // Set up context with values Map<String, Object> context = new HashMap<>(); Map<String, Object> values = new HashMap<>(); values.put("appName", "my-application"); values.put("replicaCount", 3); values.put("image", Map.of( "repository", "nginx", "tag", "latest", "pullPolicy", "IfNotPresent" )); context.put("Values", values); // Example templates String[] templates = { "Application: {{ upper .Values.appName }}", "Replicas: {{ .Values.replicaCount }}", "Image: {{ .Values.image.repository }}:{{ .Values.image.tag }}", "Base64: {{ .Values.appName | b64enc }}", "SHA256: {{ .Values.appName | sha256sum }}", "List: {{ list \"a\" \"b\" \"c\" | toJson }}", "Math: {{ add .Values.replicaCount 2 }}", "Default: {{ .Values.nonExistent | default \"default-value\" }}" }; System.out.println("🚀 Helm Template Functions Demo"); System.out.println("===============================\n"); for (String template : templates) { try { String result = engine.executeTemplate(template, context); System.out.println("Template: " + template); System.out.println("Result: " + result); System.out.println(); } catch (Exception e) { System.out.println("Template: " + template); System.out.println("Error: " + e.getMessage()); System.out.println(); } } // Test individual functions System.out.println("🔧 Individual Function Tests"); System.out.println("===========================\n"); testFunction(engine, "upper", Arrays.asList("hello"), "HELLO"); testFunction(engine, "lower", Arrays.asList("WORLD"), "world"); testFunction(engine, "b64enc", Arrays.asList("secret"), "c2VjcmV0"); testFunction(engine, "add", Arrays.asList(5, 3), 8.0); testFunction(engine, "default", Arrays.asList("default", null), "default"); } private static void testFunction(HelmTemplateEngine engine, String functionName, List<Object> args, Object expected) { try { TemplateFunction function = engine.functions.get(functionName); Object result = function.apply(args, new HashMap<>()); boolean success = Objects.equals(result, expected); System.out.printf("%s(%s) = %s %s%n", functionName, args, result, success ? "✅" : "❌ (expected: " + expected + ")"); } catch (Exception e) { System.out.printf("%s(%s) = ERROR: %s ❌%n", functionName, args, e.getMessage()); } } } Spring Boot Integration
/** * Spring Boot Service for Helm Template Processing */ @Service public class HelmTemplateService { @Autowired private HelmTemplateEngine templateEngine; /** * Generate Kubernetes manifests from Helm templates */ public String generateManifest(String template, Map<String, Object> values) { Map<String, Object> context = createTemplateContext(values); return templateEngine.executeTemplate(template, context); } /** * Generate multiple manifests for a chart */ public Map<String, String> generateChartManifests( Map<String, String> templates, Map<String, Object> values) { Map<String, Object> context = createTemplateContext(values); Map<String, String> manifests = new HashMap<>(); for (Map.Entry<String, String> entry : templates.entrySet()) { try { String manifest = templateEngine.executeTemplate(entry.getValue(), context); manifests.put(entry.getKey(), manifest); } catch (Exception e) { throw new RuntimeException("Failed to process template: " + entry.getKey(), e); } } return manifests; } private Map<String, Object> createTemplateContext(Map<String, Object> values) { Map<String, Object> context = new HashMap<>(); // Set up built-in objects BuiltInObjects builtInObjects = new BuiltInObjects(); builtInObjects.getValues().putAll(values); context.put("Values", builtInObjects.getValues()); context.put("Chart", builtInObjects.getChart()); context.put("Release", builtInObjects.getRelease()); context.put("Capabilities", builtInObjects.getCapabilities()); context.put("Template", builtInObjects.getTemplate()); return context; } /** * Validate template syntax */ public boolean validateTemplate(String template) { try { // Test execution with empty context templateEngine.executeTemplate(template, new HashMap<>()); return true; } catch (Exception e) { return false; } } } This Helm Template Functions implementation provides:
- Complete function set matching Helm's Sprig template functions
- String manipulation (upper, lower, trim, replace, etc.)
- Math operations (add, sub, mul, div, mod, etc.)
- List operations (list, first, last, append, reverse, etc.)
- Type conversion (toInt, toFloat, toJson, toYaml, etc.)
- Cryptographic functions (b64enc, b64dec, sha256sum)
- Date functions (now, date, unixEpoch)
- Flow control (default, empty, ternary, required, fail)
- Kubernetes-specific functions for manifest generation
The implementation can be used for Helm template processing, Kubernetes manifest generation, or any other templating needs that require Helm-compatible functions.
Pyroscope Profiling in Java
Explains how to use Pyroscope for continuous profiling in Java applications, helping developers analyze CPU and memory usage patterns to improve performance and identify bottlenecks.
https://macronepal.com/blog/pyroscope-profiling-in-java/
OpenTelemetry Metrics in Java: Comprehensive Guide
Provides a complete guide to collecting and exporting metrics in Java using OpenTelemetry, including counters, histograms, gauges, and integration with monitoring tools. (MACRO NEPAL)
https://macronepal.com/blog/opentelemetry-metrics-in-java-comprehensive-guide/
OTLP Exporter in Java: Complete Guide for OpenTelemetry
Explains how to configure OTLP exporters in Java to send telemetry data such as traces, metrics, and logs to monitoring systems using HTTP or gRPC protocols. (MACRO NEPAL)
https://macronepal.com/blog/otlp-exporter-in-java-complete-guide-for-opentelemetry/
Thanos Integration in Java: Global View of Metrics
Explains how to integrate Thanos with Java monitoring systems to create a scalable global metrics view across multiple Prometheus instances.
https://macronepal.com/blog/thanos-integration-in-java-global-view-of-metrics
Time Series with InfluxDB in Java: Complete Guide (Version 2)
Explains how to manage time-series data using InfluxDB in Java applications, including storing, querying, and analyzing metrics data.
https://macronepal.com/blog/time-series-with-influxdb-in-java-complete-guide-2
Time Series with InfluxDB in Java: Complete Guide
Provides an overview of integrating InfluxDB with Java for time-series data handling, including monitoring applications and managing performance metrics.
https://macronepal.com/blog/time-series-with-influxdb-in-java-complete-guide
Implementing Prometheus Remote Write in Java (Version 2)
Explains how to configure Java applications to send metrics data to Prometheus-compatible systems using the remote write feature for scalable monitoring.
https://macronepal.com/blog/implementing-prometheus-remote-write-in-java-a-complete-guide-2
Implementing Prometheus Remote Write in Java: Complete Guide
Provides instructions for sending metrics from Java services to Prometheus servers, enabling centralized monitoring and real-time analytics.
https://macronepal.com/blog/implementing-prometheus-remote-write-in-java-a-complete-guide
Building a TileServer GL in Java: Vector and Raster Tile Server
Explains how to build a TileServer GL in Java for serving vector and raster map tiles, useful for geographic visualization and mapping applications.
https://macronepal.com/blog/building-a-tileserver-gl-in-java-vector-and-raster-tile-server
Indoor Mapping in Java
Explains how to create indoor mapping systems in Java, including navigation inside buildings, spatial data handling, and visualization techniques.