diff --git a/cameleer3-server-core/src/main/java/com/cameleer3/server/core/runtime/ConfigMerger.java b/cameleer3-server-core/src/main/java/com/cameleer3/server/core/runtime/ConfigMerger.java new file mode 100644 index 00000000..e74441f7 --- /dev/null +++ b/cameleer3-server-core/src/main/java/com/cameleer3/server/core/runtime/ConfigMerger.java @@ -0,0 +1,96 @@ +package com.cameleer3.server.core.runtime; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public final class ConfigMerger { + + private ConfigMerger() {} + + public static ResolvedContainerConfig resolve( + GlobalRuntimeDefaults global, + Map envConfig, + Map appConfig) { + + return new ResolvedContainerConfig( + intVal(appConfig, envConfig, "memoryLimitMb", global.memoryLimitMb()), + intOrNull(appConfig, envConfig, "memoryReserveMb"), + intVal(appConfig, envConfig, "cpuShares", global.cpuShares()), + doubleOrNull(appConfig, envConfig, "cpuLimit"), + intVal(appConfig, envConfig, "appPort", 8080), + intList(appConfig, envConfig, "exposedPorts"), + stringMap(appConfig, envConfig, "customEnvVars"), + boolVal(appConfig, envConfig, "stripPathPrefix", true), + boolVal(appConfig, envConfig, "sslOffloading", true), + stringVal(appConfig, envConfig, "routingMode", global.routingMode()), + stringVal(appConfig, envConfig, "routingDomain", global.routingDomain()), + stringVal(appConfig, envConfig, "serverUrl", global.serverUrl()), + intVal(appConfig, envConfig, "replicas", 1), + stringVal(appConfig, envConfig, "deploymentStrategy", "blue-green") + ); + } + + private static int intVal(Map app, Map env, String key, int fallback) { + if (app.containsKey(key) && app.get(key) instanceof Number n) return n.intValue(); + if (env.containsKey(key) && env.get(key) instanceof Number n) return n.intValue(); + return fallback; + } + + private static Integer intOrNull(Map app, Map env, String key) { + if (app.containsKey(key) && app.get(key) instanceof Number n) return n.intValue(); + if (env.containsKey(key) && env.get(key) instanceof Number n) return n.intValue(); + return null; + } + + private static Double doubleOrNull(Map app, Map env, String key) { + if (app.containsKey(key) && app.get(key) instanceof Number n) return n.doubleValue(); + if (env.containsKey(key) && env.get(key) instanceof Number n) return n.doubleValue(); + return null; + } + + private static boolean boolVal(Map app, Map env, String key, boolean fallback) { + if (app.containsKey(key) && app.get(key) instanceof Boolean b) return b; + if (env.containsKey(key) && env.get(key) instanceof Boolean b) return b; + return fallback; + } + + private static String stringVal(Map app, Map env, String key, String fallback) { + if (app.containsKey(key) && app.get(key) instanceof String s) return s; + if (env.containsKey(key) && env.get(key) instanceof String s) return s; + return fallback; + } + + @SuppressWarnings("unchecked") + private static List intList(Map app, Map env, String key) { + Object val = app.containsKey(key) ? app.get(key) : env.get(key); + if (val instanceof List list) { + return list.stream() + .filter(Number.class::isInstance) + .map(n -> ((Number) n).intValue()) + .toList(); + } + return List.of(); + } + + @SuppressWarnings("unchecked") + private static Map stringMap(Map app, Map env, String key) { + Object val = app.containsKey(key) ? app.get(key) : env.get(key); + if (val instanceof Map map) { + Map result = new HashMap<>(); + map.forEach((k, v) -> result.put(String.valueOf(k), String.valueOf(v))); + return Collections.unmodifiableMap(result); + } + return Map.of(); + } + + /** Global defaults extracted from application.yml @Value fields */ + public record GlobalRuntimeDefaults( + int memoryLimitMb, + int cpuShares, + String routingMode, + String routingDomain, + String serverUrl + ) {} +} diff --git a/cameleer3-server-core/src/main/java/com/cameleer3/server/core/runtime/ResolvedContainerConfig.java b/cameleer3-server-core/src/main/java/com/cameleer3/server/core/runtime/ResolvedContainerConfig.java new file mode 100644 index 00000000..65bcd65f --- /dev/null +++ b/cameleer3-server-core/src/main/java/com/cameleer3/server/core/runtime/ResolvedContainerConfig.java @@ -0,0 +1,29 @@ +package com.cameleer3.server.core.runtime; + +import java.util.List; +import java.util.Map; + +public record ResolvedContainerConfig( + int memoryLimitMb, + Integer memoryReserveMb, + int cpuShares, + Double cpuLimit, + int appPort, + List exposedPorts, + Map customEnvVars, + boolean stripPathPrefix, + boolean sslOffloading, + String routingMode, + String routingDomain, + String serverUrl, + int replicas, + String deploymentStrategy +) { + public long memoryLimitBytes() { + return (long) memoryLimitMb * 1024 * 1024; + } + + public Long memoryReserveBytes() { + return memoryReserveMb != null ? (long) memoryReserveMb * 1024 * 1024 : null; + } +}