16
16
package translate
17
17
18
18
import (
19
+ "errors"
19
20
"fmt"
21
+ "reflect"
20
22
23
+ "github.com/stretchr/testify/assert/yaml"
21
24
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
25
+ "sigs.k8s.io/controller-runtime/pkg/client"
22
26
)
23
27
24
28
const (
@@ -27,21 +31,136 @@ const (
27
31
SecretProperySelector = "$.data.#"
28
32
)
29
33
30
- type Mapper struct {
31
- deps DependencyRepo
34
+ type mapContext struct {
35
+ main client.Object
36
+ m map [client.ObjectKey ]client.Object
37
+ added []client.Object
38
+ }
39
+
40
+ func newMapContext (main client.Object , objs ... client.Object ) * mapContext {
41
+ m := map [client.ObjectKey ]client.Object {}
42
+ for _ , obj := range objs {
43
+ m [client .ObjectKeyFromObject (obj )] = obj
44
+ }
45
+ return & mapContext {main : main , m : m }
46
+ }
47
+
48
+ func (mc * mapContext ) find (name string ) client.Object {
49
+ key := client.ObjectKey {Name : name , Namespace : mc .main .GetNamespace ()}
50
+ return mc .m [key ]
51
+ }
52
+
53
+ func (mc * mapContext ) has (name string ) bool {
54
+ return mc .find (name ) != nil
55
+ }
56
+
57
+ func (mc * mapContext ) add (obj client.Object ) {
58
+ mc .m [client .ObjectKeyFromObject (obj )] = obj
59
+ mc .added = append (mc .added , obj )
60
+ }
61
+
62
+ type mapper struct {
63
+ * mapContext
32
64
expand bool
33
65
}
34
66
35
- func (m * Mapper ) mapProperties (path []string , props , obj map [string ]any ) error {
67
+ func newExpanderMapper (main client.Object , objs ... client.Object ) * mapper {
68
+ return newMapper (true , main , objs ... )
69
+ }
70
+
71
+ func newCollarserMapper (main client.Object , objs ... client.Object ) * mapper {
72
+ return newMapper (false , main , objs ... )
73
+ }
74
+
75
+ func newMapper (expand bool , main client.Object , objs ... client.Object ) * mapper {
76
+ return & mapper {
77
+ mapContext : newMapContext (main , objs ... ),
78
+ expand : expand ,
79
+ }
80
+ }
81
+
82
+ func ExpandMappings (t * Translator , obj map [string ]any , main client.Object , objs ... client.Object ) ([]client.Object , error ) {
83
+ em := newExpanderMapper (main , objs ... )
84
+ mappingsYML := t .crd .definition .Annotations [APIMAppingsAnnotation ]
85
+ if mappingsYML == "" {
86
+ return []client.Object {}, nil
87
+ }
88
+ mappings := map [string ]any {}
89
+ if err := yaml .Unmarshal ([]byte (mappingsYML ), mappings ); err != nil {
90
+ return nil , fmt .Errorf ("failed to unmarshal mappings YAML: %w" , err )
91
+ }
92
+
93
+ if err := em .expandMappingsAt (obj , mappings , "spec" , t .majorVersion ); err != nil {
94
+ return nil , fmt .Errorf ("failed to map properties of spec from API to Kubernetes: %w" , err )
95
+ }
96
+ if err := em .expandMappingsAt (obj , mappings , "spec" , t .majorVersion , "entry" ); err != nil {
97
+ return nil , fmt .Errorf ("failed to map properties of spec from API to Kubernetes: %w" , err )
98
+ }
99
+ if err := em .expandMappingsAt (obj , mappings , "status" , t .majorVersion ); err != nil {
100
+ return nil , fmt .Errorf ("failed to map properties of status from API to Kubernetes: %w" , err )
101
+ }
102
+ return em .added , nil
103
+ }
104
+
105
+ func CollapseMappings (t * Translator , spec map [string ]any , main client.Object , objs ... client.Object ) error {
106
+ cm := newCollarserMapper (main , objs ... )
107
+ mappingsYML := t .crd .definition .Annotations [APIMAppingsAnnotation ]
108
+ if mappingsYML == "" {
109
+ return nil
110
+ }
111
+ mappings := map [string ]any {}
112
+ if err := yaml .Unmarshal ([]byte (mappingsYML ), mappings ); err != nil {
113
+ return fmt .Errorf ("failed to unmarshal mappings YAML: %w" , err )
114
+ }
115
+ props , err := accessField [map [string ]any ](mappings ,
116
+ "properties" , "spec" , "properties" , t .majorVersion , "properties" )
117
+ if errors .Is (err , ErrNotFound ) {
118
+ return nil
119
+ }
120
+ if err != nil {
121
+ return fmt .Errorf ("failed to access the API mapping properties for the spec: %w" , err )
122
+ }
123
+ return cm .mapProperties ([]string {}, props , spec )
124
+ }
125
+
126
+ func findEntryPathInTarget (targetType reflect.Type ) []string {
127
+ if targetType .String () == "admin.CreateAlertConfigurationApiParams" {
128
+ return []string {"GroupAlertsConfig" }
129
+ }
130
+ return []string {}
131
+ }
132
+
133
+ func (m * mapper ) expandMappingsAt (obj , mappings map [string ]any , fields ... string ) error {
134
+ expandedPath := []string {"properties" }
135
+ for _ , field := range fields {
136
+ expandedPath = append (expandedPath , field , "properties" )
137
+ }
138
+ props , err := accessField [map [string ]any ](mappings , expandedPath ... )
139
+ if errors .Is (err , ErrNotFound ) {
140
+ return nil
141
+ }
142
+ if err != nil {
143
+ return fmt .Errorf ("failed to access the API mapping properties for %v: %w" , expandedPath , err )
144
+ }
145
+ field , err := accessField [map [string ]any ](obj , fields ... )
146
+ if err != nil {
147
+ return fmt .Errorf ("failed to access object's %v: %w" , fields , err )
148
+ }
149
+ if err := m .mapProperties ([]string {}, props , field ); err != nil {
150
+ return fmt .Errorf ("failed to process properties from API into %v: %w" , fields , err )
151
+ }
152
+ return nil
153
+ }
154
+
155
+ func (m * mapper ) mapProperties (path []string , props , obj map [string ]any ) error {
36
156
for key , prop := range props {
37
157
mapping , ok := (prop ).(map [string ]any )
38
158
if ! ok {
39
159
continue
40
160
}
41
161
subPath := append (path , key )
42
162
if isReference (mapping ) {
43
- err := m .mapReference (subPath , key , mapping , obj )
44
- if err != nil {
163
+ if err := m .mapReference (subPath , key , mapping , obj ); err != nil {
45
164
return fmt .Errorf ("failed to process reference: %w" , err )
46
165
}
47
166
continue
@@ -54,20 +173,23 @@ func (m *Mapper) mapProperties(path []string, props, obj map[string]any) error {
54
173
return fmt .Errorf ("failed to access %q: %w" , key , err )
55
174
}
56
175
if arrayField , ok := (rawField ).([]any ); ok {
57
- return m .mapArray (subPath , mapping , arrayField )
176
+ if err := m .mapArray (subPath , mapping , arrayField ); err != nil {
177
+ return fmt .Errorf ("failed to process array mapping %q: %w" , key , err )
178
+ }
179
+ continue
58
180
}
59
181
subSpec , ok := (rawField ).(map [string ]any )
60
182
if ! ok {
61
183
return fmt .Errorf ("unsupported mapping of type %T" , rawField )
62
184
}
63
185
if err := m .mapObject (subPath , key , mapping , subSpec ); err != nil {
64
- return fmt .Errorf ("failed to process mapping %q: %w" , key , err )
186
+ return fmt .Errorf ("failed to process object mapping %q: %w" , key , err )
65
187
}
66
188
}
67
189
return nil
68
190
}
69
191
70
- func (m * Mapper ) mapArray (path []string , mapping map [string ]any , list []any ) error {
192
+ func (m * mapper ) mapArray (path []string , mapping map [string ]any , list []any ) error {
71
193
mapItems , err := accessField [map [string ]any ](mapping , "items" , "properties" )
72
194
if err != nil {
73
195
return fmt .Errorf ("failed to access %q: %w" , base (path ), err )
@@ -89,7 +211,7 @@ func (m *Mapper) mapArray(path []string, mapping map[string]any, list []any) err
89
211
return nil
90
212
}
91
213
92
- func (m * Mapper ) mapObject (path []string , mapName string , mapping , obj map [string ]any ) error {
214
+ func (m * mapper ) mapObject (path []string , mapName string , mapping , obj map [string ]any ) error {
93
215
if mapping ["properties" ] != nil {
94
216
props , err := accessField [map [string ]any ](mapping , "properties" )
95
217
if err != nil {
@@ -103,16 +225,16 @@ func (m *Mapper) mapObject(path []string, mapName string, mapping, obj map[strin
103
225
return fmt .Errorf ("unsupported extension at %v with fields %v" , path , fieldsOf (mapping ))
104
226
}
105
227
106
- func (m * Mapper ) mapReference (path []string , mappingName string , mapping , obj map [string ]any ) error {
228
+ func (m * mapper ) mapReference (path []string , mappingName string , mapping , obj map [string ]any ) error {
107
229
rm := refMapping {}
108
230
if err := fromUnstructured (& rm , mapping ); err != nil {
109
231
return fmt .Errorf ("failed to parse a reference mapping: %w" , err )
110
232
}
111
233
ref := newRef (mappingName , & rm )
112
234
if m .expand {
113
- return ref .Expand (m .deps , path , obj )
235
+ return ref .Expand (m .mapContext , path , obj )
114
236
}
115
- return ref .Collapse (m .deps , path , obj )
237
+ return ref .Collapse (m .mapContext , path , obj )
116
238
}
117
239
118
240
func entryMatchingMapping (mapName string , mapping map [string ]any , list []any , expand bool ) (string , map [string ]any ) {
0 commit comments