Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 16 additions & 15 deletions internal/v3/translate/mapping.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ import (
"reflect"

"github.com/stretchr/testify/assert/yaml"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"sigs.k8s.io/controller-runtime/pkg/client"

"github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/v3/translate/unstructured"
)

const (
Expand Down Expand Up @@ -112,9 +113,9 @@ func CollapseMappings(t *Translator, spec map[string]any, main client.Object, ob
if err := yaml.Unmarshal([]byte(mappingsYML), mappings); err != nil {
return fmt.Errorf("failed to unmarshal mappings YAML: %w", err)
}
props, err := accessField[map[string]any](mappings,
props, err := unstructured.AccessField[map[string]any](mappings,
"properties", "spec", "properties", t.majorVersion, "properties")
if errors.Is(err, ErrNotFound) {
if errors.Is(err, unstructured.ErrNotFound) {
return nil
}
if err != nil {
Expand All @@ -135,14 +136,14 @@ func (m *mapper) expandMappingsAt(obj, mappings map[string]any, fields ...string
for _, field := range fields {
expandedPath = append(expandedPath, field, "properties")
}
props, err := accessField[map[string]any](mappings, expandedPath...)
if errors.Is(err, ErrNotFound) {
props, err := unstructured.AccessField[map[string]any](mappings, expandedPath...)
if errors.Is(err, unstructured.ErrNotFound) {
return nil
}
if err != nil {
return fmt.Errorf("failed to access the API mapping properties for %v: %w", expandedPath, err)
}
field, err := accessField[map[string]any](obj, fields...)
field, err := unstructured.AccessField[map[string]any](obj, fields...)
if err != nil {
return fmt.Errorf("failed to access object's %v: %w", fields, err)
}
Expand All @@ -165,8 +166,8 @@ func (m *mapper) mapProperties(path []string, props, obj map[string]any) error {
}
continue
}
rawField, ok, err := unstructured.NestedFieldNoCopy(obj, key)
if !ok {
rawField, err := unstructured.AccessField[any](obj, key) // unstructured.NestedFieldNoCopy(obj, key)
if errors.Is(err, unstructured.ErrNotFound) {
continue
}
if err != nil {
Expand All @@ -190,9 +191,9 @@ func (m *mapper) mapProperties(path []string, props, obj map[string]any) error {
}

func (m *mapper) mapArray(path []string, mapping map[string]any, list []any) error {
mapItems, err := accessField[map[string]any](mapping, "items", "properties")
mapItems, err := unstructured.AccessField[map[string]any](mapping, "items", "properties")
if err != nil {
return fmt.Errorf("failed to access %q: %w", base(path), err)
return fmt.Errorf("failed to access %q: %w", unstructured.Base(path), err)
}
for mapName, mapItem := range mapItems {
mapping, ok := (mapItem).(map[string]any)
Expand All @@ -213,7 +214,7 @@ func (m *mapper) mapArray(path []string, mapping map[string]any, list []any) err

func (m *mapper) mapObject(path []string, mapName string, mapping, obj map[string]any) error {
if mapping["properties"] != nil {
props, err := accessField[map[string]any](mapping, "properties")
props, err := unstructured.AccessField[map[string]any](mapping, "properties")
if err != nil {
return fmt.Errorf("failed to access properties at %q: %w", path, err)
}
Expand All @@ -222,12 +223,12 @@ func (m *mapper) mapObject(path []string, mapName string, mapping, obj map[strin
if isReference(mapping) {
return m.mapReference(path, mapName, mapping, obj)
}
return fmt.Errorf("unsupported extension at %v with fields %v", path, fieldsOf(mapping))
return fmt.Errorf("unsupported extension at %v with fields %v", path, unstructured.FieldsOf(mapping))
}

func (m *mapper) mapReference(path []string, mappingName string, mapping, obj map[string]any) error {
rm := refMapping{}
if err := fromUnstructured(&rm, mapping); err != nil {
if err := unstructured.FromUnstructured(&rm, mapping); err != nil {
return fmt.Errorf("failed to parse a reference mapping: %w", err)
}
ref := newRef(mappingName, &rm)
Expand All @@ -241,11 +242,11 @@ func entryMatchingMapping(mapName string, mapping map[string]any, list []any, ex
key := mapName
if expand {
refMap := refMapping{}
if err := fromUnstructured(&refMap, mapping); err != nil {
if err := unstructured.FromUnstructured(&refMap, mapping); err != nil {
return "", nil // not a ref, cannot reverse mapping dfrom API property name
}
path := resolveXPath(refMap.XOpenAPIMapping.Property)
key = base(path)
key = unstructured.Base(path)
}
return key, findByExistingKey(list, key)
}
Expand Down
67 changes: 34 additions & 33 deletions internal/v3/translate/ref.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"

v1 "github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/v3/translate/samples/v1"
"github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/v3/translate/unstructured"
)

type EncodeDecodeFunc func(any) (any, error)
Expand Down Expand Up @@ -65,9 +66,9 @@ func newKubeObjectFactory[T any, P PtrClientObj[T]]() func(map[string]any) (clie
}
}

func initObject[T any](obj *T, unstructured map[string]any) (*T, error) {
if unstructured != nil {
if err := fromUnstructured(obj, unstructured); err != nil {
func initObject[T any](obj *T, unstructuredObj map[string]any) (*T, error) {
if unstructuredObj != nil {
if err := unstructured.FromUnstructured(obj, unstructuredObj); err != nil {
return nil, err
}
}
Expand All @@ -94,8 +95,8 @@ func newRef(name string, rm *refMapping) *namedRef {

func (ref *namedRef) Expand(mc *mapContext, pathHint []string, obj map[string]any) error {
path := ref.pathToExpand(pathHint)
rawValue, err := accessField[any](obj, base(path))
if errors.Is(err, ErrNotFound) {
rawValue, err := unstructured.AccessField[any](obj, unstructured.Base(path))
if errors.Is(err, unstructured.ErrNotFound) {
return nil
}
if err != nil {
Expand Down Expand Up @@ -127,7 +128,7 @@ func (ref *namedRef) Expand(mc *mapContext, pathHint []string, obj map[string]an
refData := map[string]any{"name": dep.GetName()}
if ref.XOpenAPIMapping.Property != "" {
path := resolveXPath(ref.XOpenAPIMapping.Property)
refData["key"] = base(path)
refData["key"] = unstructured.Base(path)
}
obj[ref.name] = refData
mc.add(dep)
Expand All @@ -137,7 +138,7 @@ func (ref *namedRef) Expand(mc *mapContext, pathHint []string, obj map[string]an
func (ref *namedRef) pathToExpand(pathHint []string) []string {
path := make([]string, len(pathHint))
copy(path, pathHint)
path[len(path)-1] = base(resolveXPath(ref.XOpenAPIMapping.Property))
path[len(path)-1] = unstructured.Base(resolveXPath(ref.XOpenAPIMapping.Property))
return path
}

Expand All @@ -153,8 +154,8 @@ func (ref *namedRef) Name(prefix string, path []string) string {
}

func (ref *namedRef) Collapse(mc *mapContext, path []string, obj map[string]any) error {
reference, err := accessField[map[string]any](obj, base(path))
if errors.Is(err, ErrNotFound) {
reference, err := unstructured.AccessField[map[string]any](obj, unstructured.Base(path))
if errors.Is(err, unstructured.ErrNotFound) {
return nil
}
if err != nil {
Expand All @@ -167,13 +168,13 @@ func (ref *namedRef) Collapse(mc *mapContext, path []string, obj map[string]any)
targetPath := ref.XOpenAPIMapping.TargetPath()
key, ok := reference["key"].(string)
if !ok || key == "" {
key = base(targetPath)
key = unstructured.Base(targetPath)
}
value, err := ref.XKubernetesMapping.FetchReferencedValue(mc, key, reference)
if err != nil {
return fmt.Errorf("failed to fetch referenced value %s: %w", key, err)
}
return createField(obj, value, targetPath...)
return unstructured.CreateField(obj, value, targetPath...)
}

type kubeMapping struct {
Expand Down Expand Up @@ -213,7 +214,7 @@ func (km kubeMapping) FetchReferencedValue(mc *mapContext, target string, refere
if refPath == "" {
return nil, errors.New("cannot solve reference without a x-kubernetes-mapping.nameSelector")
}
refName, err := accessField[string](reference, asPath(refPath)...)
refName, err := unstructured.AccessField[string](reference, unstructured.AsPath(refPath)...)
if err != nil {
return nil, fmt.Errorf("failed to access field %q at %v: %w", refPath, reference, err)
}
Expand All @@ -225,18 +226,18 @@ func (km kubeMapping) FetchReferencedValue(mc *mapContext, target string, refere
if km.Type.Kind != "" && !km.Equal(gvk) {
return nil, fmt.Errorf("resource %q had to be a %q but got %q", refName, km.GVK(), gvk)
}
resourceMap, err := toUnstructured(resource)
resourceMap, err := unstructured.ToUnstructured(resource)
if err != nil {
return nil, fmt.Errorf("failed to turn resource %q into an unestuctued map: %w", refName, err)
}
value, err := km.fetchFromProperties(resourceMap)
if err != nil && !errors.Is(err, ErrNotFound) {
if err != nil && !errors.Is(err, unstructured.ErrNotFound) {
return nil, fmt.Errorf("failed to resolve reference properties: %w", err)
}
if errors.Is(err, ErrNotFound) {
if errors.Is(err, unstructured.ErrNotFound) {
var err error
value, err = km.fetchFromPropertySelectors(resourceMap, target)
if errors.Is(err, ErrNotFound) {
if errors.Is(err, unstructured.ErrNotFound) {
return nil, fmt.Errorf("failed to resolve reference properties or property selectors: %w", err)
}
if err != nil {
Expand Down Expand Up @@ -265,16 +266,16 @@ func (km kubeMapping) Encode(value any) (any, error) {
func (km kubeMapping) fetchFromProperties(resource map[string]any) (any, error) {
for _, prop := range km.Properties {
path := resolveXPath(prop)
value, err := accessField[any](resource, path...)
if errors.Is(err, ErrNotFound) {
value, err := unstructured.AccessField[any](resource, path...)
if errors.Is(err, unstructured.ErrNotFound) {
continue
}
if err != nil {
return nil, fmt.Errorf("failed to access property as %v: %w", path, err)
}
return value, nil
}
return nil, ErrNotFound
return nil, unstructured.ErrNotFound
}

func (km kubeMapping) fetchFromPropertySelectors(resource map[string]any, target string) (any, error) {
Expand All @@ -284,46 +285,46 @@ func (km kubeMapping) fetchFromPropertySelectors(resource map[string]any, target
prop = fmt.Sprintf("%s.%s", prop[:len(prop)-2], target)
}
path := resolveXPath(prop)
value, err := accessField[any](resource, path...)
if errors.Is(err, ErrNotFound) {
value, err := unstructured.AccessField[any](resource, path...)
if errors.Is(err, unstructured.ErrNotFound) {
continue
}
if err != nil {
return nil, fmt.Errorf("failed to access selected property as %v: %w", path, err)
}
return value, nil
}
return nil, ErrNotFound
return nil, unstructured.ErrNotFound
}

func (km kubeMapping) setAtPropertySelectors(gvr string, unstructured map[string]any, target string, value any) (client.Object, error) {
func (km kubeMapping) setAtPropertySelectors(gvr string, obj map[string]any, target string, value any) (client.Object, error) {
for _, selector := range km.PropertySelectors {
prop := selector
if strings.HasSuffix(prop, ".#") {
targetPath := resolveXPath(target)
prop = fmt.Sprintf("%s.%s", prop[:len(prop)-2], base(targetPath))
prop = fmt.Sprintf("%s.%s", prop[:len(prop)-2], unstructured.Base(targetPath))
}
path := resolveXPath(prop)
if err := createField(unstructured, value, path...); err != nil {
if err := unstructured.CreateField(obj, value, path...); err != nil {
return nil, fmt.Errorf("failed to set value at %q: %w", path, err)
}
obj, err := initializedKubeObjectFor(gvr, unstructured)
obj, err := initializedKubeObjectFor(gvr, obj)
if err != nil {
return nil, fmt.Errorf("failed to initialize Kubernetes object: %w", err)
}
unstructuredCopy, err := toUnstructured(obj)
unstructuredCopy, err := unstructured.ToUnstructured(obj)
if err != nil {
return nil, fmt.Errorf("failed to read Kubernetes object contents: %w", err)
}
valueCopy, err := accessField[any](unstructuredCopy, path...)
valueCopy, err := unstructured.AccessField[any](unstructuredCopy, path...)
if reflect.DeepEqual(value, valueCopy) {
return obj, nil
}
if err != nil && !errors.Is(err, ErrNotFound) {
if err != nil && !errors.Is(err, unstructured.ErrNotFound) {
return nil, fmt.Errorf("failed to check Kubernetes object contents: %w", err)
}
}
return nil, ErrNotFound
return nil, unstructured.ErrNotFound
}

type openAPIMapping struct {
Expand All @@ -337,17 +338,17 @@ func (oam openAPIMapping) TargetPath() []string {

func resolveXPath(xpath string) []string {
if strings.HasPrefix(xpath, "$.") {
return asPath(xpath[1:])
return unstructured.AsPath(xpath[1:])
}
return asPath(xpath)
return unstructured.AsPath(xpath)
}

func unstructuredKubeObjectFor(gvr string) (map[string]any, error) {
objCopy, err := kubeObjectFor(gvr)
if err != nil {
return nil, fmt.Errorf("failed to get unstructured kube object for GVR %q: %w", gvr, err)
}
return toUnstructured(objCopy)
return unstructured.ToUnstructured(objCopy)
}

func kubeObjectFor(gvr string) (client.Object, error) {
Expand Down
Loading