-
Notifications
You must be signed in to change notification settings - Fork 19
/
builder_view_dependency_resolution.go
98 lines (86 loc) · 3.83 KB
/
builder_view_dependency_resolution.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
package visualization
import (
"github.com/Aptomi/aptomi/pkg/lang"
"github.com/Aptomi/aptomi/pkg/runtime"
)
// DependencyResolutionCfg defines graph generation parameters for DependencyResolution
type DependencyResolutionCfg struct {
showTrivialContracts bool
showContracts bool
}
// DependencyResolutionCfgDefault is default graph generation parameters for DependencyResolution
var DependencyResolutionCfgDefault = &DependencyResolutionCfg{
showTrivialContracts: true,
showContracts: false,
}
// DependencyResolution produces policy resolution graph by tracing every dependency and displaying what got allocated
func (b *GraphBuilder) DependencyResolution(cfg *DependencyResolutionCfg) *Graph {
// trace all dependencies
for _, dependencyObj := range b.policy.GetObjectsByKind(lang.DependencyObject.Kind) {
dependency := dependencyObj.(*lang.Dependency)
b.traceDependencyResolution("", dependency, nil, 0, cfg)
}
return b.graph
}
func (b *GraphBuilder) traceDependencyResolution(keySrc string, dependency *lang.Dependency, last graphNode, level int, cfg *DependencyResolutionCfg) {
var edgesOut map[string]bool
if len(keySrc) <= 0 {
// create a dependency node
depNode := dependencyNode{dependency: dependency, b: b}
b.graph.addNode(depNode, 0)
last = depNode
level++
// add an outgoing edge to its corresponding service instance
edgesOut = make(map[string]bool)
resolvedKey := b.resolution.GetDependencyInstanceMap()[runtime.KeyForStorable(dependency)]
if len(resolvedKey) > 0 {
edgesOut[resolvedKey] = true
}
} else {
// if we are processing a component instance, then follow the recorded graph edges
edgesOut = b.resolution.ComponentInstanceMap[keySrc].EdgesOut
}
// recursively walk the graph
for keyDst := range edgesOut {
instanceCurrent := b.resolution.ComponentInstanceMap[keyDst]
if instanceCurrent.Metadata.Key.IsService() {
// if it's a service, then create a contract node
contractObj, errContract := b.policy.GetObject(lang.ContractObject.Kind, instanceCurrent.Metadata.Key.ContractName, instanceCurrent.Metadata.Key.Namespace)
if errContract != nil {
b.graph.addNode(errorNode{err: errContract}, level)
continue
}
contract := contractObj.(*lang.Contract)
ctrNode := contractNode{contract: contract}
// then create a service instance node
serviceObj, errService := b.policy.GetObject(lang.ServiceObject.Kind, instanceCurrent.Metadata.Key.ServiceName, instanceCurrent.Metadata.Key.Namespace)
if errService != nil {
b.graph.addNode(errorNode{err: errService}, level)
continue
}
service := serviceObj.(*lang.Service)
svcInstNode := serviceInstanceNode{instance: instanceCurrent, service: service}
// let's see if we need to show last -> contract -> serviceInstance, or skip contract all together
trivialContract := len(contract.Contexts) <= 1
if cfg.showContracts && (!trivialContract || cfg.showTrivialContracts) {
// show 'last' -> 'contract' -> 'serviceInstance' -> (continue)
b.graph.addNode(ctrNode, level)
b.graph.addEdge(newEdge(last, ctrNode, ""))
b.graph.addNode(svcInstNode, level+1)
b.graph.addEdge(newEdge(ctrNode, svcInstNode, instanceCurrent.Metadata.Key.ContextNameWithKeys))
// continue tracing
b.traceDependencyResolution(keyDst, dependency, svcInstNode, level+2, cfg)
} else {
// skip contract, show just 'last' -> 'serviceInstance' -> (continue)
b.graph.addNode(svcInstNode, level)
b.graph.addEdge(newEdge(last, svcInstNode, ""))
// continue tracing
b.traceDependencyResolution(keyDst, dependency, svcInstNode, level+1, cfg)
}
} else {
// if it's a component, we don't need to show any additional nodes, let's just continue
// though, we could introduce additional flag which allows to render components, if needed
b.traceDependencyResolution(keyDst, dependency, last, level, cfg)
}
}
}