mirror of
https://github.com/juanfont/headscale.git
synced 2025-09-06 17:54:31 +02:00
cmd/hi: lint and format
Signed-off-by: Kristoffer Dalby <kristoffer@tailscale.com>
This commit is contained in:
parent
dc28698551
commit
f6c1348835
@ -141,6 +141,7 @@ func runTestContainer(ctx context.Context, config *RunConfig) error {
|
|||||||
log.Printf("Container %s exceeded memory limit: %.1f MB > %.1f MB",
|
log.Printf("Container %s exceeded memory limit: %.1f MB > %.1f MB",
|
||||||
violation.ContainerName, violation.MaxMemoryMB, violation.LimitMB)
|
violation.ContainerName, violation.MaxMemoryMB, violation.LimitMB)
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Errorf("test failed: %d container(s) exceeded memory limits", len(violations))
|
return fmt.Errorf("test failed: %d container(s) exceeded memory limits", len(violations))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"sort"
|
"sort"
|
||||||
@ -17,7 +18,7 @@ import (
|
|||||||
"github.com/docker/docker/client"
|
"github.com/docker/docker/client"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ContainerStats represents statistics for a single container
|
// ContainerStats represents statistics for a single container.
|
||||||
type ContainerStats struct {
|
type ContainerStats struct {
|
||||||
ContainerID string
|
ContainerID string
|
||||||
ContainerName string
|
ContainerName string
|
||||||
@ -25,14 +26,14 @@ type ContainerStats struct {
|
|||||||
mutex sync.RWMutex
|
mutex sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// StatsSample represents a single stats measurement
|
// StatsSample represents a single stats measurement.
|
||||||
type StatsSample struct {
|
type StatsSample struct {
|
||||||
Timestamp time.Time
|
Timestamp time.Time
|
||||||
CPUUsage float64 // CPU usage percentage
|
CPUUsage float64 // CPU usage percentage
|
||||||
MemoryMB float64 // Memory usage in MB
|
MemoryMB float64 // Memory usage in MB
|
||||||
}
|
}
|
||||||
|
|
||||||
// StatsCollector manages collection of container statistics
|
// StatsCollector manages collection of container statistics.
|
||||||
type StatsCollector struct {
|
type StatsCollector struct {
|
||||||
client *client.Client
|
client *client.Client
|
||||||
containers map[string]*ContainerStats
|
containers map[string]*ContainerStats
|
||||||
@ -42,7 +43,7 @@ type StatsCollector struct {
|
|||||||
collectionStarted bool
|
collectionStarted bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewStatsCollector creates a new stats collector instance
|
// NewStatsCollector creates a new stats collector instance.
|
||||||
func NewStatsCollector() (*StatsCollector, error) {
|
func NewStatsCollector() (*StatsCollector, error) {
|
||||||
cli, err := createDockerClient()
|
cli, err := createDockerClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -56,13 +57,13 @@ func NewStatsCollector() (*StatsCollector, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// StartCollection begins monitoring all containers and collecting stats for hs- and ts- containers with matching run ID
|
// StartCollection begins monitoring all containers and collecting stats for hs- and ts- containers with matching run ID.
|
||||||
func (sc *StatsCollector) StartCollection(ctx context.Context, runID string, verbose bool) error {
|
func (sc *StatsCollector) StartCollection(ctx context.Context, runID string, verbose bool) error {
|
||||||
sc.mutex.Lock()
|
sc.mutex.Lock()
|
||||||
defer sc.mutex.Unlock()
|
defer sc.mutex.Unlock()
|
||||||
|
|
||||||
if sc.collectionStarted {
|
if sc.collectionStarted {
|
||||||
return fmt.Errorf("stats collection already started")
|
return errors.New("stats collection already started")
|
||||||
}
|
}
|
||||||
|
|
||||||
sc.collectionStarted = true
|
sc.collectionStarted = true
|
||||||
@ -82,7 +83,7 @@ func (sc *StatsCollector) StartCollection(ctx context.Context, runID string, ver
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// StopCollection stops all stats collection
|
// StopCollection stops all stats collection.
|
||||||
func (sc *StatsCollector) StopCollection() {
|
func (sc *StatsCollector) StopCollection() {
|
||||||
// Check if already stopped without holding lock
|
// Check if already stopped without holding lock
|
||||||
sc.mutex.RLock()
|
sc.mutex.RLock()
|
||||||
@ -104,7 +105,7 @@ func (sc *StatsCollector) StopCollection() {
|
|||||||
sc.mutex.Unlock()
|
sc.mutex.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// monitorExistingContainers checks for existing containers that match our criteria
|
// monitorExistingContainers checks for existing containers that match our criteria.
|
||||||
func (sc *StatsCollector) monitorExistingContainers(ctx context.Context, runID string, verbose bool) {
|
func (sc *StatsCollector) monitorExistingContainers(ctx context.Context, runID string, verbose bool) {
|
||||||
defer sc.wg.Done()
|
defer sc.wg.Done()
|
||||||
|
|
||||||
@ -123,7 +124,7 @@ func (sc *StatsCollector) monitorExistingContainers(ctx context.Context, runID s
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// monitorDockerEvents listens for container start events and begins monitoring relevant containers
|
// monitorDockerEvents listens for container start events and begins monitoring relevant containers.
|
||||||
func (sc *StatsCollector) monitorDockerEvents(ctx context.Context, runID string, verbose bool) {
|
func (sc *StatsCollector) monitorDockerEvents(ctx context.Context, runID string, verbose bool) {
|
||||||
defer sc.wg.Done()
|
defer sc.wg.Done()
|
||||||
|
|
||||||
@ -171,7 +172,7 @@ func (sc *StatsCollector) monitorDockerEvents(ctx context.Context, runID string,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// shouldMonitorContainer determines if a container should be monitored
|
// shouldMonitorContainer determines if a container should be monitored.
|
||||||
func (sc *StatsCollector) shouldMonitorContainer(cont types.Container, runID string) bool {
|
func (sc *StatsCollector) shouldMonitorContainer(cont types.Container, runID string) bool {
|
||||||
// Check if it has the correct run ID label
|
// Check if it has the correct run ID label
|
||||||
if cont.Labels == nil || cont.Labels["hi.run-id"] != runID {
|
if cont.Labels == nil || cont.Labels["hi.run-id"] != runID {
|
||||||
@ -189,7 +190,7 @@ func (sc *StatsCollector) shouldMonitorContainer(cont types.Container, runID str
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// startStatsForContainer begins stats collection for a specific container
|
// startStatsForContainer begins stats collection for a specific container.
|
||||||
func (sc *StatsCollector) startStatsForContainer(ctx context.Context, containerID, containerName string, verbose bool) {
|
func (sc *StatsCollector) startStatsForContainer(ctx context.Context, containerID, containerName string, verbose bool) {
|
||||||
containerName = strings.TrimPrefix(containerName, "/")
|
containerName = strings.TrimPrefix(containerName, "/")
|
||||||
|
|
||||||
@ -215,7 +216,7 @@ func (sc *StatsCollector) startStatsForContainer(ctx context.Context, containerI
|
|||||||
go sc.collectStatsForContainer(ctx, containerID, verbose)
|
go sc.collectStatsForContainer(ctx, containerID, verbose)
|
||||||
}
|
}
|
||||||
|
|
||||||
// collectStatsForContainer collects stats for a specific container using Docker API streaming
|
// collectStatsForContainer collects stats for a specific container using Docker API streaming.
|
||||||
func (sc *StatsCollector) collectStatsForContainer(ctx context.Context, containerID string, verbose bool) {
|
func (sc *StatsCollector) collectStatsForContainer(ctx context.Context, containerID string, verbose bool) {
|
||||||
defer sc.wg.Done()
|
defer sc.wg.Done()
|
||||||
|
|
||||||
@ -284,7 +285,7 @@ func (sc *StatsCollector) collectStatsForContainer(ctx context.Context, containe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculateCPUPercent calculates CPU usage percentage from Docker stats
|
// calculateCPUPercent calculates CPU usage percentage from Docker stats.
|
||||||
func calculateCPUPercent(prevStats, stats *container.Stats) float64 {
|
func calculateCPUPercent(prevStats, stats *container.Stats) float64 {
|
||||||
// CPU calculation based on Docker's implementation
|
// CPU calculation based on Docker's implementation
|
||||||
cpuDelta := float64(stats.CPUStats.CPUUsage.TotalUsage) - float64(prevStats.CPUStats.CPUUsage.TotalUsage)
|
cpuDelta := float64(stats.CPUStats.CPUUsage.TotalUsage) - float64(prevStats.CPUStats.CPUUsage.TotalUsage)
|
||||||
@ -297,12 +298,14 @@ func calculateCPUPercent(prevStats, stats *container.Stats) float64 {
|
|||||||
// Fallback: if PercpuUsage is not available, assume 1 CPU
|
// Fallback: if PercpuUsage is not available, assume 1 CPU
|
||||||
numCPUs = 1.0
|
numCPUs = 1.0
|
||||||
}
|
}
|
||||||
|
|
||||||
return (cpuDelta / systemDelta) * numCPUs * 100.0
|
return (cpuDelta / systemDelta) * numCPUs * 100.0
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0.0
|
return 0.0
|
||||||
}
|
}
|
||||||
|
|
||||||
// ContainerStatsSummary represents summary statistics for a container
|
// ContainerStatsSummary represents summary statistics for a container.
|
||||||
type ContainerStatsSummary struct {
|
type ContainerStatsSummary struct {
|
||||||
ContainerName string
|
ContainerName string
|
||||||
SampleCount int
|
SampleCount int
|
||||||
@ -310,21 +313,21 @@ type ContainerStatsSummary struct {
|
|||||||
Memory StatsSummary
|
Memory StatsSummary
|
||||||
}
|
}
|
||||||
|
|
||||||
// MemoryViolation represents a container that exceeded the memory limit
|
// MemoryViolation represents a container that exceeded the memory limit.
|
||||||
type MemoryViolation struct {
|
type MemoryViolation struct {
|
||||||
ContainerName string
|
ContainerName string
|
||||||
MaxMemoryMB float64
|
MaxMemoryMB float64
|
||||||
LimitMB float64
|
LimitMB float64
|
||||||
}
|
}
|
||||||
|
|
||||||
// StatsSummary represents min, max, and average for a metric
|
// StatsSummary represents min, max, and average for a metric.
|
||||||
type StatsSummary struct {
|
type StatsSummary struct {
|
||||||
Min float64
|
Min float64
|
||||||
Max float64
|
Max float64
|
||||||
Average float64
|
Average float64
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSummary returns a summary of collected statistics
|
// GetSummary returns a summary of collected statistics.
|
||||||
func (sc *StatsCollector) GetSummary() []ContainerStatsSummary {
|
func (sc *StatsCollector) GetSummary() []ContainerStatsSummary {
|
||||||
// Take snapshot of container references without holding main lock long
|
// Take snapshot of container references without holding main lock long
|
||||||
sc.mutex.RLock()
|
sc.mutex.RLock()
|
||||||
@ -375,7 +378,7 @@ func (sc *StatsCollector) GetSummary() []ContainerStatsSummary {
|
|||||||
return summaries
|
return summaries
|
||||||
}
|
}
|
||||||
|
|
||||||
// calculateStatsSummary calculates min, max, and average for a slice of values
|
// calculateStatsSummary calculates min, max, and average for a slice of values.
|
||||||
func calculateStatsSummary(values []float64) StatsSummary {
|
func calculateStatsSummary(values []float64) StatsSummary {
|
||||||
if len(values) == 0 {
|
if len(values) == 0 {
|
||||||
return StatsSummary{}
|
return StatsSummary{}
|
||||||
@ -402,7 +405,7 @@ func calculateStatsSummary(values []float64) StatsSummary {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrintSummary prints the statistics summary to the console
|
// PrintSummary prints the statistics summary to the console.
|
||||||
func (sc *StatsCollector) PrintSummary() {
|
func (sc *StatsCollector) PrintSummary() {
|
||||||
summaries := sc.GetSummary()
|
summaries := sc.GetSummary()
|
||||||
|
|
||||||
@ -424,7 +427,7 @@ func (sc *StatsCollector) PrintSummary() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckMemoryLimits checks if any containers exceeded their memory limits
|
// CheckMemoryLimits checks if any containers exceeded their memory limits.
|
||||||
func (sc *StatsCollector) CheckMemoryLimits(hsLimitMB, tsLimitMB float64) []MemoryViolation {
|
func (sc *StatsCollector) CheckMemoryLimits(hsLimitMB, tsLimitMB float64) []MemoryViolation {
|
||||||
if hsLimitMB <= 0 && tsLimitMB <= 0 {
|
if hsLimitMB <= 0 && tsLimitMB <= 0 {
|
||||||
return nil
|
return nil
|
||||||
@ -455,13 +458,13 @@ func (sc *StatsCollector) CheckMemoryLimits(hsLimitMB, tsLimitMB float64) []Memo
|
|||||||
return violations
|
return violations
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrintSummaryAndCheckLimits prints the statistics summary and returns memory violations if any
|
// PrintSummaryAndCheckLimits prints the statistics summary and returns memory violations if any.
|
||||||
func (sc *StatsCollector) PrintSummaryAndCheckLimits(hsLimitMB, tsLimitMB float64) []MemoryViolation {
|
func (sc *StatsCollector) PrintSummaryAndCheckLimits(hsLimitMB, tsLimitMB float64) []MemoryViolation {
|
||||||
sc.PrintSummary()
|
sc.PrintSummary()
|
||||||
return sc.CheckMemoryLimits(hsLimitMB, tsLimitMB)
|
return sc.CheckMemoryLimits(hsLimitMB, tsLimitMB)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close closes the stats collector and cleans up resources
|
// Close closes the stats collector and cleans up resources.
|
||||||
func (sc *StatsCollector) Close() error {
|
func (sc *StatsCollector) Close() error {
|
||||||
sc.StopCollection()
|
sc.StopCollection()
|
||||||
return sc.client.Close()
|
return sc.client.Close()
|
||||||
|
Loading…
Reference in New Issue
Block a user