From 3966b8eb8588144c1c896dbb3e336ffcd102e8f2 Mon Sep 17 00:00:00 2001 From: rishabh625 Date: Mon, 4 Jul 2022 22:07:06 +0530 Subject: [PATCH 1/2] feat: Go template with sprig for application template render in applicationset Signed-off-by: rishabh625 --- .../controllers/applicationset_controller.go | 12 +- .../applicationset_controller_test.go | 34 +-- .../generators/generator_spec_processor.go | 10 +- applicationset/utils/templating.go | 159 +++++++++++ applicationset/utils/utils.go | 48 ---- applicationset/utils/utils_test.go | 260 ------------------ go.mod | 7 +- go.sum | 13 +- manifests/core-install.yaml | 2 + manifests/crds/applicationset-crd.yaml | 2 + manifests/ha/install.yaml | 2 + manifests/install.yaml | 2 + .../v1alpha1/applicationset_types.go | 10 +- .../v1alpha1/zz_generated.deepcopy.go | 11 +- test/e2e/applicationset_test.go | 16 +- test/e2e/cluster_generator_test.go | 8 +- test/e2e/clusterdecisiongenerator_e2e_test.go | 8 +- test/e2e/matrix_e2e_test.go | 4 +- test/e2e/merge_e2e_test.go | 4 +- 19 files changed, 255 insertions(+), 357 deletions(-) create mode 100644 applicationset/utils/templating.go diff --git a/applicationset/controllers/applicationset_controller.go b/applicationset/controllers/applicationset_controller.go index a14148a5820a2..aba700901919d 100644 --- a/applicationset/controllers/applicationset_controller.go +++ b/applicationset/controllers/applicationset_controller.go @@ -429,8 +429,16 @@ func (r *ApplicationSetReconciler) generateApplications(applicationSetInfo argop var firstError error var applicationSetReason argoprojiov1alpha1.ApplicationSetReasonType + if (applicationSetInfo.Spec.Template == nil && applicationSetInfo.Spec.UntypedTemplate == nil) || + (applicationSetInfo.Spec.Template != nil && applicationSetInfo.Spec.UntypedTemplate != nil) { + firstError = fmt.Errorf("application set spec should have either template or untypedTemplate defined") + applicationSetReason = argoprojiov1alpha1.ApplicationSetReasonErrorOccurred + + return res, applicationSetReason, firstError + } + for _, requestedGenerator := range applicationSetInfo.Spec.Generators { - t, err := generators.Transform(requestedGenerator, r.Generators, applicationSetInfo.Spec.Template, &applicationSetInfo, map[string]string{}) + t, err := generators.Transform(requestedGenerator, r.Generators, *applicationSetInfo.Spec.Template, &applicationSetInfo, map[string]string{}) if err != nil { log.WithError(err).WithField("generator", requestedGenerator). Error("error generating application from params") @@ -445,7 +453,7 @@ func (r *ApplicationSetReconciler) generateApplications(applicationSetInfo argop tmplApplication := getTempApplication(a.Template) for _, p := range a.Params { - app, err := r.Renderer.RenderTemplateParams(tmplApplication, applicationSetInfo.Spec.SyncPolicy, p) + app, err := r.Renderer.RenderTemplateParams(tmplApplication, applicationSetInfo.Spec.UntypedTemplate, applicationSetInfo.Spec.SyncPolicy, p) if err != nil { log.WithError(err).WithField("params", a.Params).WithField("generator", requestedGenerator). Error("error generating application from params") diff --git a/applicationset/controllers/applicationset_controller_test.go b/applicationset/controllers/applicationset_controller_test.go index 1d4f152ae8d5c..7a61352fdfc66 100644 --- a/applicationset/controllers/applicationset_controller_test.go +++ b/applicationset/controllers/applicationset_controller_test.go @@ -61,7 +61,7 @@ func (g *generatorMock) GetRequeueAfter(appSetGenerator *argoprojiov1alpha1.Appl return args.Get(0).(time.Duration) } -func (r *rendererMock) RenderTemplateParams(tmpl *argov1alpha1.Application, syncPolicy *argoprojiov1alpha1.ApplicationSetSyncPolicy, params map[string]string) (*argov1alpha1.Application, error) { +func (r *rendererMock) RenderTemplateParams(tmpl *argov1alpha1.Application, untypedTemplate *argoprojiov1alpha1.ApplicationSetUntypedTemplate, syncPolicy *argoprojiov1alpha1.ApplicationSetSyncPolicy, params map[string]string) (*argov1alpha1.Application, error) { args := r.Called(tmpl, params) if args.Error(1) != nil { @@ -189,7 +189,7 @@ func TestExtractApplications(t *testing.T) { }, Spec: argoprojiov1alpha1.ApplicationSetSpec{ Generators: []argoprojiov1alpha1.ApplicationSetGenerator{generator}, - Template: cc.template, + Template: &cc.template, }, }) @@ -302,7 +302,7 @@ func TestMergeTemplateApplications(t *testing.T) { }, Spec: argoprojiov1alpha1.ApplicationSetSpec{ Generators: []argoprojiov1alpha1.ApplicationSetGenerator{generator}, - Template: cc.template, + Template: &cc.template, }, }, ) @@ -372,7 +372,7 @@ func TestCreateOrUpdateInCluster(t *testing.T) { Namespace: "namespace", }, Spec: argoprojiov1alpha1.ApplicationSetSpec{ - Template: argoprojiov1alpha1.ApplicationSetTemplate{ + Template: &argoprojiov1alpha1.ApplicationSetTemplate{ Spec: argov1alpha1.ApplicationSpec{ Project: "project", }, @@ -430,7 +430,7 @@ func TestCreateOrUpdateInCluster(t *testing.T) { Namespace: "namespace", }, Spec: argoprojiov1alpha1.ApplicationSetSpec{ - Template: argoprojiov1alpha1.ApplicationSetTemplate{ + Template: &argoprojiov1alpha1.ApplicationSetTemplate{ Spec: argov1alpha1.ApplicationSpec{ Project: "project", }, @@ -488,7 +488,7 @@ func TestCreateOrUpdateInCluster(t *testing.T) { Namespace: "namespace", }, Spec: argoprojiov1alpha1.ApplicationSetSpec{ - Template: argoprojiov1alpha1.ApplicationSetTemplate{ + Template: &argoprojiov1alpha1.ApplicationSetTemplate{ Spec: argov1alpha1.ApplicationSpec{ Project: "project", }, @@ -550,7 +550,7 @@ func TestCreateOrUpdateInCluster(t *testing.T) { Namespace: "namespace", }, Spec: argoprojiov1alpha1.ApplicationSetSpec{ - Template: argoprojiov1alpha1.ApplicationSetTemplate{ + Template: &argoprojiov1alpha1.ApplicationSetTemplate{ Spec: argov1alpha1.ApplicationSpec{ Project: "project", }, @@ -610,7 +610,7 @@ func TestCreateOrUpdateInCluster(t *testing.T) { Namespace: "namespace", }, Spec: argoprojiov1alpha1.ApplicationSetSpec{ - Template: argoprojiov1alpha1.ApplicationSetTemplate{ + Template: &argoprojiov1alpha1.ApplicationSetTemplate{ Spec: argov1alpha1.ApplicationSpec{ Project: "project", }, @@ -682,7 +682,7 @@ func TestCreateOrUpdateInCluster(t *testing.T) { Namespace: "namespace", }, Spec: argoprojiov1alpha1.ApplicationSetSpec{ - Template: argoprojiov1alpha1.ApplicationSetTemplate{ + Template: &argoprojiov1alpha1.ApplicationSetTemplate{ Spec: argov1alpha1.ApplicationSpec{ Project: "project", Source: argov1alpha1.ApplicationSource{Path: "path", TargetRevision: "revision", RepoURL: "repoURL"}, @@ -762,7 +762,7 @@ func TestCreateOrUpdateInCluster(t *testing.T) { Namespace: "namespace", }, Spec: argoprojiov1alpha1.ApplicationSetSpec{ - Template: argoprojiov1alpha1.ApplicationSetTemplate{ + Template: &argoprojiov1alpha1.ApplicationSetTemplate{ Spec: argov1alpha1.ApplicationSpec{ Project: "project", }, @@ -902,7 +902,7 @@ func TestRemoveFinalizerOnInvalidDestination_FinalizerTypes(t *testing.T) { Namespace: "namespace", }, Spec: argoprojiov1alpha1.ApplicationSetSpec{ - Template: argoprojiov1alpha1.ApplicationSetTemplate{ + Template: &argoprojiov1alpha1.ApplicationSetTemplate{ Spec: argov1alpha1.ApplicationSpec{ Project: "project", }, @@ -1064,7 +1064,7 @@ func TestRemoveFinalizerOnInvalidDestination_DestinationTypes(t *testing.T) { Namespace: "namespace", }, Spec: argoprojiov1alpha1.ApplicationSetSpec{ - Template: argoprojiov1alpha1.ApplicationSetTemplate{ + Template: &argoprojiov1alpha1.ApplicationSetTemplate{ Spec: argov1alpha1.ApplicationSpec{ Project: "project", }, @@ -1192,7 +1192,7 @@ func TestCreateApplications(t *testing.T) { Namespace: "namespace", }, Spec: argoprojiov1alpha1.ApplicationSetSpec{ - Template: argoprojiov1alpha1.ApplicationSetTemplate{ + Template: &argoprojiov1alpha1.ApplicationSetTemplate{ Spec: argov1alpha1.ApplicationSpec{ Project: "project", }, @@ -1249,7 +1249,7 @@ func TestCreateApplications(t *testing.T) { Namespace: "namespace", }, Spec: argoprojiov1alpha1.ApplicationSetSpec{ - Template: argoprojiov1alpha1.ApplicationSetTemplate{ + Template: &argoprojiov1alpha1.ApplicationSetTemplate{ Spec: argov1alpha1.ApplicationSpec{ Project: "project", }, @@ -1361,7 +1361,7 @@ func TestDeleteInCluster(t *testing.T) { Namespace: "namespace", }, Spec: argoprojiov1alpha1.ApplicationSetSpec{ - Template: argoprojiov1alpha1.ApplicationSetTemplate{ + Template: &argoprojiov1alpha1.ApplicationSetTemplate{ Spec: argov1alpha1.ApplicationSpec{ Project: "project", }, @@ -1803,7 +1803,7 @@ func TestReconcilerValidationErrorBehaviour(t *testing.T) { }, }, }, - Template: argoprojiov1alpha1.ApplicationSetTemplate{ + Template: &argoprojiov1alpha1.ApplicationSetTemplate{ ApplicationSetTemplateMeta: argoprojiov1alpha1.ApplicationSetTemplateMeta{ Name: "{{cluster}}", Namespace: "argocd", @@ -1889,7 +1889,7 @@ func TestSetApplicationSetStatusCondition(t *testing.T) { }}, }}, }, - Template: argoprojiov1alpha1.ApplicationSetTemplate{}, + Template: &argoprojiov1alpha1.ApplicationSetTemplate{}, }, } diff --git a/applicationset/generators/generator_spec_processor.go b/applicationset/generators/generator_spec_processor.go index 634dc69895db3..ec85545f035ff 100644 --- a/applicationset/generators/generator_spec_processor.go +++ b/applicationset/generators/generator_spec_processor.go @@ -2,9 +2,10 @@ package generators import ( "encoding/json" + "reflect" + "github.com/argoproj/argo-cd/v2/applicationset/utils" "github.com/valyala/fasttemplate" - "reflect" argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/applicationset/v1alpha1" "github.com/imdario/mergo" @@ -90,8 +91,13 @@ func mergeGeneratorTemplate(g Generator, requestedGenerator *argoprojiov1alpha1. // the provided parameter (which will touch the original resource object returned by client-go) dest := g.GetTemplate(requestedGenerator).DeepCopy() - err := mergo.Merge(dest, applicationSetTemplate) + var err error + if &applicationSetTemplate != nil { + err = mergo.Merge(dest, &applicationSetTemplate) + } else { + log.Warn("generator template won't be applied when standard application template is not used") + } return *dest, err } diff --git a/applicationset/utils/templating.go b/applicationset/utils/templating.go new file mode 100644 index 0000000000000..4e0e0a5d524b5 --- /dev/null +++ b/applicationset/utils/templating.go @@ -0,0 +1,159 @@ +package utils + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "strconv" + "strings" + "text/template" + + "github.com/Masterminds/sprig/v3" + argov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" + argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/applicationset/v1alpha1" + "github.com/valyala/fasttemplate" + "sigs.k8s.io/yaml" +) + +type Renderer interface { + RenderTemplateParams(tmpl *argov1alpha1.Application, untypedTemplate *argoprojiov1alpha1.ApplicationSetUntypedTemplate, syncPolicy *argoprojiov1alpha1.ApplicationSetSyncPolicy, params map[string]string) (*argov1alpha1.Application, error) +} +type Render struct { +} + +func (r *Render) RenderTemplateParams(tmpl *argov1alpha1.Application, untypedTemplate *argoprojiov1alpha1.ApplicationSetUntypedTemplate, syncPolicy *argoprojiov1alpha1.ApplicationSetSyncPolicy, params map[string]string) (*argov1alpha1.Application, error) { + if tmpl == nil { + return nil, fmt.Errorf("application template is empty ") + } + if len(params) == 0 { + return tmpl, nil + } + var replacedTmpl argov1alpha1.Application + var replacedTmplStr string + if untypedTemplate == nil { + // interpolates the `${expression}` first and simple `{reference}` right after + tmplBytes, err := json.Marshal(tmpl) + if err != nil { + return nil, err + } + replacedTmplStr, err = renderWithFastTemplateAndGoTemplate(string(tmplBytes), params) + if err != nil { + return nil, err + } + replacedTmplStr = renderWithFastTemplate(replacedTmplStr, params) + if err != nil { + return nil, err + } + err = json.Unmarshal([]byte(replacedTmplStr), &replacedTmpl) + if err != nil { + return nil, err + } + } else { + replacedTmplStr, err := renderWithGoTemplate(string(*untypedTemplate), params) + if err != nil { + return nil, err + } + // UnmarshalStrict to fail early and raise the fact that template + // result produced not what is expected + err = yaml.UnmarshalStrict([]byte(replacedTmplStr), &replacedTmpl) + if err != nil { + return nil, err + } + } + // Add the 'resources-finalizer' finalizer if: + // The template application doesn't have any finalizers, and: + // a) there is no syncPolicy, or + // b) there IS a syncPolicy, but preserveResourcesOnDeletion is set to false + // See TestRenderTemplateParamsFinalizers in util_test.go for test-based definition of behaviour + if (syncPolicy == nil || !syncPolicy.PreserveResourcesOnDeletion) && + (replacedTmpl.ObjectMeta.Finalizers == nil || len(replacedTmpl.ObjectMeta.Finalizers) == 0) { + replacedTmpl.ObjectMeta.Finalizers = []string{"resources-finalizer.argocd.argoproj.io"} + } + return &replacedTmpl, nil +} + +// renderWithGoTemplate executes gotemplate with sprig functions against the raw (untyped) template +func renderWithGoTemplate(rawTemplate string, data map[string]string) (string, error) { + goTemplate, err := template.New("").Option("missingkey=zero").Funcs(createFuncMap()).Parse(rawTemplate) + if err != nil { + return "", err + } + var tplString bytes.Buffer + err = goTemplate.Execute(&tplString, data) + if err != nil { + return "", err + } + return tplString.String(), nil +} + +// renderWithFastTemplateAndGoTemplate executes string substitution with the result of gotemplate run +// for every token found +func renderWithFastTemplateAndGoTemplate(rawTemplate string, data map[string]string) (string, error) { + fstTmpl := fasttemplate.New(rawTemplate, "${{", "}}") + replacedTmplStr, err := fstTmpl.ExecuteFuncStringWithErr(func(w io.Writer, tag string) (int, error) { + trimmedTag := strings.TrimSpace(tag) + // json control characters here are double escaped, what was a double quote " becomes \" when + // unmarshalled to ApplicationSet and then \\\" when marshaled to json + // this becomes a problem with gotemplate trying to parse the token, so unquote the string + unquotedTag, err := strconv.Unquote(`"` + trimmedTag + `"`) + if err != nil { + return 0, err + } + // wrapping back in {{}} for gotemplate to identify the expression + gotemplateTag := fmt.Sprintf("{{%s}}", unquotedTag) + goTemplate, err := template.New("").Option("missingkey=zero").Funcs(createFuncMap()).Parse(gotemplateTag) + if err != nil { + return 0, err + } + var tplString bytes.Buffer + err = goTemplate.Execute(&tplString, data) + if err != nil { + return 0, err + } + // The following escapes any special characters (e.g. newlines, tabs, etc...) + // in preparation for substitution + replacement := strconv.Quote(tplString.String()) + replacement = replacement[1 : len(replacement)-1] + return w.Write([]byte(replacement)) + }) + if err != nil { + return "", err + } + return replacedTmplStr, nil +} + +// replaceWithFastTemplate executes basic string substitution of a template with replacement values. +func renderWithFastTemplate(rawTemplate string, data map[string]string) string { + fstTmpl := fasttemplate.New(rawTemplate, "{{", "}}") + replacedTmplStr := fstTmpl.ExecuteFuncString(func(w io.Writer, tag string) (int, error) { + trimmedTag := strings.TrimSpace(tag) + replacement, ok := data[trimmedTag] + if len(trimmedTag) == 0 || !ok { + return w.Write([]byte(fmt.Sprintf("{{%s}}", tag))) + } + // The following escapes any special characters (e.g. newlines, tabs, etc...) + // in preparation for substitution + replacement = strconv.Quote(replacement) + replacement = replacement[1 : len(replacement)-1] + return w.Write([]byte(replacement)) + }) + return replacedTmplStr +} +func ToYaml(v interface{}) (string, error) { + data, err := yaml.Marshal(v) + if err != nil { + return "", err + } + return string(data), nil +} +func createFuncMap() template.FuncMap { + funcMap := sprig.TxtFuncMap() + extraFuncMap := template.FuncMap{ + "toYaml": ToYaml, + } + for name, f := range extraFuncMap { + funcMap[name] = f + } + return funcMap +} diff --git a/applicationset/utils/utils.go b/applicationset/utils/utils.go index b2b1445022776..70eb70b912b56 100644 --- a/applicationset/utils/utils.go +++ b/applicationset/utils/utils.go @@ -12,57 +12,9 @@ import ( log "github.com/sirupsen/logrus" "github.com/valyala/fasttemplate" - argoappsv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" argoappsetv1 "github.com/argoproj/argo-cd/v2/pkg/apis/applicationset/v1alpha1" ) -type Renderer interface { - RenderTemplateParams(tmpl *argoappsv1.Application, syncPolicy *argoappsetv1.ApplicationSetSyncPolicy, params map[string]string) (*argoappsv1.Application, error) -} - -type Render struct { -} - -func (r *Render) RenderTemplateParams(tmpl *argoappsv1.Application, syncPolicy *argoappsetv1.ApplicationSetSyncPolicy, params map[string]string) (*argoappsv1.Application, error) { - if tmpl == nil { - return nil, fmt.Errorf("application template is empty ") - } - - if len(params) == 0 { - return tmpl, nil - } - - tmplBytes, err := json.Marshal(tmpl) - if err != nil { - return nil, err - } - - fstTmpl := fasttemplate.New(string(tmplBytes), "{{", "}}") - replacedTmplStr, err := r.Replace(fstTmpl, params, true) - if err != nil { - return nil, err - } - - var replacedTmpl argoappsv1.Application - err = json.Unmarshal([]byte(replacedTmplStr), &replacedTmpl) - if err != nil { - return nil, err - } - - // Add the 'resources-finalizer' finalizer if: - // The template application doesn't have any finalizers, and: - // a) there is no syncPolicy, or - // b) there IS a syncPolicy, but preserveResourcesOnDeletion is set to false - // See TestRenderTemplateParamsFinalizers in util_test.go for test-based definition of behaviour - if (syncPolicy == nil || !syncPolicy.PreserveResourcesOnDeletion) && - (replacedTmpl.ObjectMeta.Finalizers == nil || len(replacedTmpl.ObjectMeta.Finalizers) == 0) { - - replacedTmpl.ObjectMeta.Finalizers = []string{"resources-finalizer.argocd.argoproj.io"} - } - - return &replacedTmpl, nil -} - // Replace executes basic string substitution of a template with replacement values. // 'allowUnresolved' indicates whether it is acceptable to have unresolved variables // remaining in the substituted template. diff --git a/applicationset/utils/utils_test.go b/applicationset/utils/utils_test.go index 5dc9a477a7a6c..97cbc9759697b 100644 --- a/applicationset/utils/utils_test.go +++ b/applicationset/utils/utils_test.go @@ -13,266 +13,6 @@ import ( argoappsetv1 "github.com/argoproj/argo-cd/v2/pkg/apis/applicationset/v1alpha1" ) -func TestRenderTemplateParams(t *testing.T) { - - // Believe it or not, this is actually less complex than the equivalent solution using reflection - fieldMap := map[string]func(app *argoappsv1.Application) *string{} - fieldMap["Path"] = func(app *argoappsv1.Application) *string { return &app.Spec.Source.Path } - fieldMap["RepoURL"] = func(app *argoappsv1.Application) *string { return &app.Spec.Source.RepoURL } - fieldMap["TargetRevision"] = func(app *argoappsv1.Application) *string { return &app.Spec.Source.TargetRevision } - fieldMap["Chart"] = func(app *argoappsv1.Application) *string { return &app.Spec.Source.Chart } - - fieldMap["Server"] = func(app *argoappsv1.Application) *string { return &app.Spec.Destination.Server } - fieldMap["Namespace"] = func(app *argoappsv1.Application) *string { return &app.Spec.Destination.Namespace } - fieldMap["Name"] = func(app *argoappsv1.Application) *string { return &app.Spec.Destination.Name } - - fieldMap["Project"] = func(app *argoappsv1.Application) *string { return &app.Spec.Project } - - emptyApplication := &argoappsv1.Application{ - Spec: argoappsv1.ApplicationSpec{ - Source: argoappsv1.ApplicationSource{ - Path: "", - RepoURL: "", - TargetRevision: "", - Chart: "", - }, - Destination: argoappsv1.ApplicationDestination{ - Server: "", - Namespace: "", - Name: "", - }, - Project: "", - }, - } - - tests := []struct { - name string - fieldVal string - params map[string]string - expectedVal string - }{ - { - name: "simple substitution", - fieldVal: "{{one}}", - expectedVal: "two", - params: map[string]string{ - "one": "two", - }, - }, - { - name: "simple substitution with whitespace", - fieldVal: "{{ one }}", - expectedVal: "two", - params: map[string]string{ - "one": "two", - }, - }, - - { - name: "template characters but not in a template", - fieldVal: "}} {{", - expectedVal: "}} {{", - params: map[string]string{ - "one": "two", - }, - }, - - { - name: "nested template", - fieldVal: "{{ }}", - expectedVal: "{{ }}", - params: map[string]string{ - "one": "{{ }}", - }, - }, - { - name: "field with whitespace", - fieldVal: "{{ }}", - expectedVal: "{{ }}", - params: map[string]string{ - " ": "two", - "": "three", - }, - }, - - { - name: "template contains itself, containing itself", - fieldVal: "{{one}}", - expectedVal: "{{one}}", - params: map[string]string{ - "{{one}}": "{{one}}", - }, - }, - - { - name: "template contains itself, containing something else", - fieldVal: "{{one}}", - expectedVal: "{{one}}", - params: map[string]string{ - "{{one}}": "{{two}}", - }, - }, - - { - name: "templates are case sensitive", - fieldVal: "{{ONE}}", - expectedVal: "{{ONE}}", - params: map[string]string{ - "{{one}}": "two", - }, - }, - { - name: "multiple on a line", - fieldVal: "{{one}}{{one}}", - expectedVal: "twotwo", - params: map[string]string{ - "one": "two", - }, - }, - { - name: "multiple different on a line", - fieldVal: "{{one}}{{three}}", - expectedVal: "twofour", - params: map[string]string{ - "one": "two", - "three": "four", - }, - }, - } - - for _, test := range tests { - - t.Run(test.name, func(t *testing.T) { - - for fieldName, getPtrFunc := range fieldMap { - - // Clone the template application - application := emptyApplication.DeepCopy() - - // Set the value of the target field, to the test value - *getPtrFunc(application) = test.fieldVal - - // Render the cloned application, into a new application - render := Render{} - newApplication, err := render.RenderTemplateParams(application, nil, test.params) - - // Retrieve the value of the target field from the newApplication, then verify that - // the target field has been templated into the expected value - actualValue := *getPtrFunc(newApplication) - assert.Equal(t, test.expectedVal, actualValue, "Field '%s' had an unexpected value. expected: '%s' value: '%s'", fieldName, test.expectedVal, actualValue) - assert.NoError(t, err) - - } - }) - } - -} - -func TestRenderTemplateParamsFinalizers(t *testing.T) { - - emptyApplication := &argoappsv1.Application{ - Spec: argoappsv1.ApplicationSpec{ - Source: argoappsv1.ApplicationSource{ - Path: "", - RepoURL: "", - TargetRevision: "", - Chart: "", - }, - Destination: argoappsv1.ApplicationDestination{ - Server: "", - Namespace: "", - Name: "", - }, - Project: "", - }, - } - - for _, c := range []struct { - testName string - syncPolicy *argoappsetv1.ApplicationSetSyncPolicy - existingFinalizers []string - expectedFinalizers []string - }{ - { - testName: "existing finalizer should be preserved", - existingFinalizers: []string{"existing-finalizer"}, - syncPolicy: nil, - expectedFinalizers: []string{"existing-finalizer"}, - }, - { - testName: "background finalizer should be preserved", - existingFinalizers: []string{"resources-finalizer.argocd.argoproj.io/background"}, - syncPolicy: nil, - expectedFinalizers: []string{"resources-finalizer.argocd.argoproj.io/background"}, - }, - - { - testName: "empty finalizer and empty sync should use standard finalizer", - existingFinalizers: nil, - syncPolicy: nil, - expectedFinalizers: []string{"resources-finalizer.argocd.argoproj.io"}, - }, - - { - testName: "standard finalizer should be preserved", - existingFinalizers: []string{"resources-finalizer.argocd.argoproj.io"}, - syncPolicy: nil, - expectedFinalizers: []string{"resources-finalizer.argocd.argoproj.io"}, - }, - { - testName: "empty array finalizers should use standard finalizer", - existingFinalizers: []string{}, - syncPolicy: nil, - expectedFinalizers: []string{"resources-finalizer.argocd.argoproj.io"}, - }, - { - testName: "non-nil sync policy should use standard finalizer", - existingFinalizers: nil, - syncPolicy: &argoappsetv1.ApplicationSetSyncPolicy{}, - expectedFinalizers: []string{"resources-finalizer.argocd.argoproj.io"}, - }, - { - testName: "preserveResourcesOnDeletion should not have a finalizer", - existingFinalizers: nil, - syncPolicy: &argoappsetv1.ApplicationSetSyncPolicy{ - PreserveResourcesOnDeletion: true, - }, - expectedFinalizers: nil, - }, - { - testName: "user-specified finalizer should overwrite preserveResourcesOnDeletion", - existingFinalizers: []string{"resources-finalizer.argocd.argoproj.io/background"}, - syncPolicy: &argoappsetv1.ApplicationSetSyncPolicy{ - PreserveResourcesOnDeletion: true, - }, - expectedFinalizers: []string{"resources-finalizer.argocd.argoproj.io/background"}, - }, - } { - - t.Run(c.testName, func(t *testing.T) { - - // Clone the template application - application := emptyApplication.DeepCopy() - application.Finalizers = c.existingFinalizers - - params := map[string]string{ - "one": "two", - } - - // Render the cloned application, into a new application - render := Render{} - - res, err := render.RenderTemplateParams(application, c.syncPolicy, params) - assert.Nil(t, err) - - assert.ElementsMatch(t, res.Finalizers, c.expectedFinalizers) - - }) - - } - -} - func TestCheckInvalidGenerators(t *testing.T) { scheme := runtime.NewScheme() diff --git a/go.mod b/go.mod index 111b030807539..7f93715337fbe 100644 --- a/go.mod +++ b/go.mod @@ -110,7 +110,7 @@ require ( github.com/Azure/go-autorest/logger v0.2.1 // indirect github.com/Azure/go-autorest/tracing v0.6.0 // indirect github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd // indirect - github.com/Masterminds/goutils v1.1.0 // indirect + github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/semver v1.5.0 // indirect github.com/Masterminds/sprig v2.22.0+incompatible // indirect github.com/Microsoft/go-winio v0.4.17 // indirect @@ -157,7 +157,7 @@ require ( github.com/gregdel/pushover v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-version v1.2.1 // indirect - github.com/huandu/xstrings v1.3.0 // indirect + github.com/huandu/xstrings v1.3.1 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/itchyny/timefmt-go v0.1.2 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect @@ -230,6 +230,7 @@ require ( ) require ( + github.com/Masterminds/sprig/v3 v3.2.2 github.com/gosimple/slug v1.12.0 github.com/microsoft/azure-devops-go-api/azuredevops v1.0.0-b5 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.31.0 @@ -245,6 +246,8 @@ require ( github.com/gosimple/unidecode v1.0.1 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect + github.com/shopspring/decimal v1.2.0 // indirect + github.com/spf13/cast v1.4.1 // indirect go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.6.3 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.6.3 // indirect go.opentelemetry.io/otel/trace v1.6.3 // indirect diff --git a/go.sum b/go.sum index 0130942d1a089..d58a33a8e4f8f 100644 --- a/go.sum +++ b/go.sum @@ -87,14 +87,17 @@ github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible h1 github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd h1:sjQovDkwrZp8u+gxLtPgKGjk5hCxuy2hrRejBTA9xFU= github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E= -github.com/Masterminds/goutils v1.1.0 h1:zukEsf/1JZwCMgHiK3GZftabmxiCw4apj3a28RPBiVg= github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= +github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= +github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZCSYp4Z0m2dk6cEM60= github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= +github.com/Masterminds/sprig/v3 v3.2.2 h1:17jRggJu518dr3QaafizSXOjKYp94wKfABxUmyxvxX8= +github.com/Masterminds/sprig/v3 v3.2.2/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk= github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= github.com/Microsoft/go-winio v0.4.15/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= @@ -665,14 +668,16 @@ github.com/heketi/heketi v10.3.0+incompatible/go.mod h1:bB9ly3RchcQqsQ9CpyaQwvva github.com/heketi/tests v0.0.0-20151005000721-f3775cbcefd6/go.mod h1:xGMAM8JLi7UkZt1i4FQeQy0R2T8GLUwQhOP5M1gBhy4= github.com/howeyc/gopass v0.0.0-20170109162249-bf9dde6d0d2c/go.mod h1:lADxMC39cJJqL93Duh1xhAs4I2Zs8mKS89XWXFGp9cs= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/huandu/xstrings v1.3.0 h1:gvV6jG9dTgFEncxo+AF7PH6MZXi/vZl25owA/8Dg8Wo= github.com/huandu/xstrings v1.3.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/huandu/xstrings v1.3.1 h1:4jgBlKK6tLKFvO8u5pmYjG91cqytmDCDvGh7ECVFfFs= +github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/improbable-eng/grpc-web v0.0.0-20181111100011-16092bd1d58a h1:RweVA0vnEyStwtAelyGmnU8ENDnwd1Q7pQr7U3J/rXo= @@ -1021,6 +1026,8 @@ github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvW github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= +github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= @@ -1051,6 +1058,7 @@ github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY52 github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA= github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= @@ -1234,6 +1242,7 @@ golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= diff --git a/manifests/core-install.yaml b/manifests/core-install.yaml index 00a32c751bb1a..d3dc3722222ce 100644 --- a/manifests/core-install.yaml +++ b/manifests/core-install.yaml @@ -8790,6 +8790,8 @@ spec: - metadata - spec type: object + untypedTemplate: + type: string required: - generators - template diff --git a/manifests/crds/applicationset-crd.yaml b/manifests/crds/applicationset-crd.yaml index e642c5d9ce6ac..e14cb99d00bed 100644 --- a/manifests/crds/applicationset-crd.yaml +++ b/manifests/crds/applicationset-crd.yaml @@ -6638,6 +6638,8 @@ spec: - metadata - spec type: object + untypedTemplate: + type: string required: - generators - template diff --git a/manifests/ha/install.yaml b/manifests/ha/install.yaml index d03bc0cd710ef..bc399b42fc49d 100644 --- a/manifests/ha/install.yaml +++ b/manifests/ha/install.yaml @@ -8790,6 +8790,8 @@ spec: - metadata - spec type: object + untypedTemplate: + type: string required: - generators - template diff --git a/manifests/install.yaml b/manifests/install.yaml index c796f1fe5e939..122d0ecec84f7 100644 --- a/manifests/install.yaml +++ b/manifests/install.yaml @@ -8790,6 +8790,8 @@ spec: - metadata - spec type: object + untypedTemplate: + type: string required: - generators - template diff --git a/pkg/apis/applicationset/v1alpha1/applicationset_types.go b/pkg/apis/applicationset/v1alpha1/applicationset_types.go index 2cdf13786a0e9..15917acebb614 100644 --- a/pkg/apis/applicationset/v1alpha1/applicationset_types.go +++ b/pkg/apis/applicationset/v1alpha1/applicationset_types.go @@ -49,9 +49,10 @@ type ApplicationSet struct { // ApplicationSetSpec represents a class of application set state. type ApplicationSetSpec struct { - Generators []ApplicationSetGenerator `json:"generators"` - Template ApplicationSetTemplate `json:"template"` - SyncPolicy *ApplicationSetSyncPolicy `json:"syncPolicy,omitempty"` + Generators []ApplicationSetGenerator `json:"generators"` + Template *ApplicationSetTemplate `json:"template"` + SyncPolicy *ApplicationSetSyncPolicy `json:"syncPolicy,omitempty"` + UntypedTemplate *ApplicationSetUntypedTemplate `json:"untypedTemplate,omitempty"` } // ApplicationSetSyncPolicy configures how generated Applications will relate to their @@ -67,6 +68,9 @@ type ApplicationSetTemplate struct { Spec v1alpha1.ApplicationSpec `json:"spec"` } +// ApplicationSetUntypedTemplate represents argocd ApplicationSpec without type check +type ApplicationSetUntypedTemplate string + // ApplicationSetTemplateMeta represents the Argo CD application fields that may // be used for Applications generated from the ApplicationSet (based on metav1.ObjectMeta) type ApplicationSetTemplateMeta struct { diff --git a/pkg/apis/applicationset/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/applicationset/v1alpha1/zz_generated.deepcopy.go index e043dcb302fb2..c685a1362ef9d 100644 --- a/pkg/apis/applicationset/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/applicationset/v1alpha1/zz_generated.deepcopy.go @@ -243,12 +243,21 @@ func (in *ApplicationSetSpec) DeepCopyInto(out *ApplicationSetSpec) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - in.Template.DeepCopyInto(&out.Template) + if in.Template != nil { + in, out := &in.Template, &out.Template + *out = new(ApplicationSetTemplate) + (*in).DeepCopyInto(*out) + } if in.SyncPolicy != nil { in, out := &in.SyncPolicy, &out.SyncPolicy *out = new(ApplicationSetSyncPolicy) **out = **in } + if in.UntypedTemplate != nil { + in, out := &in.UntypedTemplate, &out.UntypedTemplate + *out = new(ApplicationSetUntypedTemplate) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationSetSpec. diff --git a/test/e2e/applicationset_test.go b/test/e2e/applicationset_test.go index 2129273bd9eaa..f018daff4aa1c 100644 --- a/test/e2e/applicationset_test.go +++ b/test/e2e/applicationset_test.go @@ -74,7 +74,7 @@ func TestSimpleListGenerator(t *testing.T) { Name: "simple-list-generator", }, Spec: v1alpha1.ApplicationSetSpec{ - Template: v1alpha1.ApplicationSetTemplate{ + Template: &v1alpha1.ApplicationSetTemplate{ ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{Name: "{{cluster}}-guestbook"}, Spec: argov1alpha1.ApplicationSpec{ Project: "default", @@ -175,7 +175,7 @@ func TestSimpleGitDirectoryGenerator(t *testing.T) { Name: "simple-git-generator", }, Spec: v1alpha1.ApplicationSetSpec{ - Template: v1alpha1.ApplicationSetTemplate{ + Template: &v1alpha1.ApplicationSetTemplate{ ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{Name: "{{path.basename}}"}, Spec: argov1alpha1.ApplicationSpec{ Project: "default", @@ -284,7 +284,7 @@ func TestSimpleGitFilesGenerator(t *testing.T) { Name: "simple-git-generator", }, Spec: v1alpha1.ApplicationSetSpec{ - Template: v1alpha1.ApplicationSetTemplate{ + Template: &v1alpha1.ApplicationSetTemplate{ ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{Name: "{{cluster.name}}-guestbook"}, Spec: argov1alpha1.ApplicationSpec{ Project: "default", @@ -360,7 +360,7 @@ func TestSimpleGitFilesPreserveResourcesOnDeletion(t *testing.T) { Name: "simple-git-generator", }, Spec: v1alpha1.ApplicationSetSpec{ - Template: v1alpha1.ApplicationSetTemplate{ + Template: &v1alpha1.ApplicationSetTemplate{ ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{Name: "{{cluster.name}}-guestbook"}, Spec: argov1alpha1.ApplicationSpec{ Project: "default", @@ -444,7 +444,7 @@ func TestSimpleSCMProviderGenerator(t *testing.T) { Name: "simple-scm-provider-generator", }, Spec: v1alpha1.ApplicationSetSpec{ - Template: v1alpha1.ApplicationSetTemplate{ + Template: &v1alpha1.ApplicationSetTemplate{ ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{Name: "{{ repository }}-guestbook"}, Spec: argov1alpha1.ApplicationSpec{ Project: "default", @@ -508,7 +508,7 @@ func TestCustomApplicationFinalizers(t *testing.T) { Name: "simple-list-generator", }, Spec: v1alpha1.ApplicationSetSpec{ - Template: v1alpha1.ApplicationSetTemplate{ + Template: &v1alpha1.ApplicationSetTemplate{ ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{ Name: "{{cluster}}-guestbook", Finalizers: []string{"resources-finalizer.argocd.argoproj.io/background"}, @@ -582,7 +582,7 @@ func TestSimplePullRequestGenerator(t *testing.T) { Name: "simple-pull-request-generator", }, Spec: v1alpha1.ApplicationSetSpec{ - Template: v1alpha1.ApplicationSetTemplate{ + Template: &v1alpha1.ApplicationSetTemplate{ ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{Name: "guestbook-{{ number }}"}, Spec: argov1alpha1.ApplicationSpec{ Project: "default", @@ -658,7 +658,7 @@ func TestGitGeneratorPrivateRepo(t *testing.T) { Name: "simple-git-generator-private", }, Spec: v1alpha1.ApplicationSetSpec{ - Template: v1alpha1.ApplicationSetTemplate{ + Template: &v1alpha1.ApplicationSetTemplate{ ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{Name: "{{path.basename}}"}, Spec: argov1alpha1.ApplicationSpec{ Project: "default", diff --git a/test/e2e/cluster_generator_test.go b/test/e2e/cluster_generator_test.go index 1049d9c3d1fc0..7d02bd92cf5f5 100644 --- a/test/e2e/cluster_generator_test.go +++ b/test/e2e/cluster_generator_test.go @@ -49,7 +49,7 @@ func TestSimpleClusterGenerator(t *testing.T) { Name: "simple-cluster-generator", }, Spec: v1alpha1.ApplicationSetSpec{ - Template: v1alpha1.ApplicationSetTemplate{ + Template: &v1alpha1.ApplicationSetTemplate{ ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{Name: "{{name}}-guestbook"}, Spec: argov1alpha1.ApplicationSpec{ Project: "default", @@ -173,7 +173,7 @@ func TestClusterGeneratorWithLocalCluster(t *testing.T) { Name: "in-cluster-generator", }, Spec: v1alpha1.ApplicationSetSpec{ - Template: v1alpha1.ApplicationSetTemplate{ + Template: &v1alpha1.ApplicationSetTemplate{ ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{Name: "{{name}}-guestbook"}, Spec: argov1alpha1.ApplicationSpec{ Project: "default", @@ -264,7 +264,7 @@ func TestSimpleClusterGeneratorAddingCluster(t *testing.T) { Name: "simple-cluster-generator", }, Spec: v1alpha1.ApplicationSetSpec{ - Template: v1alpha1.ApplicationSetTemplate{ + Template: &v1alpha1.ApplicationSetTemplate{ ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{Name: "{{name}}-guestbook"}, Spec: argov1alpha1.ApplicationSpec{ Project: "default", @@ -347,7 +347,7 @@ func TestSimpleClusterGeneratorDeletingCluster(t *testing.T) { Name: "simple-cluster-generator", }, Spec: v1alpha1.ApplicationSetSpec{ - Template: v1alpha1.ApplicationSetTemplate{ + Template: &v1alpha1.ApplicationSetTemplate{ ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{Name: "{{name}}-guestbook"}, Spec: argov1alpha1.ApplicationSpec{ Project: "default", diff --git a/test/e2e/clusterdecisiongenerator_e2e_test.go b/test/e2e/clusterdecisiongenerator_e2e_test.go index 94c5e052c6e8d..e4ffd3b94a080 100644 --- a/test/e2e/clusterdecisiongenerator_e2e_test.go +++ b/test/e2e/clusterdecisiongenerator_e2e_test.go @@ -61,7 +61,7 @@ func TestSimpleClusterDecisionResourceGenerator(t *testing.T) { Name: "simple-cluster-generator", }, Spec: v1alpha1.ApplicationSetSpec{ - Template: v1alpha1.ApplicationSetTemplate{ + Template: &v1alpha1.ApplicationSetTemplate{ ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{Name: "{{name}}-guestbook"}, Spec: argov1alpha1.ApplicationSpec{ Project: "default", @@ -172,7 +172,7 @@ func TestSimpleClusterDecisionResourceGeneratorAddingCluster(t *testing.T) { Name: "simple-cluster-generator", }, Spec: v1alpha1.ApplicationSetSpec{ - Template: v1alpha1.ApplicationSetTemplate{ + Template: &v1alpha1.ApplicationSetTemplate{ ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{Name: "{{name}}-guestbook"}, Spec: argov1alpha1.ApplicationSpec{ Project: "default", @@ -268,7 +268,7 @@ func TestSimpleClusterDecisionResourceGeneratorDeletingClusterSecret(t *testing. Name: "simple-cluster-generator", }, Spec: v1alpha1.ApplicationSetSpec{ - Template: v1alpha1.ApplicationSetTemplate{ + Template: &v1alpha1.ApplicationSetTemplate{ ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{Name: "{{name}}-guestbook"}, Spec: argov1alpha1.ApplicationSpec{ Project: "default", @@ -372,7 +372,7 @@ func TestSimpleClusterDecisionResourceGeneratorDeletingClusterFromResource(t *te Name: "simple-cluster-generator", }, Spec: v1alpha1.ApplicationSetSpec{ - Template: v1alpha1.ApplicationSetTemplate{ + Template: &v1alpha1.ApplicationSetTemplate{ ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{Name: "{{name}}-guestbook"}, Spec: argov1alpha1.ApplicationSpec{ Project: "default", diff --git a/test/e2e/matrix_e2e_test.go b/test/e2e/matrix_e2e_test.go index 99f840263d40a..1118f46a2dee0 100644 --- a/test/e2e/matrix_e2e_test.go +++ b/test/e2e/matrix_e2e_test.go @@ -60,7 +60,7 @@ func TestListMatrixGenerator(t *testing.T) { Name: "matrix-generator", }, Spec: v1alpha1.ApplicationSetSpec{ - Template: v1alpha1.ApplicationSetTemplate{ + Template: &v1alpha1.ApplicationSetTemplate{ ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{Name: "{{values.name}}-{{path.basename}}"}, Spec: argov1alpha1.ApplicationSpec{ Project: "default", @@ -186,7 +186,7 @@ func TestClusterMatrixGenerator(t *testing.T) { Name: "matrix-generator", }, Spec: v1alpha1.ApplicationSetSpec{ - Template: v1alpha1.ApplicationSetTemplate{ + Template: &v1alpha1.ApplicationSetTemplate{ ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{Name: "{{name}}-{{path.basename}}"}, Spec: argov1alpha1.ApplicationSpec{ Project: "default", diff --git a/test/e2e/merge_e2e_test.go b/test/e2e/merge_e2e_test.go index 482fb5759a01b..e8f1155e34758 100644 --- a/test/e2e/merge_e2e_test.go +++ b/test/e2e/merge_e2e_test.go @@ -56,7 +56,7 @@ func TestListMergeGenerator(t *testing.T) { Name: "merge-generator", }, Spec: v1alpha1.ApplicationSetSpec{ - Template: v1alpha1.ApplicationSetTemplate{ + Template: &v1alpha1.ApplicationSetTemplate{ ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{Name: "{{path.basename}}-{{name-suffix}}"}, Spec: argov1alpha1.ApplicationSpec{ Project: "default", @@ -183,7 +183,7 @@ func TestClusterMergeGenerator(t *testing.T) { Name: "merge-generator", }, Spec: v1alpha1.ApplicationSetSpec{ - Template: v1alpha1.ApplicationSetTemplate{ + Template: &v1alpha1.ApplicationSetTemplate{ ApplicationSetTemplateMeta: v1alpha1.ApplicationSetTemplateMeta{Name: "{{name}}-{{path.basename}}-{{values.name-suffix}}"}, Spec: argov1alpha1.ApplicationSpec{ Project: "default", From fd182577c496a08d10a11533acfb0db5adc63025 Mon Sep 17 00:00:00 2001 From: rishabh625 Date: Tue, 5 Jul 2022 13:23:47 +0530 Subject: [PATCH 2/2] fix lint issues Signed-off-by: rishabh625 --- applicationset/generators/generator_spec_processor.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/applicationset/generators/generator_spec_processor.go b/applicationset/generators/generator_spec_processor.go index ec85545f035ff..12d89b85113a5 100644 --- a/applicationset/generators/generator_spec_processor.go +++ b/applicationset/generators/generator_spec_processor.go @@ -26,7 +26,7 @@ func Transform(requestedGenerator argoprojiov1alpha1.ApplicationSetGenerator, al generators := GetRelevantGenerators(&requestedGenerator, allGenerators) for _, g := range generators { // we call mergeGeneratorTemplate first because GenerateParams might be more costly so we want to fail fast if there is an error - mergedTemplate, err := mergeGeneratorTemplate(g, &requestedGenerator, baseTemplate) + mergedTemplate, err := mergeGeneratorTemplate(g, &requestedGenerator, &baseTemplate) if err != nil { log.WithError(err).WithField("generator", g). Error("error generating params") @@ -85,7 +85,7 @@ func GetRelevantGenerators(requestedGenerator *argoprojiov1alpha1.ApplicationSet return res } -func mergeGeneratorTemplate(g Generator, requestedGenerator *argoprojiov1alpha1.ApplicationSetGenerator, applicationSetTemplate argoprojiov1alpha1.ApplicationSetTemplate) (argoprojiov1alpha1.ApplicationSetTemplate, error) { +func mergeGeneratorTemplate(g Generator, requestedGenerator *argoprojiov1alpha1.ApplicationSetGenerator, applicationSetTemplate *argoprojiov1alpha1.ApplicationSetTemplate) (argoprojiov1alpha1.ApplicationSetTemplate, error) { // Make a copy of the value from `GetTemplate()` before merge, rather than copying directly into // the provided parameter (which will touch the original resource object returned by client-go) @@ -93,8 +93,8 @@ func mergeGeneratorTemplate(g Generator, requestedGenerator *argoprojiov1alpha1. var err error - if &applicationSetTemplate != nil { - err = mergo.Merge(dest, &applicationSetTemplate) + if applicationSetTemplate != nil { + err = mergo.Merge(dest, applicationSetTemplate) } else { log.Warn("generator template won't be applied when standard application template is not used") }