282 lines
8.2 KiB
Go
282 lines
8.2 KiB
Go
package models
|
|
|
|
import (
|
|
"encoding/json"
|
|
|
|
"strings"
|
|
|
|
"github.com/golang/glog"
|
|
|
|
"kubesphere.io/kubesphere/pkg/client"
|
|
|
|
ksutil "kubesphere.io/kubesphere/pkg/util"
|
|
|
|
"fmt"
|
|
"strconv"
|
|
|
|
"k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"kubesphere.io/kubesphere/pkg/constants"
|
|
"math"
|
|
)
|
|
|
|
type ResultPod struct {
|
|
PodName string `json:"pod_name"`
|
|
NameSpace string `json:"namespace"`
|
|
NodeName string `json:"node_name"`
|
|
CPURequest string `json:"cpu_request"`
|
|
CPULimit string `json:"cpu_limit"`
|
|
MemoryRequest string `json:"mem_request"`
|
|
MemoryLimit string `json:"mem_limit"`
|
|
CPU []CPUPod `json:"cpu"`
|
|
Memory []MemoryPod `json:"memory"`
|
|
}
|
|
type CPUPod struct {
|
|
TimeStamp string `json:"timestamp"`
|
|
UsedCPU string `json:"used_cpu"`
|
|
CPUUtilization string `json:"cpu_utilization"`
|
|
}
|
|
|
|
type MemoryPod struct {
|
|
TimeStamp string `json:"timestamp"`
|
|
UsedMemory string `json:"used_mem"`
|
|
MemoryUtilization string `json:"mem_utilization"`
|
|
}
|
|
|
|
/*
|
|
Get all namespaces in default cluster
|
|
*/
|
|
func GetNameSpaces() []string {
|
|
namespacesList := client.GetHeapsterMetrics("/namespaces")
|
|
var namespaces []string
|
|
dec := json.NewDecoder(strings.NewReader(namespacesList))
|
|
err := dec.Decode(&namespaces)
|
|
if err != nil {
|
|
glog.Error(err)
|
|
}
|
|
return namespaces
|
|
}
|
|
|
|
/*
|
|
Get all pods under specified namespace in default cluster
|
|
*/
|
|
func GetPods(namespace string) []string {
|
|
podsList := client.GetHeapsterMetrics("/namespaces/" + namespace + "/pods")
|
|
var pods []string
|
|
dec := json.NewDecoder(strings.NewReader(podsList))
|
|
err := dec.Decode(&pods)
|
|
if err != nil {
|
|
glog.Error(err)
|
|
}
|
|
return pods
|
|
}
|
|
|
|
func GetPodsForNode(nodeName, namespace string) []string {
|
|
var pods []string
|
|
cli := client.NewK8sClient()
|
|
podList, err := cli.CoreV1().Pods(namespace).List(v1.ListOptions{FieldSelector: "spec.nodeName=" + nodeName})
|
|
if err != nil {
|
|
glog.Error(err)
|
|
} else {
|
|
for _, pod := range podList.Items {
|
|
pods = append(pods, pod.Name)
|
|
}
|
|
}
|
|
return pods
|
|
}
|
|
|
|
func FormatPodsMetrics(nodeName, namespace string) constants.PageableResponse {
|
|
var result constants.PageableResponse
|
|
|
|
var resultPod ResultPod
|
|
var pods []string
|
|
if nodeName == "" {
|
|
pods = GetPods(namespace)
|
|
} else {
|
|
pods = GetPodsForNode(nodeName, namespace)
|
|
}
|
|
|
|
var total_count int
|
|
for i, pod := range pods {
|
|
resultPod = FormatPodMetrics(namespace, pod)
|
|
if nodeName != "" {
|
|
resultPod.NodeName = nodeName
|
|
} else {
|
|
resultPod.NodeName = GetNodeNameForPod(pod, namespace)
|
|
}
|
|
result.Items = append(result.Items, resultPod)
|
|
total_count = i
|
|
}
|
|
result.TotalCount = total_count + 1
|
|
return result
|
|
}
|
|
|
|
func FormatPodMetrics(namespace, pod string) ResultPod {
|
|
|
|
var resultPod ResultPod
|
|
var podCPUMetrics []CPUPod
|
|
var podMemMetrics []MemoryPod
|
|
var cpuMetrics CPUPod
|
|
var memMetrics MemoryPod
|
|
|
|
resultPod.PodName = pod
|
|
resultPod.NameSpace = namespace
|
|
cpuRequest := client.GetHeapsterMetrics("/namespaces/" + namespace + "/pods/" + pod + "/metrics/cpu/request")
|
|
cpuRequest = ksutil.JsonRawMessage(cpuRequest).Find("metrics").ToList()[0].Find("value").ToString()
|
|
if cpuRequest != "" && cpuRequest != "0" {
|
|
resultPod.CPURequest = cpuRequest
|
|
} else {
|
|
resultPod.CPURequest = "inf"
|
|
}
|
|
|
|
cpuLimit := client.GetHeapsterMetrics("/namespaces/" + namespace + "/pods/" + pod + "/metrics/cpu/limit")
|
|
cpuLimit = ksutil.JsonRawMessage(cpuLimit).Find("metrics").ToList()[0].Find("value").ToString()
|
|
if cpuLimit != "" && cpuLimit != "0" {
|
|
resultPod.CPULimit = cpuLimit
|
|
} else {
|
|
resultPod.CPULimit = "inf"
|
|
}
|
|
memoryRequest := ksutil.JsonRawMessage(client.GetHeapsterMetrics("/namespaces/" + namespace + "/pods/" + pod + "/metrics/memory/request")).Find("metrics").ToList()[0].Find("value").ToString()
|
|
resultPod.MemoryRequest = ConvertMemory(memoryRequest)
|
|
|
|
memoryLimit := ksutil.JsonRawMessage(client.GetHeapsterMetrics("/namespaces/" + namespace + "/pods/" + pod + "/metrics/memory/limit")).Find("metrics").ToList()[0].Find("value").ToString()
|
|
resultPod.MemoryLimit = ConvertMemory(memoryLimit)
|
|
|
|
cpuUsageRate := client.GetHeapsterMetrics("/namespaces/" + namespace + "/pods/" + pod + "/metrics/cpu/usage_rate")
|
|
if cpuUsageRate != "" {
|
|
metrics := ksutil.JsonRawMessage(cpuUsageRate).Find("metrics").ToList()
|
|
|
|
for _, metric := range metrics {
|
|
timestamp := metric.Find("timestamp")
|
|
cpu_utilization, _ := strconv.ParseFloat(ConvertCPUUsageRate(metric.Find("value").ToString()), 64)
|
|
cpuMetrics.TimeStamp = timestamp.ToString()
|
|
cpuMetrics.CPUUtilization = fmt.Sprintf("%.3f", cpu_utilization)
|
|
if resultPod.CPULimit != "inf" {
|
|
cpu_limit, _ := strconv.ParseFloat(resultPod.CPULimit, 64)
|
|
cpuMetrics.UsedCPU = fmt.Sprintf("%.1f", cpu_limit*cpu_utilization)
|
|
} else {
|
|
cpuMetrics.UsedCPU = "inf"
|
|
}
|
|
glog.Info("pod " + pod + " has limit cpu " + resultPod.CPULimit + " CPU utilization " + fmt.Sprintf("%.3f", cpu_utilization) + " at time" + timestamp.ToString())
|
|
podCPUMetrics = append(podCPUMetrics, cpuMetrics)
|
|
}
|
|
|
|
}
|
|
|
|
resultPod.CPU = podCPUMetrics
|
|
|
|
var used_mem_bytes float64
|
|
|
|
memUsage := client.GetHeapsterMetrics("/namespaces/" + namespace + "/pods/" + pod + "/metrics/memory/usage")
|
|
if memUsage != "" {
|
|
metrics := ksutil.JsonRawMessage(memUsage).Find("metrics").ToList()
|
|
|
|
for _, metric := range metrics {
|
|
timestamp := metric.Find("timestamp")
|
|
used_mem_bytes, _ = strconv.ParseFloat(metric.Find("value").ToString(), 64)
|
|
used_mem := used_mem_bytes / 1024 / 1024
|
|
memMetrics.TimeStamp = timestamp.ToString()
|
|
memMetrics.UsedMemory = fmt.Sprintf("%.1f", used_mem)
|
|
memMetrics.MemoryUtilization = fmt.Sprintf("%.3f", CalculateMemoryUsage(memoryRequest, memoryLimit, metric.Find("value").ToString()))
|
|
|
|
glog.Info("pod " + pod + " has limit mem " + resultPod.MemoryLimit + " mem utilization " + memMetrics.MemoryUtilization + " at time" + timestamp.ToString())
|
|
podMemMetrics = append(podMemMetrics, memMetrics)
|
|
}
|
|
}
|
|
|
|
resultPod.Memory = podMemMetrics
|
|
return resultPod
|
|
}
|
|
|
|
func ConvertMemory(memBytes string) string {
|
|
var mem string
|
|
|
|
if memBytes != "" {
|
|
if memBytes != "" && memBytes != "0" {
|
|
memBytes, error := strconv.ParseFloat(memBytes, 64)
|
|
if error == nil {
|
|
mem = fmt.Sprintf("%.3f", memBytes/1024/1024)
|
|
} else {
|
|
mem = "inf"
|
|
}
|
|
} else {
|
|
mem = "inf"
|
|
}
|
|
|
|
} else {
|
|
mem = "inf"
|
|
}
|
|
return mem
|
|
}
|
|
|
|
func CalculateMemoryUsage(requestMem, limitMem, usedMem string) float64 {
|
|
var requestMemInBytes, limitMemInBytes, usedMemInBytes, memUsage float64
|
|
if requestMem != "" && requestMem != "0" && requestMem != "inf" {
|
|
requestMemInBytes, _ = strconv.ParseFloat(requestMem, 64)
|
|
} else {
|
|
glog.Info("memory request is not set")
|
|
requestMemInBytes = 0
|
|
}
|
|
if limitMem != "" && limitMem != "0" && limitMem != "inf" {
|
|
limitMemInBytes, _ = strconv.ParseFloat(limitMem, 64)
|
|
} else {
|
|
glog.Info("memory limit is not set")
|
|
limitMemInBytes = 0
|
|
}
|
|
if usedMem != "" && usedMem != "0" {
|
|
usedMemInBytes, _ = strconv.ParseFloat(usedMem, 64)
|
|
} else {
|
|
usedMemInBytes = 0
|
|
}
|
|
|
|
if usedMemInBytes > 0 {
|
|
if requestMemInBytes > 0 && limitMemInBytes > 0 {
|
|
if usedMemInBytes > requestMemInBytes {
|
|
glog.Info("used memory is higher than memory request")
|
|
memUsage = usedMemInBytes / limitMemInBytes
|
|
} else {
|
|
memUsage = usedMemInBytes / requestMemInBytes
|
|
}
|
|
} else if requestMemInBytes > 0 && limitMemInBytes == 0 {
|
|
if usedMemInBytes > requestMemInBytes {
|
|
glog.Info("used memory is higher than memory request")
|
|
memUsage = 0
|
|
} else {
|
|
memUsage = usedMemInBytes / requestMemInBytes
|
|
}
|
|
} else if requestMemInBytes == 0 && limitMemInBytes > 0 {
|
|
if usedMemInBytes <= limitMemInBytes {
|
|
memUsage = usedMemInBytes / limitMemInBytes
|
|
}
|
|
} else {
|
|
memUsage = 0
|
|
}
|
|
} else {
|
|
memUsage = 0
|
|
}
|
|
return memUsage
|
|
}
|
|
|
|
func ConvertCPUUsageRate(cpuUsageRate string) string {
|
|
if cpuUsageRate != "" && cpuUsageRate != "0" {
|
|
rate, _ := strconv.ParseFloat(cpuUsageRate, 64)
|
|
rateBase := math.Pow10(strings.Count(cpuUsageRate, "") - 1)
|
|
return fmt.Sprintf("%.3f", rate/rateBase)
|
|
} else {
|
|
return "0"
|
|
}
|
|
}
|
|
|
|
func GetNodeNameForPod(podName, namespace string) string {
|
|
var nodeName string
|
|
cli := client.NewK8sClient()
|
|
|
|
pod, err := cli.CoreV1().Pods(namespace).Get(podName, v1.GetOptions{})
|
|
|
|
if err != nil {
|
|
glog.Error(err)
|
|
} else {
|
|
nodeName = pod.Spec.NodeName
|
|
}
|
|
return nodeName
|
|
}
|