pkg/health/controller.go
Rama main · réplica de lectura del repositorio original.
package health
import (
"fmt"
corev1 "k8s.io/api/core/v1"
)
// ControllerPodHealth summarizes readiness and failure signals from controller pods.
type ControllerPodHealth struct {
Ready int
Total int
Crashing int
Pending int
CrashReason string
}
// SummarizeControllerPods counts the supplied pods without filtering their lifecycle.
// Callers that require only active pods must filter before calling.
func SummarizeControllerPods(pods []*corev1.Pod) ControllerPodHealth {
out := ControllerPodHealth{Total: len(pods)}
for _, p := range pods {
for _, cs := range p.Status.ContainerStatuses {
if cs.State.Waiting != nil && (cs.State.Waiting.Reason == "CrashLoopBackOff" || cs.State.Waiting.Reason == "Error") {
out.Crashing++
if out.CrashReason == "" {
out.CrashReason = cs.State.Waiting.Reason
}
break
}
}
ready := p.Status.Phase == corev1.PodRunning
for _, cs := range p.Status.ContainerStatuses {
if !cs.Ready {
ready = false
}
}
if ready {
out.Ready++
}
if p.Status.Phase == corev1.PodPending {
out.Pending++
}
}
if out.Ready > out.Total {
out.Ready = out.Total
}
return out
}
// SummarizeControllerHealth distills a slice of controller pods into a
// short, operator-readable status verb. Aggregates over multiple
// replicas (Argo's controller is typically deployed as a 2-replica
// StatefulSet for HA): if any pod is in CrashLoopBackOff or Error, that
// fact dominates the status. If all pods are Ready, "healthy". Anything
// in between is "degraded" with a count.
func SummarizeControllerHealth(controller string, pods []*corev1.Pod) string {
return controller + " is " + DescribeControllerHealth(pods)
}
// DescribeControllerHealth returns the status phrase SummarizeControllerHealth
// puts after "<controller> is", such as "CrashLoopBackOff (1/1 pods)".
func DescribeControllerHealth(pods []*corev1.Pod) string {
health := SummarizeControllerPods(pods)
switch {
case health.Crashing > 0:
return fmt.Sprintf("%s (%d/%d pods)", health.CrashReason, health.Crashing, health.Total)
case health.Ready == health.Total && health.Total > 0:
// All pods Ready — if the resource is *still* stuck deleting
// despite a healthy controller, it's a different problem (RBAC,
// network, broken finalizer logic). Surface the healthy state
// so the operator knows to dig into the controller's logs
// rather than its lifecycle.
suffix := "s"
if health.Ready == 1 {
suffix = ""
}
return fmt.Sprintf("healthy (%d pod%s ready)", health.Ready, suffix)
case health.Pending > 0:
return fmt.Sprintf("pending start (%d/%d pods Pending)", health.Pending, health.Total)
default:
return fmt.Sprintf("degraded (%d/%d pods ready)", health.Ready, health.Total)
}
}