forked from kyma-project/kyma
/
generic_sbu_tracer.go
144 lines (119 loc) · 4.57 KB
/
generic_sbu_tracer.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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package controller
import (
"encoding/json"
"fmt"
"github.com/pkg/errors"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
type genericUsageBindingAnnotationTracer interface {
GetInjectedLabels(res *unstructured.Unstructured, usageName string) (map[string]string, error)
DeleteAnnotationAboutBindingUsage(res *unstructured.Unstructured, usageName string) error
SetAnnotationAboutBindingUsage(res *unstructured.Unstructured, usageName string, labels map[string]string) error
}
// genericUsageAnnotationTracer adds information in any kind of Kubernetes resources that they have been modified
// by given ServiceBindingUsage
type genericUsageAnnotationTracer struct{}
// GetInjectedLabels returns all labels that have been added to given resources
func (c *genericUsageAnnotationTracer) GetInjectedLabels(res *unstructured.Unstructured, usageName string) (map[string]string, error) {
data, found, err := c.readAnnotationData(res)
if err != nil {
return map[string]string{}, errors.Wrapf(err, "while reading binding usage annotation tracing data")
}
if !found {
return map[string]string{}, nil
}
info, found := data[usageName]
if !found {
return map[string]string{}, nil
}
return info.InjectedLabelKeys, nil
}
func (c *genericUsageAnnotationTracer) DeleteAnnotationAboutBindingUsage(res *unstructured.Unstructured, usageName string) error {
data, found, err := c.readAnnotationData(res)
if err != nil {
return errors.Wrap(err, "while reading annotation tracing data")
}
if !found {
return nil
}
delete(data, usageName)
err = c.saveAnnotationData(res, data)
if err != nil {
return errors.Wrap(err, "while saving annotation tracing data")
}
return nil
}
// SetAnnotationAboutBindingUsage sets annotations about injected labels keys
func (c *genericUsageAnnotationTracer) SetAnnotationAboutBindingUsage(res *unstructured.Unstructured, usageName string, labels map[string]string) error {
data, _, err := c.readAnnotationData(res)
if err != nil {
return errors.Wrap(err, "while reading annotation tracing data")
}
info := data[usageName]
info.InjectedLabelKeys = labels
data[usageName] = info
err = c.saveAnnotationData(res, data)
if err != nil {
return errors.Wrap(err, "while saving annotation tracing data")
}
return nil
}
func (c *genericUsageAnnotationTracer) readAnnotationData(res *unstructured.Unstructured) (map[string]sbuTracingInfo, bool, error) {
annotations, err := c.extractAnnotations(res)
if err != nil {
return map[string]sbuTracingInfo{}, false, fmt.Errorf("while extracting annotations")
}
value, found := annotations[tracingAnnotationKey]
if !found {
return map[string]sbuTracingInfo{}, false, nil
}
valueAsString, ok := value.(string)
if !ok {
return map[string]sbuTracingInfo{}, false, fmt.Errorf("incorrect annotations, expect string but was %T", valueAsString)
}
var data map[string]sbuTracingInfo
err = json.Unmarshal([]byte(valueAsString), &data)
if err != nil {
return map[string]sbuTracingInfo{}, false, errors.Wrapf(err, "while unmarshalling annotation tracing data")
}
return data, true, nil
}
func (c *genericUsageAnnotationTracer) saveAnnotationData(res *unstructured.Unstructured, info map[string]sbuTracingInfo) error {
bytes, err := json.Marshal(info)
if err != nil {
return errors.Wrapf(err, "while marshalling annotation tracing data %+v for object (%s/%s)", info, res.GetNamespace(), res.GetName())
}
annotations, err := c.extractAnnotations(res)
if err != nil {
return fmt.Errorf("while extracting annotations")
}
metadataAsMap, ok := res.Object["metadata"].(map[string]interface{})
if !ok {
return fmt.Errorf("incorrect metadata, expect map[string]interface{} but was %T", res.Object["metadata"])
}
metadataAsMap["annotations"] = annotations
annotations[tracingAnnotationKey] = string(bytes)
if len(info) == 0 {
delete(annotations, tracingAnnotationKey)
}
return nil
}
func (c *genericUsageAnnotationTracer) extractAnnotations(res *unstructured.Unstructured) (map[string]interface{}, error) {
metadata, exists := res.Object["metadata"]
if !exists {
return map[string]interface{}{}, nil
}
metadataAsMap, ok := metadata.(map[string]interface{})
if !ok {
return map[string]interface{}{}, fmt.Errorf("incorrect metadata, expect map[string]interface{} but was %T", metadata)
}
annotations, exists := metadataAsMap["annotations"]
if !exists {
return map[string]interface{}{}, nil
}
annotationsAsMap, ok := annotations.(map[string]interface{})
if !ok {
return map[string]interface{}{}, fmt.Errorf("incorrect annotations, expect map[string]interface{} but was %T", annotations)
}
return annotationsAsMap, nil
}