// UncoveredDeploymentFlowNodes includes nodes that either services or deployment // configs, or which haven't previously been covered. func UncoveredDeploymentFlowNodes(covered osgraph.NodeSet) osgraph.NodeFunc { return func(g osgraph.Interface, node graph.Node) bool { switch node.(type) { case *deploygraph.DeploymentConfigNode, *kubegraph.ServiceNode: return true } return !covered.Has(node.ID()) } }
// 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) } }
func findBuildInputs(g osgraph.Graph, n graph.Node, covered osgraph.NodeSet) (base ImageTagLocation, source SourceLocation, err error) { // find inputs to the build for _, input := range g.Neighbors(n) { switch g.EdgeKind(g.EdgeBetween(n, input)) { case buildedges.BuildInputEdgeKind: if source != nil { // report this as an error (unexpected duplicate source) } covered.Add(input.ID()) source = input.(SourceLocation) case buildedges.BuildInputImageEdgeKind: if base != nil { // report this as an error (unexpected duplicate input build) } covered.Add(input.ID()) base = input.(ImageTagLocation) } } return }
// subgraphWithoutPrunableImages creates a subgraph from g with prunable image // nodes excluded. func subgraphWithoutPrunableImages(g graph.Graph, prunableImageIDs graph.NodeSet) graph.Graph { return g.Subgraph( func(g graph.Interface, node gonum.Node) bool { return !prunableImageIDs.Has(node.ID()) }, func(g graph.Interface, head, tail gonum.Node, edgeKinds util.StringSet) bool { if prunableImageIDs.Has(head.ID()) { return false } if prunableImageIDs.Has(tail.ID()) { return false } return true }, ) }
// subgraphWithoutPrunableImages creates a subgraph from g with prunable image // nodes excluded. func subgraphWithoutPrunableImages(g graph.Graph, prunableImageIDs graph.NodeSet) graph.Graph { return g.Subgraph( func(g graph.Interface, node gonum.Node) bool { return !prunableImageIDs.Has(node.ID()) }, func(g graph.Interface, from, to gonum.Node, edgeKinds sets.String) bool { if prunableImageIDs.Has(from.ID()) { return false } if prunableImageIDs.Has(to.ID()) { return false } return true }, ) }
// ImagePipelineFromNode attempts to locate a build flow from the provided node. If no such // build flow can be located, false is returned. func ImagePipelineFromNode(g osgraph.Graph, n graph.Node, covered osgraph.NodeSet) (ImagePipeline, bool) { flow := ImagePipeline{} switch node := n.(type) { case *buildgraph.BuildConfigNode: covered.Add(n.ID()) base, src, _ := findBuildInputs(g, n, covered) flow.Build = node flow.BaseImage = base flow.Source = src return flow, true case ImageTagLocation: covered.Add(n.ID()) flow.Image = node for _, input := range g.Neighbors(n) { switch g.EdgeKind(g.EdgeBetween(n, input)) { case buildedges.BuildOutputEdgeKind: covered.Add(input.ID()) build := input.(*buildgraph.BuildConfigNode) if flow.Build != nil { // report this as an error (unexpected duplicate input build) } if build.BuildConfig == nil { // report this as as a missing build / broken link break } base, src, _ := findBuildInputs(g, input, covered) flow.Build = build flow.BaseImage = base flow.Source = src } } return flow, true default: return flow, false } }