97 lines
2.5 KiB
Go
97 lines
2.5 KiB
Go
|
|
// ABOUTME: Parses Kubernetes-style resource notation for CPU and memory.
|
||
|
|
// ABOUTME: CPU: "500m" = 0.5 cores, "2" = 2 cores.
|
||
|
|
// ABOUTME: Memory: "1Gi" = 1 GiB, "512Mi" = 512 MiB, "1G" = 1 GB.
|
||
|
|
package cgroup
|
||
|
|
|
||
|
|
import (
|
||
|
|
"fmt"
|
||
|
|
"strconv"
|
||
|
|
"strings"
|
||
|
|
)
|
||
|
|
|
||
|
|
// ParseCPU parses Kubernetes CPU notation to cores.
|
||
|
|
// Examples: "500m" => 0.5, "2" => 2.0, "100m" => 0.1, "2000m" => 2.0
|
||
|
|
func ParseCPU(value string) (float64, error) {
|
||
|
|
value = strings.TrimSpace(value)
|
||
|
|
if value == "" {
|
||
|
|
return 0, fmt.Errorf("empty CPU value")
|
||
|
|
}
|
||
|
|
|
||
|
|
// Handle millicores suffix
|
||
|
|
if strings.HasSuffix(value, "m") {
|
||
|
|
millis, err := strconv.ParseFloat(strings.TrimSuffix(value, "m"), 64)
|
||
|
|
if err != nil {
|
||
|
|
return 0, fmt.Errorf("parsing millicores: %w", err)
|
||
|
|
}
|
||
|
|
return millis / 1000.0, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// Plain number means cores
|
||
|
|
cores, err := strconv.ParseFloat(value, 64)
|
||
|
|
if err != nil {
|
||
|
|
return 0, fmt.Errorf("parsing cores: %w", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
return cores, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// ParseMemory parses Kubernetes memory notation to bytes.
|
||
|
|
// Supports:
|
||
|
|
// - Binary suffixes: Ki, Mi, Gi, Ti (powers of 1024)
|
||
|
|
// - Decimal suffixes: K, M, G, T (powers of 1000)
|
||
|
|
// - Plain numbers: bytes
|
||
|
|
func ParseMemory(value string) (uint64, error) {
|
||
|
|
value = strings.TrimSpace(value)
|
||
|
|
if value == "" {
|
||
|
|
return 0, fmt.Errorf("empty memory value")
|
||
|
|
}
|
||
|
|
|
||
|
|
// Binary suffixes (powers of 1024)
|
||
|
|
binarySuffixes := map[string]uint64{
|
||
|
|
"Ki": 1024,
|
||
|
|
"Mi": 1024 * 1024,
|
||
|
|
"Gi": 1024 * 1024 * 1024,
|
||
|
|
"Ti": 1024 * 1024 * 1024 * 1024,
|
||
|
|
}
|
||
|
|
|
||
|
|
// Decimal suffixes (powers of 1000)
|
||
|
|
decimalSuffixes := map[string]uint64{
|
||
|
|
"K": 1000,
|
||
|
|
"M": 1000 * 1000,
|
||
|
|
"G": 1000 * 1000 * 1000,
|
||
|
|
"T": 1000 * 1000 * 1000 * 1000,
|
||
|
|
}
|
||
|
|
|
||
|
|
// Try binary suffixes first (2-char)
|
||
|
|
for suffix, multiplier := range binarySuffixes {
|
||
|
|
if strings.HasSuffix(value, suffix) {
|
||
|
|
numStr := strings.TrimSuffix(value, suffix)
|
||
|
|
num, err := strconv.ParseFloat(numStr, 64)
|
||
|
|
if err != nil {
|
||
|
|
return 0, fmt.Errorf("parsing memory value: %w", err)
|
||
|
|
}
|
||
|
|
return uint64(num * float64(multiplier)), nil
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Try decimal suffixes (1-char)
|
||
|
|
for suffix, multiplier := range decimalSuffixes {
|
||
|
|
if strings.HasSuffix(value, suffix) {
|
||
|
|
numStr := strings.TrimSuffix(value, suffix)
|
||
|
|
num, err := strconv.ParseFloat(numStr, 64)
|
||
|
|
if err != nil {
|
||
|
|
return 0, fmt.Errorf("parsing memory value: %w", err)
|
||
|
|
}
|
||
|
|
return uint64(num * float64(multiplier)), nil
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Plain number (bytes)
|
||
|
|
bytes, err := strconv.ParseUint(value, 10, 64)
|
||
|
|
if err != nil {
|
||
|
|
return 0, fmt.Errorf("parsing bytes: %w", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
return bytes, nil
|
||
|
|
}
|