Files
kubesphere/pkg/models/monitoring/utils.go
yuswift e9695cba4c fix spelling typo
Signed-off-by: yuswift <yuswift2018@gmail.com>
2021-07-15 11:06:07 +08:00

259 lines
9.4 KiB
Go

package monitoring
import (
"fmt"
"math/big"
"k8s.io/klog"
meteringclient "kubesphere.io/kubesphere/pkg/simple/client/metering"
"kubesphere.io/kubesphere/pkg/simple/client/monitoring"
)
const (
METER_RESOURCE_TYPE_CPU = iota
METER_RESOURCE_TYPE_MEM
METER_RESOURCE_TYPE_NET_INGRESS
METER_RESOURCE_TYPE_NET_EGRESS
METER_RESOURCE_TYPE_PVC
meteringConfigDir = "/etc/kubesphere/metering/"
meteringConfigName = "ks-metering.yaml"
meteringDefaultPrecision = 10
meteringFeePrecision = 3
)
var meterResourceUnitMap = map[int]string{
METER_RESOURCE_TYPE_CPU: "cores",
METER_RESOURCE_TYPE_MEM: "bytes",
METER_RESOURCE_TYPE_NET_INGRESS: "bytes",
METER_RESOURCE_TYPE_NET_EGRESS: "bytes",
METER_RESOURCE_TYPE_PVC: "bytes",
}
var MeterResourceMap = map[string]int{
"meter_cluster_cpu_usage": METER_RESOURCE_TYPE_CPU,
"meter_cluster_memory_usage": METER_RESOURCE_TYPE_MEM,
"meter_cluster_net_bytes_transmitted": METER_RESOURCE_TYPE_NET_EGRESS,
"meter_cluster_net_bytes_received": METER_RESOURCE_TYPE_NET_INGRESS,
"meter_cluster_pvc_bytes_total": METER_RESOURCE_TYPE_PVC,
"meter_node_cpu_usage": METER_RESOURCE_TYPE_CPU,
"meter_node_memory_usage_wo_cache": METER_RESOURCE_TYPE_MEM,
"meter_node_net_bytes_transmitted": METER_RESOURCE_TYPE_NET_EGRESS,
"meter_node_net_bytes_received": METER_RESOURCE_TYPE_NET_INGRESS,
"meter_node_pvc_bytes_total": METER_RESOURCE_TYPE_PVC,
"meter_workspace_cpu_usage": METER_RESOURCE_TYPE_CPU,
"meter_workspace_memory_usage": METER_RESOURCE_TYPE_MEM,
"meter_workspace_net_bytes_transmitted": METER_RESOURCE_TYPE_NET_EGRESS,
"meter_workspace_net_bytes_received": METER_RESOURCE_TYPE_NET_INGRESS,
"meter_workspace_pvc_bytes_total": METER_RESOURCE_TYPE_PVC,
"meter_namespace_cpu_usage": METER_RESOURCE_TYPE_CPU,
"meter_namespace_memory_usage_wo_cache": METER_RESOURCE_TYPE_MEM,
"meter_namespace_net_bytes_transmitted": METER_RESOURCE_TYPE_NET_EGRESS,
"meter_namespace_net_bytes_received": METER_RESOURCE_TYPE_NET_INGRESS,
"meter_namespace_pvc_bytes_total": METER_RESOURCE_TYPE_PVC,
"meter_application_cpu_usage": METER_RESOURCE_TYPE_CPU,
"meter_application_memory_usage_wo_cache": METER_RESOURCE_TYPE_MEM,
"meter_application_net_bytes_transmitted": METER_RESOURCE_TYPE_NET_EGRESS,
"meter_application_net_bytes_received": METER_RESOURCE_TYPE_NET_INGRESS,
"meter_application_pvc_bytes_total": METER_RESOURCE_TYPE_PVC,
"meter_workload_cpu_usage": METER_RESOURCE_TYPE_CPU,
"meter_workload_memory_usage_wo_cache": METER_RESOURCE_TYPE_MEM,
"meter_workload_net_bytes_transmitted": METER_RESOURCE_TYPE_NET_EGRESS,
"meter_workload_net_bytes_received": METER_RESOURCE_TYPE_NET_INGRESS,
"meter_workload_pvc_bytes_total": METER_RESOURCE_TYPE_PVC,
"meter_service_cpu_usage": METER_RESOURCE_TYPE_CPU,
"meter_service_memory_usage_wo_cache": METER_RESOURCE_TYPE_MEM,
"meter_service_net_bytes_transmitted": METER_RESOURCE_TYPE_NET_EGRESS,
"meter_service_net_bytes_received": METER_RESOURCE_TYPE_NET_INGRESS,
"meter_pod_cpu_usage": METER_RESOURCE_TYPE_CPU,
"meter_pod_memory_usage_wo_cache": METER_RESOURCE_TYPE_MEM,
"meter_pod_net_bytes_transmitted": METER_RESOURCE_TYPE_NET_EGRESS,
"meter_pod_net_bytes_received": METER_RESOURCE_TYPE_NET_INGRESS,
"meter_pod_pvc_bytes_total": METER_RESOURCE_TYPE_PVC,
}
func getMaxPointValue(points []monitoring.Point) string {
var max *big.Float
for i, p := range points {
if i == 0 {
max = new(big.Float).SetFloat64(p.Value())
}
pf := new(big.Float).SetFloat64(p.Value())
if pf.Cmp(max) == 1 {
max = pf
}
}
return fmt.Sprintf(generateFloatFormat(meteringDefaultPrecision), max)
}
func getMinPointValue(points []monitoring.Point) string {
var min *big.Float
for i, p := range points {
if i == 0 {
min = new(big.Float).SetFloat64(p.Value())
}
pf := new(big.Float).SetFloat64(p.Value())
if min.Cmp(pf) == 1 {
min = pf
}
}
return fmt.Sprintf(generateFloatFormat(meteringDefaultPrecision), min)
}
func getSumPointValue(points []monitoring.Point) string {
sum := new(big.Float).SetFloat64(0)
for _, p := range points {
pf := new(big.Float).SetFloat64(p.Value())
sum.Add(sum, pf)
}
return fmt.Sprintf(generateFloatFormat(meteringDefaultPrecision), sum)
}
func getAvgPointValue(points []monitoring.Point) string {
sum, ok := new(big.Float).SetString(getSumPointValue(points))
if !ok {
klog.Error("failed to parse big.Float")
return ""
}
length := new(big.Float).SetFloat64(float64(len(points)))
return fmt.Sprintf(generateFloatFormat(meteringDefaultPrecision), sum.Quo(sum, length))
}
func generateFloatFormat(precision int) string {
return "%." + fmt.Sprintf("%d", precision) + "f"
}
func getResourceUnit(meterName string) string {
if resourceType, ok := MeterResourceMap[meterName]; !ok {
klog.Errorf("invlaid meter %v", meterName)
return ""
} else {
return meterResourceUnitMap[resourceType]
}
}
func getFeeWithMeterName(meterName string, sum string, priceInfo meteringclient.PriceInfo) string {
s, ok := new(big.Float).SetString(sum)
if !ok {
klog.Error("failed to parse string to float")
return ""
}
if resourceType, ok := MeterResourceMap[meterName]; !ok {
klog.Errorf("invlaid meter %v", meterName)
return ""
} else {
switch resourceType {
case METER_RESOURCE_TYPE_CPU:
CpuPerCorePerHour := new(big.Float).SetFloat64(priceInfo.CpuPerCorePerHour)
tmp := s.Mul(s, CpuPerCorePerHour)
return fmt.Sprintf(generateFloatFormat(meteringFeePrecision), tmp)
case METER_RESOURCE_TYPE_MEM:
oneGiga := new(big.Float).SetInt64(1073741824)
MemPerGigabytesPerHour := new(big.Float).SetFloat64(priceInfo.MemPerGigabytesPerHour)
// transform unit from bytes to Gigabytes
s.Quo(s, oneGiga)
return fmt.Sprintf(generateFloatFormat(meteringFeePrecision), s.Mul(s, MemPerGigabytesPerHour))
case METER_RESOURCE_TYPE_NET_INGRESS:
oneMega := new(big.Float).SetInt64(1048576)
IngressNetworkTrafficPerMegabytesPerHour := new(big.Float).SetFloat64(priceInfo.IngressNetworkTrafficPerMegabytesPerHour)
// transform unit from bytes to Migabytes
s.Quo(s, oneMega)
return fmt.Sprintf(generateFloatFormat(meteringFeePrecision), s.Mul(s, IngressNetworkTrafficPerMegabytesPerHour))
case METER_RESOURCE_TYPE_NET_EGRESS:
oneMega := new(big.Float).SetInt64(1048576)
EgressNetworkTrafficPerMegabytesPerHour := new(big.Float).SetPrec(meteringFeePrecision).SetFloat64(priceInfo.EgressNetworkTrafficPerMegabytesPerHour)
// transform unit from bytes to Migabytes
s.Quo(s, oneMega)
return fmt.Sprintf(generateFloatFormat(meteringFeePrecision), s.Mul(s, EgressNetworkTrafficPerMegabytesPerHour))
case METER_RESOURCE_TYPE_PVC:
oneGiga := new(big.Float).SetInt64(1073741824)
PvcPerGigabytesPerHour := new(big.Float).SetPrec(meteringFeePrecision).SetFloat64(priceInfo.PvcPerGigabytesPerHour)
// transform unit from bytes to Gigabytes
s.Quo(s, oneGiga)
return fmt.Sprintf(generateFloatFormat(meteringFeePrecision), s.Mul(s, PvcPerGigabytesPerHour))
}
return ""
}
}
func updateMetricStatData(metric monitoring.Metric, scalingMap map[string]float64, priceInfo meteringclient.PriceInfo) monitoring.MetricData {
metricName := metric.MetricName
metricData := metric.MetricData
for index, metricValue := range metricData.MetricValues {
// calculate min, max, avg value first, then squash points with factor
if metricData.MetricType == monitoring.MetricTypeMatrix {
metricData.MetricValues[index].MinValue = getMinPointValue(metricValue.Series)
metricData.MetricValues[index].MaxValue = getMaxPointValue(metricValue.Series)
metricData.MetricValues[index].AvgValue = getAvgPointValue(metricValue.Series)
} else {
metricData.MetricValues[index].MinValue = getMinPointValue([]monitoring.Point{*metricValue.Sample})
metricData.MetricValues[index].MaxValue = getMaxPointValue([]monitoring.Point{*metricValue.Sample})
metricData.MetricValues[index].AvgValue = getAvgPointValue([]monitoring.Point{*metricValue.Sample})
}
// squash points if step is more than one hour and calculate sum and fee
var factor float64 = 1
if scalingMap != nil {
factor = scalingMap[metricName]
}
metricData.MetricValues[index].Series = squashPoints(metricData.MetricValues[index].Series, int(factor))
if metricData.MetricType == monitoring.MetricTypeMatrix {
sum := getSumPointValue(metricData.MetricValues[index].Series)
metricData.MetricValues[index].SumValue = sum
metricData.MetricValues[index].Fee = getFeeWithMeterName(metricName, sum, priceInfo)
} else {
sum := getSumPointValue([]monitoring.Point{*metricValue.Sample})
metricData.MetricValues[index].SumValue = sum
metricData.MetricValues[index].Fee = getFeeWithMeterName(metricName, sum, priceInfo)
}
metricData.MetricValues[index].CurrencyUnit = priceInfo.CurrencyUnit
metricData.MetricValues[index].ResourceUnit = getResourceUnit(metricName)
}
return metricData
}
func squashPoints(input []monitoring.Point, factor int) (output []monitoring.Point) {
if factor <= 0 {
klog.Errorln("factor should be positive")
return nil
}
for i := 0; i < len(input); i++ {
if i%factor == 0 {
output = append([]monitoring.Point{input[len(input)-1-i]}, output...)
} else {
output[0] = output[0].Add(input[len(input)-1-i])
}
}
return output
}