package dev.dinauer; import dev.dinauer.utils.ClientProvider; import io.fabric8.kubernetes.api.model.Node; import io.fabric8.kubernetes.client.KubernetesClient; import io.fabric8.kubernetes.client.KubernetesClientBuilder; import io.quarkus.security.Authenticated; import io.smallrye.common.annotation.Blocking; import jakarta.annotation.PostConstruct; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.MediaType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.List; @Path("/nodes") @ApplicationScoped @Blocking @Authenticated public class NodeResource { private static final Logger LOG = LoggerFactory.getLogger(NodeResource.class); @Inject ClientProvider clientProvider; @GET @Produces(MediaType.APPLICATION_JSON) public List getMonitoring() throws IOException, InterruptedException { List result = new ArrayList<>(); List stats = getTopNodes(); for(String nodeName : stats) { String[] parts = nodeName.split("\\s+"); if(parts.length == 5) { String name = parts[0]; Node node = clientProvider.getClient().nodes().withName(name).get(); Integer absoluteCpu = extractInteger(parts[1]); Integer relativeCpu = extractInteger(parts[2]); Integer absoluteMemory = extractMemory(parts[3]); Integer relativeMemory = extractInteger(parts[4]); result.add(new NodeStats(node, absoluteCpu, relativeCpu, Integer.parseInt(node.getStatus().getAllocatable().get("cpu").getAmount()) * 1000, absoluteMemory, relativeMemory, extractMemory(node.getStatus().getAllocatable().get("memory").getAmount()))); } } return result; } private List getTopNodes() throws IOException, InterruptedException { List commands = List.of("kubectl", String.format("--kubeconfig=%s", clientProvider.pathToKubeconfig()), "top", "nodes", "--no-headers"); LOG.info("Executing command: {}", String.join(" ", commands)); ProcessBuilder pb = new ProcessBuilder(commands); Process p = pb.start(); List text = new ArrayList<>(); try(BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()))) { String line; while((line = br.readLine()) != null) { text.add(line); } } int exitCode = p.waitFor(); if(exitCode == 0) { LOG.info("Found {} nodes", text.size()); return text; } throw new RuntimeException("Failed to retrieve top nodes."); } public record NodeStats(Node node, Integer absoluteCpuUsage, Integer relativeCpuUsage, Integer totalCpu, Integer absoluteMemory, Integer relativeMemory, Integer totalMemory) { } private Integer extractInteger(String input) { return Integer.valueOf(input.replace("m", "").replace("%", "")); } private Integer extractMemory(String input) { if(input.contains("Ki")) { return Integer.parseInt(input.replace("Ki", "")); } if(input.contains("Mi")) { return Integer.parseInt(input.replace("Mi", "")) * 1024; } if(input.contains("Gi")) { return Integer.parseInt(input.replace("Gi", "")) * 1024 * 1024; } return Integer.parseInt(input); } }