// UncoveredDeploymentFlowEdges preserves (and duplicates) edges that were not // covered by a deployment flow. As a special case, it preserves edges between // Services and DeploymentConfigs. func UncoveredDeploymentFlowEdges(covered osgraph.NodeSet) osgraph.EdgeFunc { return func(g osgraph.Interface, head, tail graph.Node, edgeKind string) bool { if edgeKind == kubeedges.ExposedThroughServiceEdgeKind { return osgraph.AddReversedEdge(g, head, tail, osgraph.ReferencedByEdgeKind) } if covered.Has(head.ID()) && covered.Has(tail.ID()) { return false } return osgraph.AddReversedEdge(g, head, tail, osgraph.ReferencedByEdgeKind) } }
// FindOverlappingHPAs scans the graph in search of HorizontalPodAutoscalers that are attempting to scale the same set of pods. // This can occur in two ways: // - 1. label selectors for two ReplicationControllers/DeploymentConfigs/etc overlap // - 2. multiple HorizontalPodAutoscalers are attempting to scale the same ReplicationController/DeploymentConfig/etc // Case 1 is handled by deconflicting the area of influence of ReplicationControllers/DeploymentConfigs/etc, and therefore we // can assume that it will be handled before this step. Therefore, we are only concerned with finding HPAs that are trying to // scale the same resources. // // The algorithm that is used to implement this check is described as follows: // - create a sub-graph containing only HPA nodes and other nodes that can be scaled, as well as any scaling edges or other // edges used to connect between objects that can be scaled // - for every resulting edge in the new sub-graph, create an edge in the reverse direction // - find the shortest paths between all HPA nodes in the graph // - shortest paths connecting two horizontal pod autoscalers are used to create markers for the graph func FindOverlappingHPAs(graph osgraph.Graph, namer osgraph.Namer) []osgraph.Marker { markers := []osgraph.Marker{} nodeFilter := osgraph.NodesOfKind( kubenodes.HorizontalPodAutoscalerNodeKind, kubenodes.ReplicationControllerNodeKind, deploynodes.DeploymentConfigNodeKind, ) edgeFilter := osgraph.EdgesOfKind( kubegraph.ScalingEdgeKind, deploygraph.DeploymentEdgeKind, kubeedges.ManagedByControllerEdgeKind, ) hpaSubGraph := graph.Subgraph(nodeFilter, edgeFilter) for _, edge := range hpaSubGraph.Edges() { osgraph.AddReversedEdge(hpaSubGraph, edge.From(), edge.To(), sets.NewString()) } hpaNodes := hpaSubGraph.NodesByKind(kubenodes.HorizontalPodAutoscalerNodeKind) for _, firstHPA := range hpaNodes { // we can use Dijkstra's algorithm as we know we do not have any negative edge weights shortestPaths := path.DijkstraFrom(firstHPA, hpaSubGraph) for _, secondHPA := range hpaNodes { if firstHPA == secondHPA { continue } shortestPath, _ := shortestPaths.To(secondHPA) if shortestPath == nil { // if two HPAs have no path between them, no error exists continue } markers = append(markers, osgraph.Marker{ Node: firstHPA, Severity: osgraph.WarningSeverity, RelatedNodes: shortestPath[1:], Key: HPAOverlappingScaleRefWarning, Message: fmt.Sprintf("%s and %s overlap because they both attempt to scale %s", namer.ResourceName(firstHPA), namer.ResourceName(secondHPA), nameList(shortestPath[1:len(shortestPath)-1], namer)), }) } } return markers }