Files
elmprodvpn/selective-vpn-api/app/transport_backends_adapter_systemd_health.go

84 lines
2.0 KiB
Go

package app
import (
"strings"
)
func (transportSystemdBackend) Health(client TransportClient) transportBackendHealthResult {
units, errCode, errMsg := transportSystemdHealthUnits(client)
if len(units) == 0 {
return transportBackendHealthResult{
OK: false,
Code: errCode,
Message: errMsg,
Status: TransportClientDown,
}
}
active := 0
starting := 0
inactive := 0
failed := 0
unknown := 0
issues := make([]string, 0, len(units))
for _, unit := range units {
stdout, stderr, _, _ := transportRunCommand(transportBackendHealthTimeout, "systemctl", "is-active", unit)
state := strings.ToLower(strings.TrimSpace(stdout))
switch state {
case "active":
active++
case "activating", "reloading":
starting++
case "inactive", "deactivating":
inactive++
case "failed":
failed++
msg := strings.TrimSpace(stderr)
if msg == "" {
msg = "systemd unit failed"
}
issues = append(issues, unit+": "+msg)
default:
unknown++
msg := strings.TrimSpace(stderr)
if msg == "" {
msg = strings.TrimSpace(stdout)
}
if msg == "" {
msg = "status unknown"
}
issues = append(issues, unit+": "+msg)
}
}
total := len(units)
if active == total {
res := transportBackendHealthResult{OK: true, Status: TransportClientUp}
if latency, _ := transportProbeClientLatency(client); latency > 0 {
res.LatencyMS = latency
}
return res
}
if active+starting == total {
return transportBackendHealthResult{OK: true, Status: TransportClientStarting}
}
if inactive == total {
return transportBackendHealthResult{OK: true, Status: TransportClientDown}
}
msg := strings.TrimSpace(strings.Join(issues, "; "))
if msg == "" {
msg = "backend units are not synchronized"
}
status := TransportClientDegraded
if active == 0 && failed == 0 && unknown == 0 {
status = TransportClientDown
}
return transportBackendHealthResult{
OK: false,
Code: "TRANSPORT_BACKEND_HEALTH_FAILED",
Message: msg,
Status: status,
Retryable: true,
}
}