Skip to content

Commit c6303ee

Browse files
authored
Remove deps, embed in mappings (#2776)
1 parent 85efeac commit c6303ee

File tree

4 files changed

+148
-179
lines changed

4 files changed

+148
-179
lines changed

internal/v3/translate/deps.go

Lines changed: 0 additions & 80 deletions
This file was deleted.

internal/v3/translate/mapping.go

Lines changed: 134 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,13 @@
1616
package translate
1717

1818
import (
19+
"errors"
1920
"fmt"
21+
"reflect"
2022

23+
"github.com/stretchr/testify/assert/yaml"
2124
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
25+
"sigs.k8s.io/controller-runtime/pkg/client"
2226
)
2327

2428
const (
@@ -27,21 +31,136 @@ const (
2731
SecretProperySelector = "$.data.#"
2832
)
2933

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
3264
expand bool
3365
}
3466

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 {
36156
for key, prop := range props {
37157
mapping, ok := (prop).(map[string]any)
38158
if !ok {
39159
continue
40160
}
41161
subPath := append(path, key)
42162
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 {
45164
return fmt.Errorf("failed to process reference: %w", err)
46165
}
47166
continue
@@ -54,20 +173,23 @@ func (m *Mapper) mapProperties(path []string, props, obj map[string]any) error {
54173
return fmt.Errorf("failed to access %q: %w", key, err)
55174
}
56175
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
58180
}
59181
subSpec, ok := (rawField).(map[string]any)
60182
if !ok {
61183
return fmt.Errorf("unsupported mapping of type %T", rawField)
62184
}
63185
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)
65187
}
66188
}
67189
return nil
68190
}
69191

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 {
71193
mapItems, err := accessField[map[string]any](mapping, "items", "properties")
72194
if err != nil {
73195
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
89211
return nil
90212
}
91213

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 {
93215
if mapping["properties"] != nil {
94216
props, err := accessField[map[string]any](mapping, "properties")
95217
if err != nil {
@@ -103,16 +225,16 @@ func (m *Mapper) mapObject(path []string, mapName string, mapping, obj map[strin
103225
return fmt.Errorf("unsupported extension at %v with fields %v", path, fieldsOf(mapping))
104226
}
105227

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 {
107229
rm := refMapping{}
108230
if err := fromUnstructured(&rm, mapping); err != nil {
109231
return fmt.Errorf("failed to parse a reference mapping: %w", err)
110232
}
111233
ref := newRef(mappingName, &rm)
112234
if m.expand {
113-
return ref.Expand(m.deps, path, obj)
235+
return ref.Expand(m.mapContext, path, obj)
114236
}
115-
return ref.Collapse(m.deps, path, obj)
237+
return ref.Collapse(m.mapContext, path, obj)
116238
}
117239

118240
func entryMatchingMapping(mapName string, mapping map[string]any, list []any, expand bool) (string, map[string]any) {

internal/v3/translate/ref.go

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ func newRef(name string, rm *refMapping) *namedRef {
9292
return &namedRef{name: name, refMapping: rm}
9393
}
9494

95-
func (ref *namedRef) Expand(deps DependencyRepo, pathHint []string, obj map[string]any) error {
95+
func (ref *namedRef) Expand(mc *mapContext, pathHint []string, obj map[string]any) error {
9696
path := ref.pathToExpand(pathHint)
9797
rawValue, err := accessField[any](obj, base(path))
9898
if errors.Is(err, ErrNotFound) {
@@ -118,15 +118,19 @@ func (ref *namedRef) Expand(deps DependencyRepo, pathHint []string, obj map[stri
118118
}
119119
return fmt.Errorf("failed to populate final dependency object: %w", err)
120120
}
121-
dep.SetName(ref.Name(deps.MainObject().GetName(), path))
122-
dep.SetNamespace(SetFallbackNamespace)
123-
deps.Add(dep)
121+
name := ref.Name(mc.main.GetName(), path)
122+
if mc.has(name) {
123+
return nil
124+
}
125+
dep.SetName(name)
126+
dep.SetNamespace(mc.main.GetNamespace())
124127
refData := map[string]any{"name": dep.GetName()}
125128
if ref.XOpenAPIMapping.Property != "" {
126129
path := resolveXPath(ref.XOpenAPIMapping.Property)
127130
refData["key"] = base(path)
128131
}
129132
obj[ref.name] = refData
133+
mc.add(dep)
130134
return nil
131135
}
132136

@@ -148,7 +152,7 @@ func (ref *namedRef) Name(prefix string, path []string) string {
148152
return PrefixedName(prefix, path[0], path[1:]...)
149153
}
150154

151-
func (ref *namedRef) Collapse(deps DependencyRepo, path []string, obj map[string]any) error {
155+
func (ref *namedRef) Collapse(mc *mapContext, path []string, obj map[string]any) error {
152156
reference, err := accessField[map[string]any](obj, base(path))
153157
if errors.Is(err, ErrNotFound) {
154158
return nil
@@ -165,7 +169,7 @@ func (ref *namedRef) Collapse(deps DependencyRepo, path []string, obj map[string
165169
if !ok || key == "" {
166170
key = base(targetPath)
167171
}
168-
value, err := ref.XKubernetesMapping.FetchReferencedValue(key, reference, deps)
172+
value, err := ref.XKubernetesMapping.FetchReferencedValue(mc, key, reference)
169173
if err != nil {
170174
return fmt.Errorf("failed to fetch referenced value %s: %w", key, err)
171175
}
@@ -204,7 +208,7 @@ func (km kubeMapping) Equal(gvk schema.GroupVersionKind) bool {
204208
return km.Type.Group == gvk.Group && km.Type.Version == gvk.Version && km.Type.Kind == gvk.Kind
205209
}
206210

207-
func (km kubeMapping) FetchReferencedValue(target string, reference map[string]any, deps DependencyRepo) (any, error) {
211+
func (km kubeMapping) FetchReferencedValue(mc *mapContext, target string, reference map[string]any) (any, error) {
208212
refPath := km.NameSelector
209213
if refPath == "" {
210214
return nil, errors.New("cannot solve reference without a x-kubernetes-mapping.nameSelector")
@@ -213,7 +217,7 @@ func (km kubeMapping) FetchReferencedValue(target string, reference map[string]a
213217
if err != nil {
214218
return nil, fmt.Errorf("failed to access field %q at %v: %w", refPath, reference, err)
215219
}
216-
resource := deps.Find(refName, SetFallbackNamespace)
220+
resource := mc.find(refName)
217221
if resource == nil {
218222
return nil, fmt.Errorf("failed to find Kubernetes resource %q: %w", refName, err)
219223
}

0 commit comments

Comments
 (0)