Beispiel #1
0
func TestTarjan(t *testing.T) {
	for i, test := range tarjanTests {
		g := concrete.NewDirectedGraph()
		for u, e := range test.g {
			g.AddNode(concrete.Node(u))
			for v := range e {
				if !g.NodeExists(concrete.Node(v)) {
					g.AddNode(concrete.Node(v))
				}
				g.AddDirectedEdge(concrete.Edge{H: concrete.Node(u), T: concrete.Node(v)}, 0)
			}
		}
		gotSCCs := search.Tarjan(g)
		// tarjan.strongconnect does range iteration over maps,
		// so sort SCC members to ensure consistent ordering.
		gotIDs := make([][]int, len(gotSCCs))
		for i, scc := range gotSCCs {
			gotIDs[i] = make([]int, len(scc))
			for j, id := range scc {
				gotIDs[i][j] = id.ID()
			}
			sort.Ints(gotIDs[i])
		}
		for _, iv := range test.ambiguousOrder {
			sort.Sort(byComponentLengthOrStart(test.want[iv.start:iv.end]))
			sort.Sort(byComponentLengthOrStart(gotIDs[iv.start:iv.end]))
		}
		if !reflect.DeepEqual(gotIDs, test.want) {
			t.Errorf("unexpected Tarjan scc result for %d:\n\tgot:%v\n\twant:%v", i, gotIDs, test.want)
		}
	}
}
// 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 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 := NodesByKind(other, c, ServiceGraphKind, DeploymentConfigGraphKind)
		svcs, dcs, _ := matches[0], matches[1], matches[2]

		for _, n := range svcs {
			covers := []*DeploymentConfigNode{}
			for _, neighbor := range other.Neighbors(n) {
				switch other.EdgeKind(g.EdgeBetween(neighbor, n)) {
				case ExposedThroughServiceGraphEdgeKind:
					covers = append(covers, neighbor.(*DeploymentConfigNode))
				}
			}
			group.Services = append(group.Services, ServiceReference{
				Service: n.(*ServiceNode),
				Covers:  covers,
			})
		}
		sort.Sort(SortedServiceReferences(group.Services))

		for _, n := range dcs {
			d := n.(*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, ExistingDirectEdge)
			for _, n := range unknown.NodeList() {
				g.PredecessorEdges(n, AddGraphEdgesTo(unknown), BuildOutputGraphEdgeKind)
			}
			unknown = unknown.EdgeSubgraph(ReverseGraphEdge)
			for _, n := range unknown.RootNodes() {
				if flow, ok := ImagePipelineFromNode(unknown, n, make(NodeSet)); ok {
					group.Builds = append(group.Builds, flow)
				}
			}
		}
		sort.Sort(SortedImagePipelines(group.Builds))

		serviceGroups = append(serviceGroups, group)
	}
	sort.Sort(SortedServiceGroups(serviceGroups))
	return serviceGroups
}
Beispiel #3
0
// 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
}