/
config_traversal.go
91 lines (81 loc) · 2.64 KB
/
config_traversal.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
package query
import (
"strings"
"github.com/flanksource/duty/context"
"github.com/flanksource/duty/models"
"github.com/flanksource/gomplate/v3/conv"
"github.com/google/cel-go/cel"
"github.com/google/cel-go/common/types"
"github.com/google/cel-go/common/types/ref"
)
func TraverseConfig(ctx context.Context, configID, relationType, direction string) []models.ConfigItem {
var configItems []models.ConfigItem
ids := []string{configID}
for _, typ := range strings.Split(relationType, "/") {
ids = getRelatedTypeConfigID(ctx, ids, typ, direction)
}
for _, id := range ids {
configItem, err := ConfigItemFromCache(ctx, id)
if err != nil {
ctx.Tracef("no config[%s] found in cache: %v", id, err)
continue
}
configItems = append(configItems, configItem)
}
return configItems
}
// Fetch config IDs which match the type and direction upto max depth (5)
func getRelatedTypeConfigID(ctx context.Context, ids []string, relatedType, direction string) []string {
var allIDs []string
for _, id := range ids {
q := ctx.DB().Table("related_configs_recursive(?, ?)", id, direction).Select("id", "depth", "type").Where("type = ?", relatedType)
var rows []struct {
ID string
Type string
Depth int
}
if err := q.Scan(&rows).Error; err != nil {
ctx.Tracef("error querying database for related_configs[%s]: %v", id, err)
return nil
}
for _, r := range rows {
allIDs = append(allIDs, r.ID)
}
}
return allIDs
}
func traverseConfigCELFunction() func(ctx context.Context) cel.EnvOption {
return func(ctx context.Context) cel.EnvOption {
return cel.Function("catalog.traverse",
cel.Overload("catalog.traverse_string_string",
[]*cel.Type{cel.StringType, cel.StringType, cel.StringType},
cel.AnyType,
cel.FunctionBinding(func(args ...ref.Val) ref.Val {
if len(args) < 2 || len(args) > 3 {
return types.String("invalid number of args")
}
id := conv.ToString(args[0])
typ := conv.ToString(args[1])
direction := "incoming"
if len(args) == 3 {
direction = conv.ToString(args[2])
}
items := TraverseConfig(ctx, id, typ, direction)
jsonObj, _ := conv.AnyToListMapStringAny(items)
return types.NewDynamicList(types.DefaultTypeAdapter, jsonObj)
}),
),
)
}
}
func traverseConfigTemplateFunction() func(ctx context.Context) any {
return func(ctx context.Context) any {
return func(id, relationType, direction string) []models.ConfigItem {
return TraverseConfig(ctx, id, relationType, direction)
}
}
}
func init() {
context.CelEnvFuncs["catalog.traverse"] = traverseConfigCELFunction()
context.TemplateFuncs["catalog_traverse"] = traverseConfigTemplateFunction()
}