Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
aos
GitHub Repository: aos/grafana-agent
Path: blob/main/pkg/operator/config/utils.go
4095 views
1
package config
2
3
import (
4
"encoding/json"
5
"fmt"
6
"regexp"
7
8
"github.com/fatih/structs"
9
jsonnet "github.com/google/go-jsonnet"
10
gragent "github.com/grafana/agent/pkg/operator/apis/monitoring/v1alpha1"
11
"sigs.k8s.io/yaml"
12
)
13
14
func unmarshalYAML(i []interface{}) (interface{}, error) {
15
text, ok := i[0].(string)
16
if !ok {
17
return nil, jsonnet.RuntimeError{Msg: "unmarshalYAML text argument must be a string"}
18
}
19
var v interface{}
20
err := yaml.Unmarshal([]byte(text), &v)
21
if err != nil {
22
return nil, jsonnet.RuntimeError{Msg: err.Error()}
23
}
24
return v, nil
25
}
26
27
// trimMap recursively deletes fields from m whose value is nil.
28
func trimMap(m map[string]interface{}) {
29
for k, v := range m {
30
if v == nil {
31
delete(m, k)
32
continue
33
}
34
35
if next, ok := v.(map[string]interface{}); ok {
36
trimMap(next)
37
}
38
39
if arr, ok := v.([]interface{}); ok {
40
m[k] = trimSlice(arr)
41
}
42
}
43
}
44
45
func trimSlice(s []interface{}) []interface{} {
46
res := make([]interface{}, 0, len(s))
47
48
for _, e := range s {
49
if e == nil {
50
continue
51
}
52
53
if next, ok := e.([]interface{}); ok {
54
e = trimSlice(next)
55
}
56
57
if next, ok := e.(map[string]interface{}); ok {
58
trimMap(next)
59
}
60
61
res = append(res, e)
62
}
63
64
return res
65
}
66
67
// intoStages converts a yaml slice of stages into a Jsonnet array.
68
func intoStages(i []interface{}) (interface{}, error) {
69
text, ok := i[0].(string)
70
if !ok {
71
return nil, jsonnet.RuntimeError{Msg: "text argument not string"}
72
}
73
74
// The way this works is really, really gross. We only need any of this
75
// because Kubernetes CRDs can't recursively define types, which we need
76
// for the match stage.
77
//
78
// 1. Convert YAML -> map[string]interface{}
79
// 2. Convert map[string]interface{} -> JSON
80
// 3. Convert JSON -> []*grafana.PipelineStageSpec
81
// 4. Convert []*grafana.PipelineStageSpec into []interface{}, where
82
// each interface{} has the type information lost so marshaling it
83
// again to JSON doesn't break anything.
84
var raw interface{}
85
if err := yaml.Unmarshal([]byte(text), &raw); err != nil {
86
return nil, jsonnet.RuntimeError{
87
Msg: fmt.Sprintf("failed to unmarshal stages: %s", err.Error()),
88
}
89
}
90
91
bb, err := json.Marshal(raw)
92
if err != nil {
93
return nil, jsonnet.RuntimeError{
94
Msg: fmt.Sprintf("failed to unmarshal stages: %s", err.Error()),
95
}
96
}
97
98
var ps []*gragent.PipelineStageSpec
99
if err := json.Unmarshal(bb, &ps); err != nil {
100
return nil, jsonnet.RuntimeError{
101
Msg: fmt.Sprintf("failed to unmarshal stages: %s", err.Error()),
102
}
103
}
104
105
// Then we need to convert each into their raw types.
106
rawPS := make([]interface{}, 0, len(ps))
107
for _, stage := range ps {
108
bb, err := json.Marshal(structs.Map(stage))
109
if err != nil {
110
return nil, jsonnet.RuntimeError{
111
Msg: fmt.Sprintf("failed to unmarshal stages: %s", err.Error()),
112
}
113
}
114
115
var v interface{}
116
if err := json.Unmarshal(bb, &v); err != nil {
117
return nil, jsonnet.RuntimeError{
118
Msg: fmt.Sprintf("failed to unmarshal stages: %s", err.Error()),
119
}
120
}
121
122
rawPS = append(rawPS, v)
123
}
124
return rawPS, nil
125
}
126
127
var invalidLabelCharRE = regexp.MustCompile(`[^a-zA-Z0-9_]`)
128
129
// SanitizeLabelName sanitizes a label name for Prometheus.
130
func SanitizeLabelName(name string) string {
131
return invalidLabelCharRE.ReplaceAllString(name, "_")
132
}
133
134