mirror of
https://github.com/outbackdingo/cozystack.git
synced 2026-01-27 10:18:39 +00:00
This patch implements external monitoring of the Kube-OVN cluster. A new reconciler timed to run its reconcile loop at a fixed interval execs into the ovn-central pods and collects their cluster info. If the members' opinions about the cluster disagree, an alert is raised. Other issues with the distributed consensus are also highlighted. ```release-note [kubeovn,cozystack-controller] Implement the KubeOVN plunger, an external monitoring agent for the ovn-central cluster. ``` Signed-off-by: Timofei Larkin <lllamnyp@gmail.com>
116 lines
3.0 KiB
Go
116 lines
3.0 KiB
Go
package ovnstatus
|
|
|
|
import "strings"
|
|
|
|
// ----- SID normalization (handles legacy "b007" style SIDs) -----
|
|
|
|
// NormalizeViews expands truncated SIDs in each MemberView's Members map,
|
|
// using IP->fullSID learned from reporters and unique-prefix fallback.
|
|
type sidCanon struct{ raw, canon string }
|
|
|
|
func NormalizeViews(views []MemberView) []MemberView {
|
|
// 1) Learn IP -> fullSID from reporters (self entries)
|
|
ipToFull := map[string]string{}
|
|
fullSIDs := map[string]struct{}{}
|
|
|
|
for _, v := range views {
|
|
if v.FromSID != "" {
|
|
fullSIDs[v.FromSID] = struct{}{}
|
|
}
|
|
if v.FromAddress != "" {
|
|
ip := AddrToIP(v.FromAddress)
|
|
if ip != "" && v.FromSID != "" {
|
|
ipToFull[ip] = v.FromSID
|
|
}
|
|
}
|
|
}
|
|
|
|
// Build a slice for prefix-matching fallback (hyphenless, lowercase)
|
|
var known []sidCanon
|
|
for fsid := range fullSIDs {
|
|
known = append(known, sidCanon{
|
|
raw: fsid,
|
|
canon: canonizeSID(fsid),
|
|
})
|
|
}
|
|
|
|
// 2) Normalize each view's Members by replacing short SIDs with full SIDs
|
|
out := make([]MemberView, 0, len(views))
|
|
for _, v := range views {
|
|
mv := MemberView{
|
|
FromSID: normalizeOneSID(v.FromSID, v.FromAddress, ipToFull, known),
|
|
FromAddress: v.FromAddress,
|
|
Members: make(map[string]string, len(v.Members)),
|
|
}
|
|
for sid, addr := range v.Members {
|
|
full := normalizeOneSIDWithAddr(sid, addr, ipToFull, known)
|
|
// If remapping causes a collision, prefer keeping the address
|
|
// from the entry that matches the full SID (no-op), otherwise last write wins.
|
|
mv.Members[full] = addr
|
|
}
|
|
out = append(out, mv)
|
|
}
|
|
return out
|
|
}
|
|
|
|
func normalizeOneSIDWithAddr(sid, addr string, ipToFull map[string]string, known []sidCanon) string {
|
|
// If it's already full-ish, return as-is
|
|
if looksFullSID(sid) {
|
|
return sid
|
|
}
|
|
// First try IP mapping
|
|
if ip := AddrToIP(addr); ip != "" {
|
|
if fsid, ok := ipToFull[ip]; ok {
|
|
return fsid
|
|
}
|
|
}
|
|
// Fallback: unique prefix match against known full SIDs (hyphens ignored)
|
|
return expandByUniquePrefix(sid, known)
|
|
}
|
|
|
|
func normalizeOneSID(sid, selfAddr string, ipToFull map[string]string, known []sidCanon) string {
|
|
if looksFullSID(sid) {
|
|
return sid
|
|
}
|
|
if ip := AddrToIP(selfAddr); ip != "" {
|
|
if fsid, ok := ipToFull[ip]; ok {
|
|
return fsid
|
|
}
|
|
}
|
|
return expandByUniquePrefix(sid, known)
|
|
}
|
|
|
|
func looksFullSID(s string) bool {
|
|
// Heuristic: a v4 UUID with hyphens is 36 chars.
|
|
// Some builds may print full without hyphens (32). Treat >= 32 hex-ish as "full".
|
|
cs := canonizeSID(s)
|
|
return len(cs) >= 32
|
|
}
|
|
|
|
func canonizeSID(s string) string {
|
|
// lower + drop hyphens for prefix comparisons
|
|
s = strings.ToLower(s)
|
|
return strings.ReplaceAll(s, "-", "")
|
|
}
|
|
|
|
func expandByUniquePrefix(short string, known []sidCanon) string {
|
|
p := canonizeSID(short)
|
|
if p == "" {
|
|
return short
|
|
}
|
|
matches := make([]string, 0, 2)
|
|
for _, k := range known {
|
|
if strings.HasPrefix(k.canon, p) {
|
|
matches = append(matches, k.raw)
|
|
if len(matches) > 1 {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
if len(matches) == 1 {
|
|
return matches[0]
|
|
}
|
|
// ambiguous or none → leave as-is (will still be visible in diagnostics)
|
|
return short
|
|
}
|