code
This commit is contained in:
150
metrics-row.go
Normal file
150
metrics-row.go
Normal file
@@ -0,0 +1,150 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/dustin/go-humanize"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
metricsv "k8s.io/metrics/pkg/client/clientset/versioned"
|
||||
)
|
||||
|
||||
type PodInfo struct {
|
||||
Name string
|
||||
Namespace string
|
||||
Status string
|
||||
ReadyContainers int
|
||||
ContainerCount int
|
||||
RestartCount int
|
||||
CPUUsage string
|
||||
MemoryUsage string
|
||||
Age time.Duration
|
||||
Node string
|
||||
IsStarting bool // Added to track if pod is starting or restarting
|
||||
}
|
||||
|
||||
func refreshData(clientset *kubernetes.Clientset, metricsClient *metricsv.Clientset, namespaces []string) ([]PodInfo, error) {
|
||||
pods, err := clientset.CoreV1().Pods("").List(context.Background(), metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error listing pods: %v", err)
|
||||
}
|
||||
|
||||
// Create a map for faster namespace lookups
|
||||
namespaceMap := make(map[string]bool)
|
||||
for _, ns := range namespaces {
|
||||
namespaceMap[ns] = true
|
||||
}
|
||||
|
||||
podMetricsMap := make(map[string]map[string]struct {
|
||||
CPU int64
|
||||
Memory int64
|
||||
})
|
||||
if metricsClient != nil {
|
||||
podMetrics, err := metricsClient.MetricsV1beta1().PodMetricses("").List(context.Background(), metav1.ListOptions{})
|
||||
if err == nil {
|
||||
for _, metric := range podMetrics.Items {
|
||||
nsKey := metric.Namespace
|
||||
// Only process metrics for specified namespaces
|
||||
if !namespaceMap[nsKey] {
|
||||
continue
|
||||
}
|
||||
|
||||
if _, ok := podMetricsMap[nsKey]; !ok {
|
||||
podMetricsMap[nsKey] = make(map[string]struct {
|
||||
CPU int64
|
||||
Memory int64
|
||||
})
|
||||
}
|
||||
var totalCPU, totalMemory int64
|
||||
for _, container := range metric.Containers {
|
||||
totalCPU += container.Usage.Cpu().MilliValue()
|
||||
totalMemory += container.Usage.Memory().Value()
|
||||
}
|
||||
podMetricsMap[nsKey][metric.Name] = struct {
|
||||
CPU int64
|
||||
Memory int64
|
||||
}{
|
||||
CPU: totalCPU,
|
||||
Memory: totalMemory,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var result []PodInfo
|
||||
for _, pod := range pods.Items {
|
||||
readyCount := 0
|
||||
restarts := 0
|
||||
nsKey := pod.Namespace
|
||||
// Only process pods for specified namespaces
|
||||
if !namespaceMap[nsKey] {
|
||||
continue
|
||||
}
|
||||
for _, status := range pod.Status.ContainerStatuses {
|
||||
if status.Ready {
|
||||
readyCount++
|
||||
}
|
||||
restarts += int(status.RestartCount)
|
||||
}
|
||||
podInfo := PodInfo{
|
||||
Name: pod.Name,
|
||||
Namespace: pod.Namespace,
|
||||
Status: string(pod.Status.Phase),
|
||||
ContainerCount: len(pod.Spec.Containers),
|
||||
ReadyContainers: readyCount,
|
||||
RestartCount: restarts,
|
||||
Age: time.Since(pod.CreationTimestamp.Time),
|
||||
//IP: pod.Status.PodIP,
|
||||
IsStarting: time.Since(pod.CreationTimestamp.Time) < 1*time.Minute || isPodStartingOrRestarting(pod),
|
||||
Node: pod.Spec.NodeName,
|
||||
}
|
||||
if metrics, ok := podMetricsMap[pod.Namespace][pod.Name]; ok {
|
||||
podInfo.CPUUsage = fmt.Sprintf("%dm", metrics.CPU)
|
||||
podInfo.MemoryUsage = humanize.Bytes(uint64(metrics.Memory))
|
||||
} else {
|
||||
podInfo.CPUUsage = "N/A"
|
||||
podInfo.MemoryUsage = "N/A"
|
||||
}
|
||||
result = append(result, podInfo)
|
||||
}
|
||||
sort.Slice(result, func(i, j int) bool {
|
||||
if result[i].Namespace == result[j].Namespace {
|
||||
return result[i].Name < result[j].Name
|
||||
}
|
||||
return result[i].Namespace < result[j].Namespace
|
||||
})
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Helper function to check if pod is starting or restarting
|
||||
func isPodStartingOrRestarting(pod v1.Pod) bool {
|
||||
// Check if pod is in Pending state
|
||||
if pod.Status.Phase == corev1.PodPending {
|
||||
return true
|
||||
}
|
||||
|
||||
// Check if any container is in waiting state with specific reasons
|
||||
for _, containerStatus := range pod.Status.ContainerStatuses {
|
||||
if containerStatus.State.Waiting != nil {
|
||||
reason := containerStatus.State.Waiting.Reason
|
||||
if reason == "ContainerCreating" ||
|
||||
reason == "PodInitializing" ||
|
||||
reason == "CrashLoopBackOff" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
// Check if container recently restarted (within last minute)
|
||||
if containerStatus.LastTerminationState.Terminated != nil {
|
||||
terminatedTime := containerStatus.LastTerminationState.Terminated.FinishedAt.Time
|
||||
if time.Since(terminatedTime) < 60*time.Second {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
Reference in New Issue
Block a user