package graph import ( "github.com/gonum/graph" ) // Marker is a struct that describes something interesting on a Node type Marker struct { // Node is the optional node that this message is attached to Node graph.Node // RelatedNodes is an optional list of other nodes that are involved in this marker. RelatedNodes []graph.Node // Severity indicates how important this problem is. Severity Severity // Key is a short string to identify this message Key string // Message is a human-readable string that describes what is interesting Message string // Suggestion is a human-readable string that holds advice for resolving this // marker. Suggestion Suggestion } // Severity indicates how important this problem is. type Severity string const ( // InfoSeverity is interesting // Currently used in missing probe markers InfoSeverity Severity = "info" // WarningSeverity is probably wrong, but we aren't certain WarningSeverity Severity = "warning" // ErrorSeverity is definitely wrong, this won't work ErrorSeverity Severity = "error" ) type Markers []Marker // MarkerScanner is a function for analyzing a graph and finding interesting things in it type MarkerScanner func(g Graph, f Namer) []Marker func (m Markers) BySeverity(severity Severity) []Marker { ret := []Marker{} for i := range m { if m[i].Severity == severity { ret = append(ret, m[i]) } } return ret } // FilterByNamespace returns all the markers that are not associated with missing nodes // from other namespaces (other than the provided namespace). func (m Markers) FilterByNamespace(namespace string) Markers { filtered := Markers{} for i := range m { markerNodes := []graph.Node{} markerNodes = append(markerNodes, m[i].Node) markerNodes = append(markerNodes, m[i].RelatedNodes...) hasCrossNamespaceLink := false for _, node := range markerNodes { if IsFromDifferentNamespace(namespace, node) { hasCrossNamespaceLink = true break } } if !hasCrossNamespaceLink { filtered = append(filtered, m[i]) } } return filtered } type BySeverity []Marker func (m BySeverity) Len() int { return len(m) } func (m BySeverity) Swap(i, j int) { m[i], m[j] = m[j], m[i] } func (m BySeverity) Less(i, j int) bool { lhs := m[i] rhs := m[j] switch lhs.Severity { case ErrorSeverity: switch rhs.Severity { case ErrorSeverity: return false } case WarningSeverity: switch rhs.Severity { case ErrorSeverity, WarningSeverity: return false } case InfoSeverity: switch rhs.Severity { case ErrorSeverity, WarningSeverity, InfoSeverity: return false } } return true } type ByNodeID []Marker func (m ByNodeID) Len() int { return len(m) } func (m ByNodeID) Swap(i, j int) { m[i], m[j] = m[j], m[i] } func (m ByNodeID) Less(i, j int) bool { if m[i].Node == nil { return true } if m[j].Node == nil { return false } return m[i].Node.ID() < m[j].Node.ID() } type ByKey []Marker func (m ByKey) Len() int { return len(m) } func (m ByKey) Swap(i, j int) { m[i], m[j] = m[j], m[i] } func (m ByKey) Less(i, j int) bool { return m[i].Key < m[j].Key } type Suggestion string func (s Suggestion) String() string { return string(s) }