/
management_graph.go
121 lines (104 loc) · 3.26 KB
/
management_graph.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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package types
import (
"fmt"
)
// BuildManagementGraph builds a Management Graph from a Policy.
func (g *ManagementGraph) LoadFromPolicy(policy *Policy) {
for _, resource := range policy.Resources {
// register relation and managed rels
for _, relation := range resource.Relations {
g.registerRel(resource.Name, relation.Name)
for _, managedRel := range relation.Manages {
g.RegisterManagedRel(resource.Name, relation.Name, managedRel)
}
}
}
}
// IsWellFormed walks through edges in graph and verifies whether the
// source and destination nodes for the edges are defined.
// If any edge is not defined, returns an error with the offending edges.
// If graph is well formed, return nil
func (g *ManagementGraph) IsWellFormed() error {
for src, edgs := range g.ForwardEdges {
for dst, _ := range edgs.Edges {
_, src_ok := g.getNode(src)
if !src_ok {
return fmt.Errorf("edge defined from %v to %v: %v not found", src, dst, src)
}
_, dst_ok := g.getNode(dst)
if !dst_ok {
return fmt.Errorf("edge defined from %v to %v: %v not found", src, dst, dst)
}
}
}
return nil
}
// RegisterManagement adds a management rule in the Management graph.
// The registered rule states that for resource sourceRel manages managedRel.
func (g *ManagementGraph) RegisterManagedRel(resource, sourceRel, managedRel string) {
srcId := g.buildNodeId(resource, sourceRel)
dstId := g.buildNodeId(resource, managedRel)
g.setEdg(srcId, dstId)
}
func (g *ManagementGraph) registerRel(resource, rel string) {
node := &ManagerNode{
Id: g.buildNodeId(resource, rel),
Text: rel,
}
g.setNode(node)
}
func (g *ManagementGraph) setEdg(src, dst string) {
if g.ForwardEdges == nil {
g.ForwardEdges = make(map[string]*ManagerEdges)
}
if g.ForwardEdges[src] == nil {
g.ForwardEdges[src] = &ManagerEdges{}
}
if g.ForwardEdges[src].Edges == nil {
g.ForwardEdges[src].Edges = make(map[string]bool)
}
g.ForwardEdges[src].Edges[dst] = true
if g.BackwardEdges == nil {
g.BackwardEdges = make(map[string]*ManagerEdges)
}
if g.BackwardEdges[dst] == nil {
g.BackwardEdges[dst] = &ManagerEdges{}
}
if g.BackwardEdges[dst].Edges == nil {
g.BackwardEdges[dst].Edges = make(map[string]bool)
}
g.BackwardEdges[dst].Edges[src] = true
}
func (g *ManagementGraph) setNode(node *ManagerNode) {
if g.Nodes == nil {
g.Nodes = make(map[string]*ManagerNode)
}
g.Nodes[node.Id] = node
}
func (g *ManagementGraph) getNode(id string) (*ManagerNode, bool) {
if g.Nodes == nil {
return nil, false
}
node, ok := g.Nodes[id]
return node, ok
}
func (g *ManagementGraph) buildNodeId(resource, rel string) string {
return resource + "/" + rel
}
// GetManagers return the list of relations which manages the relationName.
// Returns nil if relation wasn't found
func (g *ManagementGraph) GetManagers(resourceName, relationName string) []string {
// The Management graph points from the manager relation to the managee
// therefore the backward edges can be used to derive the managing relations
relId := g.buildNodeId(resourceName, relationName)
ancestors, ok := g.BackwardEdges[relId]
if !ok {
return nil
}
managers := make([]string, 0, len(ancestors.Edges))
for id := range ancestors.Edges {
node, _ := g.getNode(id)
managers = append(managers, node.Text)
}
return managers
}