From 677f052a3e9db95f608e78c123f11d12c73472ea Mon Sep 17 00:00:00 2001 From: Antoine Martin Date: Sun, 22 Jan 2023 11:20:45 +0000 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Allowing=20generators?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main.go | 113 ++++++++++-------- .../builtinplugintype_string.go | 2 +- .../tranformers.go => plugins/factories.go} | 52 +++++++- tests/functions2/01_configmap-generator.yaml | 12 ++ .../02_replacement-transformer.yaml | 29 +++++ tests/test_krmfnbuiltin.sh | 6 +- 6 files changed, 158 insertions(+), 56 deletions(-) rename pkg/{transformers => plugins}/builtinplugintype_string.go (98%) rename pkg/{transformers/tranformers.go => plugins/factories.go} (67%) create mode 100644 tests/functions2/01_configmap-generator.yaml create mode 100644 tests/functions2/02_replacement-transformer.yaml diff --git a/main.go b/main.go index 6a1d950..77bed10 100644 --- a/main.go +++ b/main.go @@ -4,18 +4,16 @@ import ( "fmt" "os" - "github.com/kaweezle/krmfnbuiltin/pkg/transformers" + "github.com/kaweezle/krmfnbuiltin/pkg/plugins" "sigs.k8s.io/kustomize/api/konfig" - fLdr "sigs.k8s.io/kustomize/api/loader" - "sigs.k8s.io/kustomize/api/provider" "sigs.k8s.io/kustomize/api/resmap" "sigs.k8s.io/kustomize/api/resource" - "sigs.k8s.io/kustomize/api/types" "sigs.k8s.io/kustomize/kyaml/errors" - "sigs.k8s.io/kustomize/kyaml/filesys" "sigs.k8s.io/kustomize/kyaml/fn/framework" "sigs.k8s.io/kustomize/kyaml/fn/framework/command" + "sigs.k8s.io/kustomize/kyaml/kio/filters" + "sigs.k8s.io/kustomize/kyaml/kio/kioutil" "sigs.k8s.io/kustomize/kyaml/resid" "sigs.k8s.io/kustomize/kyaml/yaml" ) @@ -43,34 +41,6 @@ var BuildAnnotations = []string{ BuildAnnotationsGenAddHashSuffix, } -func makeBuiltinPlugin(r resid.Gvk) (resmap.Configurable, error) { - bpt := transformers.GetBuiltinPluginType(r.Kind) - if f, ok := transformers.TransformerFactories[bpt]; ok { - return f(), nil - } - return nil, errors.Errorf("unable to load builtin %s", r) -} - -func NewPluginHelpers() (*resmap.PluginHelpers, error) { - depProvider := provider.NewDepProvider() - - fSys := filesys.MakeFsOnDisk() - path, err := os.Getwd() - if err != nil { - return nil, err - } - resmapFactory := resmap.NewFactory(depProvider.GetResourceFactory()) - - lr := fLdr.RestrictionNone - - ldr, err := fLdr.NewLoader(lr, path, fSys) - if err != nil { - return nil, err - } - - return resmap.NewPluginHelpers(ldr, depProvider.GetFieldValidator(), resmapFactory, types.DisabledPluginConfig()), nil -} - func RemoveBuildAnnotations(r *resource.Resource) { annotations := r.GetAnnotations() if len(annotations) == 0 { @@ -92,46 +62,83 @@ func main() { res := resource.Resource{RNode: *config} - plugin, err := makeBuiltinPlugin(resid.GvkFromNode(config)) + plugin, err := plugins.MakeBuiltinPlugin(resid.GvkFromNode(config)) if err != nil { return errors.WrapPrefixf(err, "creating plugin") } yamlNode := config.YNode() - yaml, err := yaml.Marshal(yamlNode) + yamlBytes, err := yaml.Marshal(yamlNode) if err != nil { return errors.WrapPrefixf(err, "marshalling yaml from res %s", res.OrgId()) } - helpers, err := NewPluginHelpers() + helpers, err := plugins.NewPluginHelpers() if err != nil { return errors.WrapPrefixf(err, "Cannot build Plugin helpers") } - err = plugin.Config(helpers, yaml) + err = plugin.Config(helpers, yamlBytes) if err != nil { return errors.WrapPrefixf( err, "plugin %s fails configuration", res.OrgId()) } transformer, ok := plugin.(resmap.Transformer) - if !ok { - return fmt.Errorf("plugin %s not a transformer", res.OrgId()) - } + if ok { + rm, err := helpers.ResmapFactory().NewResMapFromRNodeSlice(rl.Items) + if err != nil { + return errors.WrapPrefixf(err, "getting resource maps") + } + err = transformer.Transform(rm) + if err != nil { + return errors.WrapPrefixf(err, "Transforming resources") + } + + for _, r := range rm.Resources() { + RemoveBuildAnnotations(r) + } + + rl.Items = rm.ToRNodeSlice() + + // kustomize fn don't remove config.kubernetes.io/local-config resources upon completion. + // As it always add a filename by default, the local resources keep saved. + // To avoid this, an annotation `config.kubernetes.io/prune-local` present in a + // transformer makes all the local resources disappear. + if _, ok := config.GetAnnotations()["config.kubernetes.io/prune-local"]; ok { + filter := &filters.IsLocalConfig{IncludeLocalConfig: false, ExcludeNonLocalConfig: false} + err = rl.Filter(filter) + if err != nil { + return errors.WrapPrefixf(err, "filtering local configs") + } + } + + } else { + generator, ok := plugin.(resmap.Generator) + + if !ok { + return fmt.Errorf("plugin %s is neither a generator nor a transformer", res.OrgId()) + } + + rm, err := generator.Generate() + if err != nil { + return errors.WrapPrefixf(err, "generating resource(s)") + } + + for _, r := range rm.Resources() { + r.RemoveBuildAnnotations() + // We add the annotation config.kubernetes.io/local-config to be able to delete + // The generated resource at the end of the process. Unfortunately, kustomize doesn't + // do that on functions. So we have added a special annotation + // `config.kubernetes.io/prune-local` to add on the last transformer. + // We set the filename of the generated resource in case it is forgotten. + r.Pipe(yaml.SetAnnotation(filters.LocalConfigAnnotation, "true")) + r.Pipe(yaml.SetAnnotation(kioutil.PathAnnotation, ".generated.yaml")) + r.Pipe(yaml.SetAnnotation(kioutil.LegacyPathAnnotation, ".generated.yaml")) + } + + rl.Items = append(rl.Items, rm.ToRNodeSlice()...) - rm, err := helpers.ResmapFactory().NewResMapFromRNodeSlice(rl.Items) - if err != nil { - return errors.WrapPrefixf(err, "getting resource maps") } - err = transformer.Transform(rm) - if err != nil { - return errors.WrapPrefixf(err, "Transforming resources") - } - - for _, r := range rm.Resources() { - RemoveBuildAnnotations(r) - } - - rl.Items = rm.ToRNodeSlice() return nil diff --git a/pkg/transformers/builtinplugintype_string.go b/pkg/plugins/builtinplugintype_string.go similarity index 98% rename from pkg/transformers/builtinplugintype_string.go rename to pkg/plugins/builtinplugintype_string.go index d22f907..36785e3 100644 --- a/pkg/transformers/builtinplugintype_string.go +++ b/pkg/plugins/builtinplugintype_string.go @@ -1,6 +1,6 @@ // Code generated by "stringer -type=BuiltinPluginType"; DO NOT EDIT. -package transformers +package plugins import "strconv" diff --git a/pkg/transformers/tranformers.go b/pkg/plugins/factories.go similarity index 67% rename from pkg/transformers/tranformers.go rename to pkg/plugins/factories.go index c09b4fe..fc0ba94 100644 --- a/pkg/transformers/tranformers.go +++ b/pkg/plugins/factories.go @@ -1,8 +1,16 @@ -package transformers +package plugins import ( + "os" + "sigs.k8s.io/kustomize/api/builtins" + "sigs.k8s.io/kustomize/api/filesys" + fLdr "sigs.k8s.io/kustomize/api/loader" + "sigs.k8s.io/kustomize/api/provider" "sigs.k8s.io/kustomize/api/resmap" + "sigs.k8s.io/kustomize/api/types" + "sigs.k8s.io/kustomize/kyaml/errors" + "sigs.k8s.io/kustomize/kyaml/resid" ) //go:generate go run golang.org/x/tools/cmd/stringer -type=BuiltinPluginType @@ -41,6 +49,9 @@ func makeStringToBuiltinPluginTypeMap() (result map[string]BuiltinPluginType) { for k := range TransformerFactories { result[k.String()] = k } + for k := range GeneratorFactories { + result[k.String()] = k + } return } @@ -100,3 +111,42 @@ var TransformerFactories = map[BuiltinPluginType]func() resmap.TransformerPlugin // We only want it to be available in the top-level kustomization. // See: https://github.com/kubernetes-sigs/kustomize/issues/3913 } + +var GeneratorFactories = map[BuiltinPluginType]func() resmap.GeneratorPlugin{ + ConfigMapGenerator: builtins.NewConfigMapGeneratorPlugin, + IAMPolicyGenerator: builtins.NewIAMPolicyGeneratorPlugin, + SecretGenerator: builtins.NewSecretGeneratorPlugin, + HelmChartInflationGenerator: builtins.NewHelmChartInflationGeneratorPlugin, +} + +func MakeBuiltinPlugin(r resid.Gvk) (resmap.Configurable, error) { + bpt := GetBuiltinPluginType(r.Kind) + if f, ok := TransformerFactories[bpt]; ok { + return f(), nil + } + if f, ok := GeneratorFactories[bpt]; ok { + return f(), nil + } + return nil, errors.Errorf("unable to load builtin %s", r) +} + +func NewPluginHelpers() (*resmap.PluginHelpers, error) { + depProvider := provider.NewDepProvider() + + fSys := filesys.MakeFsOnDisk() + path, err := os.Getwd() + if err != nil { + return nil, err + } + resmapFactory := resmap.NewFactory(depProvider.GetResourceFactory()) + resmapFactory.RF().IncludeLocalConfigs = true + + lr := fLdr.RestrictionNone + + ldr, err := fLdr.NewLoader(lr, path, fSys) + if err != nil { + return nil, err + } + + return resmap.NewPluginHelpers(ldr, depProvider.GetFieldValidator(), resmapFactory, types.DisabledPluginConfig()), nil +} diff --git a/tests/functions2/01_configmap-generator.yaml b/tests/functions2/01_configmap-generator.yaml new file mode 100644 index 0000000..2e5359f --- /dev/null +++ b/tests/functions2/01_configmap-generator.yaml @@ -0,0 +1,12 @@ +apiVersion: builtin +kind: ConfigMapGenerator +metadata: + name: configuration-map + namespace: argocd + annotations: + config.kubernetes.io/function: | + exec: + path: ../krmfnbuiltin +literals: + - repoURL=https://github.com/antoinemartin/autocloud.git + - targetRevision=deploy/citest diff --git a/tests/functions2/02_replacement-transformer.yaml b/tests/functions2/02_replacement-transformer.yaml new file mode 100644 index 0000000..b7e5768 --- /dev/null +++ b/tests/functions2/02_replacement-transformer.yaml @@ -0,0 +1,29 @@ +apiVersion: builtin +kind: ReplacementTransformer +metadata: + name: replacement-transformer + namespace: argocd + annotations: + config.kubernetes.io/prune-local: "true" + config.kubernetes.io/function: | + exec: + path: ../krmfnbuiltin +replacements: + - source: + kind: ConfigMap + fieldPath: data.repoURL + targets: + - select: + kind: Application + annotationSelector: "autocloud/local=true" + fieldPaths: + - spec.source.repoURL + - source: + kind: ConfigMap + fieldPath: data.targetRevision + targets: + - select: + kind: Application + annotationSelector: "autocloud/local=true" + fieldPaths: + - spec.source.targetRevision diff --git a/tests/test_krmfnbuiltin.sh b/tests/test_krmfnbuiltin.sh index f433a55..969731d 100755 --- a/tests/test_krmfnbuiltin.sh +++ b/tests/test_krmfnbuiltin.sh @@ -11,7 +11,11 @@ set -e pipefail trap "cp compare/argocd.original.yaml applications/argocd.yaml" EXIT -echo "Running kustomize with transformer..." +echo "Running kustomize with patch transformer..." kustomize fn run --enable-exec --fn-path functions applications diff <(yq eval -P compare/argocd.expected.yaml) <(yq eval -P applications/argocd.yaml) +cp compare/argocd.original.yaml applications/argocd.yaml +echo "Running kustomize with replacement transformer..." +kustomize fn run --enable-exec --fn-path functions2 applications +diff <(yq eval -P compare/argocd.expected.yaml) <(yq eval -P applications/argocd.yaml) echo "Done ok 🎉"