From 2309a959273789c8368405d268bac32850fcffd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergen=20Yal=C3=A7=C4=B1n?= Date: Wed, 9 Aug 2023 17:12:26 +0200 Subject: [PATCH] Add some common utility functions to migration framework MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Sergen Yalçın --- pkg/migration/converter.go | 69 ++++++++++++++++++++++++++++++++++++++ pkg/migration/registry.go | 49 +++++++++++++++++++++++++++ 2 files changed, 118 insertions(+) diff --git a/pkg/migration/converter.go b/pkg/migration/converter.go index 6019060a..6d5cf7e7 100644 --- a/pkg/migration/converter.go +++ b/pkg/migration/converter.go @@ -15,6 +15,9 @@ package migration import ( + "fmt" + "strings" + "github.com/crossplane/crossplane-runtime/pkg/fieldpath" "github.com/crossplane/crossplane-runtime/pkg/resource" xpv1 "github.com/crossplane/crossplane/apis/apiextensions/v1" @@ -259,3 +262,69 @@ func toPackageLock(u unstructured.Unstructured) (*xppkgv1beta1.Lock, error) { } return lock, nil } + +func ConvertComposedTemplateTags(sourceTemplate xpv1.ComposedTemplate, value string, key string) ([]xpv1.Patch, error) { + var patchesToAdd []xpv1.Patch + for _, p := range sourceTemplate.Patches { + if p.ToFieldPath != nil { + if strings.HasPrefix(*p.ToFieldPath, "spec.forProvider.tags") { + u, err := FromRawExtension(sourceTemplate.Base) + if err != nil { + return nil, errors.Wrap(err, "failed to convert ComposedTemplate") + } + paved := fieldpath.Pave(u.Object) + key, err := paved.GetString(strings.ReplaceAll(*p.ToFieldPath, value, key)) + if err != nil { + return nil, errors.Wrap(err, "failed to get value from paved") + } + s := fmt.Sprintf(`spec.forProvider.tags["%s"]`, key) + patchesToAdd = append(patchesToAdd, xpv1.Patch{ + FromFieldPath: p.FromFieldPath, + ToFieldPath: &s, + Transforms: p.Transforms, + Policy: p.Policy, + }) + } + } + } + return patchesToAdd, nil +} + +func ConvertComposedTemplatePatchesMap(sourceTemplate xpv1.ComposedTemplate, conversionMap map[string]string) []xpv1.Patch { + var patchesToAdd []xpv1.Patch + for _, p := range sourceTemplate.Patches { + switch p.Type { // nolint:exhaustive + case xpv1.PatchTypeFromCompositeFieldPath, xpv1.PatchTypeCombineFromComposite, "": + { + if p.ToFieldPath != nil { + if to, ok := conversionMap[*p.ToFieldPath]; ok { + patchesToAdd = append(patchesToAdd, xpv1.Patch{ + Type: p.Type, + FromFieldPath: p.FromFieldPath, + ToFieldPath: &to, + Transforms: p.Transforms, + Policy: p.Policy, + Combine: p.Combine, + }) + } + } + } + case xpv1.PatchTypeToCompositeFieldPath, xpv1.PatchTypeCombineToComposite: + { + if p.FromFieldPath != nil { + if to, ok := conversionMap[*p.FromFieldPath]; ok { + patchesToAdd = append(patchesToAdd, xpv1.Patch{ + Type: p.Type, + FromFieldPath: &to, + ToFieldPath: p.ToFieldPath, + Transforms: p.Transforms, + Policy: p.Policy, + Combine: p.Combine, + }) + } + } + } + } + } + return patchesToAdd +} diff --git a/pkg/migration/registry.go b/pkg/migration/registry.go index 12a06d23..b716cd99 100644 --- a/pkg/migration/registry.go +++ b/pkg/migration/registry.go @@ -15,7 +15,9 @@ package migration import ( + "fmt" "regexp" + "strings" "github.com/crossplane/crossplane-runtime/pkg/resource" xpv1 "github.com/crossplane/crossplane/apis/apiextensions/v1" @@ -452,6 +454,35 @@ func (d *delegatingConverter) PatchSets(psMap map[string]*xpv1.PatchSet) error { return d.psFn(psMap) } +func DefaultPatchSetsConverter(sourcePatchSets map[string]*xpv1.PatchSet) error { + tagsPatchSetName := "" + for _, patchSet := range sourcePatchSets { + for _, patch := range patchSet.Patches { + if patch.ToFieldPath != nil { + if strings.HasPrefix(*patch.ToFieldPath, "spec.forProvider.tags") { + tagsPatchSetName = patchSet.Name + break + } + } + } + if tagsPatchSetName != "" { + break + } + } + + tPs := sourcePatchSets[tagsPatchSetName] + if tPs == nil { + return nil + } + for i, p := range tPs.Patches { + r := strings.NewReplacer("metadata.labels[", "", "]", "") + key := r.Replace(*p.FromFieldPath) + *tPs.Patches[i].ToFieldPath = fmt.Sprintf(`spec.forProvider.tags[%s]`, key) + } + // convert patch sets in the source + return nil +} + // Resource takes a managed resource and returns zero or more managed // resources to be created by calling the configured ResourceConversionFn. func (d *delegatingConverter) Resource(mg resource.Managed) ([]resource.Managed, error) { @@ -471,6 +502,24 @@ func (d *delegatingConverter) ComposedTemplate(sourceTemplate xpv1.ComposedTempl return d.cmpFn(sourceTemplate, convertedTemplates...) } +func DefaultCompositionConverter(convertTags bool, conversionMap map[string]string) ComposedTemplateConversionFn { + return func(sourceTemplate xpv1.ComposedTemplate, convertedTemplates ...*xpv1.ComposedTemplate) error { + var patchesToAdd []xpv1.Patch + var err error + if convertTags { + patchesToAdd, err = ConvertComposedTemplateTags(sourceTemplate, ".value", ".key") + if err != nil { + return errors.Wrap(err, "failed to convert tags") + } + } + patchesToAdd = append(patchesToAdd, ConvertComposedTemplatePatchesMap(sourceTemplate, conversionMap)...) + for i := range convertedTemplates { + convertedTemplates[i].Patches = append(convertedTemplates[i].Patches, patchesToAdd...) + } + return nil + } +} + // RegisterAPIConversionFunctions registers the supplied ResourceConversionFn and // ComposedTemplateConversionFn for the specified GVK, and the supplied // PatchSetsConversionFn for all the discovered Compositions.