// ServiceAndDeploymentGroups breaks the provided graph of API relationships into ServiceGroup objects, // ordered consistently. Groups are organized so that overlapping Services and DeploymentConfigs are // part of the same group, Deployment Configs are each in their own group, and then BuildConfigs are // part of the last service group. func ServiceAndDeploymentGroups(g osgraph.Graph) []ServiceGroup { deploys, covered := DeploymentPipelines(g) other := g.Subgraph(UncoveredDeploymentFlowNodes(covered), UncoveredDeploymentFlowEdges(covered)) components := search.Tarjan(other) serviceGroups := []ServiceGroup{} for _, c := range components { group := ServiceGroup{} matches := osgraph.NodesByKind(other, c, kubegraph.ServiceNodeKind, deploygraph.DeploymentConfigNodeKind) svcs, dcs, _ := matches[0], matches[1], matches[2] for _, n := range svcs { coveredDCs := []*deploygraph.DeploymentConfigNode{} coveredRCs := []*kubegraph.ReplicationControllerNode{} coveredPods := []*kubegraph.PodNode{} for _, neighbor := range other.Neighbors(n) { switch other.EdgeKind(g.EdgeBetween(neighbor, n)) { case kubeedges.ExposedThroughServiceEdgeKind: containerNode := osgraph.GetTopLevelContainerNode(g, neighbor) switch castCoveredNode := containerNode.(type) { case *deploygraph.DeploymentConfigNode: coveredDCs = append(coveredDCs, castCoveredNode) case *kubegraph.ReplicationControllerNode: coveredRCs = append(coveredRCs, castCoveredNode) case *kubegraph.PodNode: coveredPods = append(coveredPods, castCoveredNode) } } } group.Services = append(group.Services, ServiceReference{ Service: n.(*kubegraph.ServiceNode), CoveredDCs: coveredDCs, CoveredRCs: coveredRCs, CoveredPods: coveredPods, }) } sort.Sort(SortedServiceReferences(group.Services)) for _, n := range dcs { d := n.(*deploygraph.DeploymentConfigNode) group.Deployments = append(group.Deployments, DeploymentFlow{ Deployment: d, Images: deploys[d], }) } sort.Sort(SortedDeploymentPipelines(group.Deployments)) if len(dcs) == 0 || len(svcs) == 0 { unknown := g.SubgraphWithNodes(c, osgraph.ExistingDirectEdge) for _, n := range unknown.NodeList() { g.PredecessorEdges(n, osgraph.AddGraphEdgesTo(unknown), buildedges.BuildOutputEdgeKind) } unknown = unknown.EdgeSubgraph(osgraph.ReverseGraphEdge) for _, n := range unknown.RootNodes() { if flow, ok := ImagePipelineFromNode(unknown, n, make(osgraph.NodeSet)); ok { group.Builds = append(group.Builds, flow) } } } sort.Sort(SortedImagePipelines(group.Builds)) serviceGroups = append(serviceGroups, group) } sort.Sort(SortedServiceGroups(serviceGroups)) return serviceGroups }