chore: publish pxmon v0.2.0
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
package cluster
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type DriftIssue struct {
|
||||
Level string `json:"level"`
|
||||
Kind string `json:"kind"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
type DriftReport struct {
|
||||
Cluster string `json:"cluster"`
|
||||
Generated time.Time `json:"generated_at"`
|
||||
Issues []DriftIssue `json:"issues,omitempty"`
|
||||
}
|
||||
|
||||
func (s *Service) DetectDrift(ctx context.Context, selector string) (DriftReport, error) {
|
||||
c, err := s.Get(selector)
|
||||
if err != nil {
|
||||
return DriftReport{}, err
|
||||
}
|
||||
rep := DriftReport{Cluster: c.Name, Generated: s.now().UTC()}
|
||||
expected := strings.TrimSpace(s.ExpectedAgentVersion())
|
||||
dctrl := normalizeDriftControl(c.Drift)
|
||||
|
||||
if !c.Agent.Installed {
|
||||
rep.Issues = append(rep.Issues, DriftIssue{Level: "warn", Kind: "agent", Message: "agent is not installed"})
|
||||
return rep, nil
|
||||
}
|
||||
|
||||
pingCtx, cancel := context.WithTimeout(ctx, 2500*time.Millisecond)
|
||||
ping, pingErr := s.PingAgent(pingCtx, c.ID)
|
||||
cancel()
|
||||
if pingErr != nil || !ping.Reachable || ping.StatusCode >= 400 {
|
||||
rep.Issues = append(rep.Issues, DriftIssue{Level: "crit", Kind: "agent", Message: "agent is unreachable"})
|
||||
} else {
|
||||
nodeVersion := strings.TrimSpace(ping.Version)
|
||||
if nodeVersion == "" {
|
||||
nodeVersion = strings.TrimSpace(c.Agent.Version)
|
||||
}
|
||||
if expected != "" && nodeVersion != "" && nodeVersion != expected {
|
||||
rep.Issues = append(rep.Issues, DriftIssue{Level: "warn", Kind: "agent_version", Message: fmt.Sprintf("agent version mismatch: node=%s local=%s", nodeVersion, expected)})
|
||||
}
|
||||
if nodeVersion != "" {
|
||||
if ok, latest, known := s.CompareAgentVersion(nodeVersion); known && !ok {
|
||||
rep.Issues = append(rep.Issues, DriftIssue{Level: "warn", Kind: "agent_outdated", Message: fmt.Sprintf("node version %s is older than latest known %s", nodeVersion, latest)})
|
||||
}
|
||||
if dctrl.Baseline.Enabled && strings.TrimSpace(dctrl.Baseline.AgentVersion) != "" && !strings.EqualFold(strings.TrimSpace(dctrl.Baseline.AgentVersion), nodeVersion) {
|
||||
rep.Issues = append(rep.Issues, DriftIssue{
|
||||
Level: "warn",
|
||||
Kind: "baseline_agent_version",
|
||||
Message: fmt.Sprintf("baseline agent version mismatch: baseline=%s live=%s", dctrl.Baseline.AgentVersion, nodeVersion),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
softCtx, softCancel := context.WithTimeout(ctx, 7*time.Second)
|
||||
fresh, softErr := s.probeSoftware(softCtx, c, "", "")
|
||||
softCancel()
|
||||
if softErr != nil {
|
||||
rep.Issues = append(rep.Issues, DriftIssue{Level: "warn", Kind: "software_probe", Message: softErr.Error()})
|
||||
} else {
|
||||
oldSet := strings.TrimSpace(c.Software.Summary())
|
||||
newSet := strings.TrimSpace(fresh.Summary())
|
||||
if oldSet != "" && oldSet != "-" && newSet != oldSet {
|
||||
rep.Issues = append(rep.Issues, DriftIssue{Level: "warn", Kind: "software", Message: fmt.Sprintf("software support changed: stored=%s live=%s", oldSet, newSet)})
|
||||
}
|
||||
if dctrl.Baseline.Enabled && strings.TrimSpace(dctrl.Baseline.Software) != "" && !strings.EqualFold(strings.TrimSpace(dctrl.Baseline.Software), newSet) {
|
||||
rep.Issues = append(rep.Issues, DriftIssue{
|
||||
Level: "warn",
|
||||
Kind: "baseline_software",
|
||||
Message: fmt.Sprintf("baseline software mismatch: baseline=%s live=%s", dctrl.Baseline.Software, newSet),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
sort.Slice(rep.Issues, func(i, j int) bool { return rep.Issues[i].Kind < rep.Issues[j].Kind })
|
||||
return rep, nil
|
||||
}
|
||||
Reference in New Issue
Block a user