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 1/3] 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. From 3d06353ddbbf0ff7232d8fc8c6386ef3528118b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergen=20Yal=C3=A7=C4=B1n?= Date: Thu, 10 Aug 2023 15:46:32 +0200 Subject: [PATCH 2/3] Move the provider specific functions to extensions-migration 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 | 31 +------------------------- pkg/migration/registry.go | 45 ++++++++------------------------------ 2 files changed, 10 insertions(+), 66 deletions(-) diff --git a/pkg/migration/converter.go b/pkg/migration/converter.go index 6d5cf7e7..914dfd14 100644 --- a/pkg/migration/converter.go +++ b/pkg/migration/converter.go @@ -15,9 +15,6 @@ 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" @@ -263,33 +260,7 @@ 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 -} - +// ConvertComposedTemplatePatchesMap converts the composed templates with given conversion map func ConvertComposedTemplatePatchesMap(sourceTemplate xpv1.ComposedTemplate, conversionMap map[string]string) []xpv1.Patch { var patchesToAdd []xpv1.Patch for _, p := range sourceTemplate.Patches { diff --git a/pkg/migration/registry.go b/pkg/migration/registry.go index b716cd99..c9994227 100644 --- a/pkg/migration/registry.go +++ b/pkg/migration/registry.go @@ -15,9 +15,7 @@ package migration import ( - "fmt" "regexp" - "strings" "github.com/crossplane/crossplane-runtime/pkg/resource" xpv1 "github.com/crossplane/crossplane/apis/apiextensions/v1" @@ -454,35 +452,6 @@ 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) { @@ -502,15 +471,19 @@ func (d *delegatingConverter) ComposedTemplate(sourceTemplate xpv1.ComposedTempl return d.cmpFn(sourceTemplate, convertedTemplates...) } -func DefaultCompositionConverter(convertTags bool, conversionMap map[string]string) ComposedTemplateConversionFn { +// DefaultCompositionConverter is a generic composition converter +// conversionMap: is fieldpath map for conversion +// Example: "spec.forProvider.assumeRolePolicyDocument": "spec.forProvider.assumeRolePolicy", +// fns are functions that manipulate the patchsets +func DefaultCompositionConverter(conversionMap map[string]string, fns ...func(sourceTemplate xpv1.ComposedTemplate) ([]xpv1.Patch, error)) 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") + for _, fn := range fns { + patches, err := fn(sourceTemplate) if err != nil { - return errors.Wrap(err, "failed to convert tags") + return errors.Wrap(err, "cannot run the patch sets converter function") } + patchesToAdd = append(patchesToAdd, patches...) } patchesToAdd = append(patchesToAdd, ConvertComposedTemplatePatchesMap(sourceTemplate, conversionMap)...) for i := range convertedTemplates { From 35498766927e3b6ae7a708c095d197302895eb02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergen=20Yal=C3=A7=C4=B1n?= Date: Tue, 15 Aug 2023 10:58:41 +0200 Subject: [PATCH 3/3] Add some details to the code comments 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 | 4 +++- pkg/migration/registry.go | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/pkg/migration/converter.go b/pkg/migration/converter.go index 914dfd14..c8f86bbd 100644 --- a/pkg/migration/converter.go +++ b/pkg/migration/converter.go @@ -260,7 +260,9 @@ func toPackageLock(u unstructured.Unstructured) (*xppkgv1beta1.Lock, error) { return lock, nil } -// ConvertComposedTemplatePatchesMap converts the composed templates with given conversion map +// ConvertComposedTemplatePatchesMap converts the composed templates with given conversionMap +// Key of the conversionMap points to the source field +// Value of the conversionMap points to the target field func ConvertComposedTemplatePatchesMap(sourceTemplate xpv1.ComposedTemplate, conversionMap map[string]string) []xpv1.Patch { var patchesToAdd []xpv1.Patch for _, p := range sourceTemplate.Patches { diff --git a/pkg/migration/registry.go b/pkg/migration/registry.go index c9994227..b88a7b27 100644 --- a/pkg/migration/registry.go +++ b/pkg/migration/registry.go @@ -473,6 +473,8 @@ func (d *delegatingConverter) ComposedTemplate(sourceTemplate xpv1.ComposedTempl // DefaultCompositionConverter is a generic composition converter // conversionMap: is fieldpath map for conversion +// Key of the conversionMap points to the source field +// Value of the conversionMap points to the target field // Example: "spec.forProvider.assumeRolePolicyDocument": "spec.forProvider.assumeRolePolicy", // fns are functions that manipulate the patchsets func DefaultCompositionConverter(conversionMap map[string]string, fns ...func(sourceTemplate xpv1.ComposedTemplate) ([]xpv1.Patch, error)) ComposedTemplateConversionFn {