forgejo-runner-optimiser/internal/cgroup/config.go

85 lines
2.3 KiB
Go
Raw Normal View History

// ABOUTME: Configuration types and parsing for cgroup limits and process mapping.
// ABOUTME: Parses CGROUP_LIMITS and CGROUP_PROCESS_MAP environment variables.
package cgroup
import (
"encoding/json"
"fmt"
"os"
)
// CgroupLimit holds the resource limits for a container/cgroup
type CgroupLimit struct {
CPUCores float64 // CPU limit in cores (e.g., 0.5 for "500m", 2.0 for "2")
MemoryBytes uint64 // Memory limit in bytes
}
// CgroupLimits maps container names to their resource limits
type CgroupLimits map[string]CgroupLimit
// ProcessMapping maps process names to container names (for cgroup path discovery)
type ProcessMapping map[string]string
// CgroupPathMapping maps cgroup paths to container names (built at runtime)
type CgroupPathMapping map[string]string
// rawLimitEntry is the JSON structure for each entry in CGROUP_LIMITS
type rawLimitEntry struct {
CPU string `json:"cpu"`
Memory string `json:"memory"`
}
// ParseCgroupLimitsEnv parses the CGROUP_LIMITS environment variable.
// Expected format: {"container-name": {"cpu": "500m", "memory": "1Gi"}, ...}
func ParseCgroupLimitsEnv() (CgroupLimits, error) {
raw := os.Getenv("CGROUP_LIMITS")
if raw == "" {
return nil, nil // No limits configured
}
var parsed map[string]rawLimitEntry
if err := json.Unmarshal([]byte(raw), &parsed); err != nil {
return nil, fmt.Errorf("parsing CGROUP_LIMITS: %w", err)
}
limits := make(CgroupLimits)
for name, entry := range parsed {
var limit CgroupLimit
var err error
if entry.CPU != "" {
limit.CPUCores, err = ParseCPU(entry.CPU)
if err != nil {
return nil, fmt.Errorf("parsing CPU for %q: %w", name, err)
}
}
if entry.Memory != "" {
limit.MemoryBytes, err = ParseMemory(entry.Memory)
if err != nil {
return nil, fmt.Errorf("parsing memory for %q: %w", name, err)
}
}
limits[name] = limit
}
return limits, nil
}
// ParseProcessMappingEnv parses the CGROUP_PROCESS_MAP environment variable.
// Expected format: {"process-name": "container-name", ...}
func ParseProcessMappingEnv() (ProcessMapping, error) {
raw := os.Getenv("CGROUP_PROCESS_MAP")
if raw == "" {
return nil, nil // No mapping configured
}
var parsed map[string]string
if err := json.Unmarshal([]byte(raw), &parsed); err != nil {
return nil, fmt.Errorf("parsing CGROUP_PROCESS_MAP: %w", err)
}
return ProcessMapping(parsed), nil
}