diff --git a/backend/src/main/java/com/qqchen/deploy/backend/framework/utils/K8sResourceUtils.java b/backend/src/main/java/com/qqchen/deploy/backend/framework/utils/K8sResourceUtils.java new file mode 100644 index 00000000..d5de062b --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/framework/utils/K8sResourceUtils.java @@ -0,0 +1,159 @@ +package com.qqchen.deploy.backend.framework.utils; + +import lombok.extern.slf4j.Slf4j; + +/** + * K8s资源工具类 + * 用于解析和格式化K8s资源(CPU、内存) + */ +@Slf4j +public class K8sResourceUtils { + + private K8sResourceUtils() { + // 工具类,禁止实例化 + } + + /** + * 解析CPU资源字符串为毫核(millicores) + * 支持格式: + * - "2" -> 2000m (2核) + * - "2000m" -> 2000m + * - "0.5" -> 500m + * + * @param cpuStr CPU资源字符串 + * @return 毫核数 + */ + public static long parseCpuToMillicores(String cpuStr) { + if (cpuStr == null || cpuStr.isEmpty()) { + return 0; + } + + try { + if (cpuStr.endsWith("m")) { + // 已经是毫核格式,如"2000m" + return Long.parseLong(cpuStr.substring(0, cpuStr.length() - 1)); + } else { + // 核数格式,如"2"或"0.5",转换为毫核 + return (long) (Double.parseDouble(cpuStr) * 1000); + } + } catch (NumberFormatException e) { + log.warn("解析CPU资源失败: {}", cpuStr, e); + return 0; + } + } + + /** + * 解析内存资源字符串为字节数 + * 支持格式: + * - "4Gi" -> 4 * 1024 * 1024 * 1024 bytes + * - "512Mi" -> 512 * 1024 * 1024 bytes + * - "1024Ki" -> 1024 * 1024 bytes + * - "4G" -> 4 * 1000 * 1000 * 1000 bytes + * - "512M" -> 512 * 1000 * 1000 bytes + * - "1024K" -> 1024 * 1000 bytes + * - "1000000" -> 1000000 bytes + * + * @param memoryStr 内存资源字符串 + * @return 字节数 + */ + public static long parseMemoryToBytes(String memoryStr) { + if (memoryStr == null || memoryStr.isEmpty()) { + return 0; + } + + try { + // 二进制单位(1024进制) + if (memoryStr.endsWith("Gi")) { + return Long.parseLong(memoryStr.substring(0, memoryStr.length() - 2)) * 1024L * 1024L * 1024L; + } else if (memoryStr.endsWith("Mi")) { + return Long.parseLong(memoryStr.substring(0, memoryStr.length() - 2)) * 1024L * 1024L; + } else if (memoryStr.endsWith("Ki")) { + return Long.parseLong(memoryStr.substring(0, memoryStr.length() - 2)) * 1024L; + } + // 十进制单位(1000进制) + else if (memoryStr.endsWith("G")) { + return Long.parseLong(memoryStr.substring(0, memoryStr.length() - 1)) * 1000L * 1000L * 1000L; + } else if (memoryStr.endsWith("M")) { + return Long.parseLong(memoryStr.substring(0, memoryStr.length() - 1)) * 1000L * 1000L; + } else if (memoryStr.endsWith("K")) { + return Long.parseLong(memoryStr.substring(0, memoryStr.length() - 1)) * 1000L; + } else { + // 纯数字,单位为字节 + return Long.parseLong(memoryStr); + } + } catch (NumberFormatException e) { + log.warn("解析内存资源失败: {}", memoryStr, e); + return 0; + } + } + + /** + * 格式化CPU资源为K8s格式字符串 + * 优先使用整数核,如果不能整除则使用毫核或保留小数 + * + * @param millicores 毫核数 + * @return K8s格式字符串,如"2"、"2.5"、"500m" + */ + public static String formatCpuResource(long millicores) { + if (millicores == 0) { + return "0"; + } + + if (millicores % 1000 == 0) { + // 整数核,如2000m -> "2" + return String.valueOf(millicores / 1000); + } else if (millicores >= 1000) { + // 大于1核但不能整除,使用小数表示,如2500m -> "2.5" + double cores = millicores / 1000.0; + // 如果小数部分为0,显示整数;否则保留1位小数 + if (cores == Math.floor(cores)) { + return String.valueOf((long) cores); + } else { + return String.format("%.1f", cores); + } + } else { + // 小于1核,使用毫核格式,如"500m" + return millicores + "m"; + } + } + + /** + * 格式化内存资源为K8s格式字符串(使用二进制单位) + * 优先使用能整除的最大单位,如果都不能整除则选择最接近的单位并保留1位小数 + * + * @param bytes 字节数 + * @return K8s格式字符串,如"4Gi"、"15.6Gi"、"512Mi" + */ + public static String formatMemoryResource(long bytes) { + if (bytes == 0) { + return "0"; + } + + long gi = 1024L * 1024L * 1024L; + long mi = 1024L * 1024L; + long ki = 1024L; + + // 优先尝试整除转换 + if (bytes >= gi && bytes % gi == 0) { + return (bytes / gi) + "Gi"; + } else if (bytes >= mi && bytes % mi == 0) { + return (bytes / mi) + "Mi"; + } else if (bytes >= ki && bytes % ki == 0) { + return (bytes / ki) + "Ki"; + } + + // 如果不能整除,选择最接近的单位并保留1位小数 + if (bytes >= gi) { + double value = bytes / (double) gi; + return String.format("%.1fGi", value); + } else if (bytes >= mi) { + double value = bytes / (double) mi; + return String.format("%.1fMi", value); + } else if (bytes >= ki) { + double value = bytes / (double) ki; + return String.format("%.1fKi", value); + } else { + return String.valueOf(bytes); + } + } +}