mirror of
https://github.com/MAKS-IT-COM/maksit-cluster-console.git
synced 2026-11-13 20:26:10 +01:00
160 lines
4.2 KiB
C#
160 lines
4.2 KiB
C#
using System.Text.Json.Nodes;
|
|
|
|
|
|
namespace MaksIT.ClusterConsole.Client.Cluster;
|
|
|
|
public sealed record ClusterSummary(
|
|
string GitVersion,
|
|
string Platform,
|
|
int NodeCount,
|
|
int PodCount);
|
|
|
|
public sealed record ResourceSlice(
|
|
double Used,
|
|
double Requests,
|
|
double Limits,
|
|
double Allocatable,
|
|
double Capacity,
|
|
string Kind) {
|
|
public static ResourceSlice Empty(string kind) => new(0, 0, 0, 0, 0, kind);
|
|
|
|
public double Scale =>
|
|
Math.Max(1, new[] { Used, Requests, Limits, Allocatable, Capacity }.Max());
|
|
|
|
public double UsedPercent => Percent(Used);
|
|
|
|
public double RequestsPercent => Percent(Requests);
|
|
|
|
public double LimitsPercent => Percent(Limits);
|
|
|
|
public double AllocatablePercent => Percent(Allocatable);
|
|
|
|
public double CapacityPercent => Percent(Capacity);
|
|
|
|
public bool ShowRequestsAndLimits => Kind is "cpu" or "memory";
|
|
|
|
public bool LimitsExceedCapacity => ShowRequestsAndLimits && Limits > Capacity && Capacity > 0;
|
|
|
|
public string UsageLine => $"Usage: {Format(Used)}";
|
|
|
|
public string RequestsLine => $"Requests: {Format(Requests)}";
|
|
|
|
public string LimitsLine => $"Limits: {Format(Limits)}";
|
|
|
|
public string AllocatableLine => $"Allocatable Capacity: {Format(Allocatable)}";
|
|
|
|
public string CapacityLine => $"Capacity: {Format(Capacity)}";
|
|
|
|
public string LimitsWarning =>
|
|
LimitsExceedCapacity ? "Specified limits are higher than node capacity!" : "";
|
|
|
|
public string Caption => $"{Format(Used)} / {Format(Allocatable)}";
|
|
|
|
private double Percent(double value) =>
|
|
Math.Clamp(value / Scale * 100, 0, 100);
|
|
|
|
private string Format(double value) => Kind switch {
|
|
"cpu" => KubeQuantity.FormatCoresFixed(value),
|
|
"memory" => KubeQuantity.FormatBytesCompact((long)Math.Round(value)),
|
|
_ => value.ToString("0")
|
|
};
|
|
}
|
|
|
|
public sealed record ClusterUsage(
|
|
string GitVersion,
|
|
string Platform,
|
|
int NodeCount,
|
|
ResourceSlice Cpu,
|
|
ResourceSlice Memory,
|
|
ResourceSlice Pods,
|
|
IReadOnlyList<NodeUsage> Nodes,
|
|
IReadOnlyList<WorkloadContainerLimit> ContainerLimits,
|
|
bool MetricsAvailable,
|
|
string? MetricsMessage) {
|
|
public double CpuPercent => Percent(Cpu.Used, Cpu.Allocatable);
|
|
|
|
public double MemoryPercent => Percent(Memory.Used, Memory.Allocatable);
|
|
|
|
public double PodPercent => Percent(Pods.Used, Pods.Allocatable);
|
|
|
|
public string CpuCaption => Cpu.Caption;
|
|
|
|
public string MemoryCaption => Memory.Caption;
|
|
|
|
public string PodCaption => Pods.Caption;
|
|
|
|
private static double Percent(double used, double capacity) =>
|
|
capacity <= 0 ? 0 : Math.Clamp(used / capacity * 100, 0, 100);
|
|
}
|
|
|
|
public sealed record ResourceMetrics(
|
|
string Name,
|
|
string? Namespace,
|
|
string Cpu,
|
|
string Memory);
|
|
|
|
public sealed record ExecBytesResult(byte[] Stdout, string Stderr);
|
|
|
|
public sealed class ResourceListOptions {
|
|
public string? LabelSelector { get; init; }
|
|
|
|
public string? FieldSelector { get; init; }
|
|
|
|
public string? ResourceVersion { get; set; }
|
|
}
|
|
|
|
public sealed record ClusterWatchEvent(string Type, JsonObject? Object);
|
|
|
|
public sealed record HelmReleaseInfo(
|
|
string Name,
|
|
string Namespace,
|
|
string Status,
|
|
string Chart,
|
|
string AppVersion,
|
|
DateTimeOffset? Updated);
|
|
|
|
public sealed record PortForwardEndpoint(string PodName, string Namespace, int ContainerPort);
|
|
|
|
public sealed class PortForwardHandle : IDisposable {
|
|
private readonly IDisposable _inner;
|
|
private readonly Action? _onDispose;
|
|
|
|
public PortForwardHandle(
|
|
string podName,
|
|
string @namespace,
|
|
int containerPort,
|
|
int localPort,
|
|
IDisposable inner,
|
|
Action? onDispose = null,
|
|
int requestedPort = 0) {
|
|
PodName = podName;
|
|
Namespace = @namespace;
|
|
ContainerPort = containerPort;
|
|
LocalPort = localPort;
|
|
RequestedPort = requestedPort > 0 ? requestedPort : containerPort;
|
|
_inner = inner;
|
|
_onDispose = onDispose;
|
|
}
|
|
|
|
public string PodName { get; private set; }
|
|
|
|
public string Namespace { get; private set; }
|
|
|
|
public int ContainerPort { get; private set; }
|
|
|
|
public int RequestedPort { get; }
|
|
|
|
public int LocalPort { get; }
|
|
|
|
public void Retarget(string podName, string @namespace, int containerPort) {
|
|
PodName = podName;
|
|
Namespace = @namespace;
|
|
ContainerPort = containerPort;
|
|
}
|
|
|
|
public void Dispose() {
|
|
_onDispose?.Invoke();
|
|
_inner.Dispose();
|
|
}
|
|
}
|