From 99e83dd55517f7b505d84ee89d205bd3cb6d4071 Mon Sep 17 00:00:00 2001 From: Arthur Outhenin-Chalandre Date: Fri, 8 Dec 2023 17:35:23 +0100 Subject: [PATCH] feat(kustomize): add support for new args to pass api and kube versions Signed-off-by: Arthur Outhenin-Chalandre --- reposerver/repository/repository.go | 7 ++++-- util/kustomize/kustomize.go | 32 ++++++++++++++++++++++----- util/kustomize/kustomize_test.go | 34 ++++++++++++++++++++++------- 3 files changed, 58 insertions(+), 15 deletions(-) diff --git a/reposerver/repository/repository.go b/reposerver/repository/repository.go index 5d11a6438272d..36a320f4e2eec 100644 --- a/reposerver/repository/repository.go +++ b/reposerver/repository/repository.go @@ -1390,7 +1390,10 @@ func GenerateManifests(ctx context.Context, appPath, repoRoot, revision string, kustomizeBinary = q.KustomizeOptions.BinaryPath } k := kustomize.NewKustomizeApp(repoRoot, appPath, q.Repo.GetGitCreds(gitCredsStore), repoURL, kustomizeBinary) - targetObjs, _, err = k.Build(q.ApplicationSource.Kustomize, q.KustomizeOptions, env) + targetObjs, _, err = k.Build(q.ApplicationSource.Kustomize, q.KustomizeOptions, env, &kustomize.BuildOpts{ + KubeVersion: q.KubeVersion, + APIVersions: q.ApiVersions, + }) case v1alpha1.ApplicationSourceTypePlugin: pluginName := "" if q.ApplicationSource.Plugin != nil { @@ -2131,7 +2134,7 @@ func populateKustomizeAppDetails(res *apiclient.RepoAppDetailsResponse, q *apicl ApplicationSource: q.Source, } env := newEnv(&fakeManifestRequest, reversion) - _, images, err := k.Build(q.Source.Kustomize, q.KustomizeOptions, env) + _, images, err := k.Build(q.Source.Kustomize, q.KustomizeOptions, env, nil) if err != nil { return err } diff --git a/util/kustomize/kustomize.go b/util/kustomize/kustomize.go index d938beeceb578..82d36f5839bee 100644 --- a/util/kustomize/kustomize.go +++ b/util/kustomize/kustomize.go @@ -28,10 +28,15 @@ import ( // represents a Docker image in the format NAME[:TAG]. type Image = string +type BuildOpts struct { + KubeVersion string + APIVersions []string +} + // Kustomize provides wrapper functionality around the `kustomize` command. type Kustomize interface { // Build returns a list of unstructured objects from a `kustomize build` command and extract supported parameters - Build(opts *v1alpha1.ApplicationSourceKustomize, kustomizeOptions *v1alpha1.KustomizeOptions, envVars *v1alpha1.Env) ([]*unstructured.Unstructured, []Image, error) + Build(opts *v1alpha1.ApplicationSourceKustomize, kustomizeOptions *v1alpha1.KustomizeOptions, envVars *v1alpha1.Env, buildOpts *BuildOpts) ([]*unstructured.Unstructured, []Image, error) } // NewKustomizeApp create a new wrapper to run commands on the `kustomize` command-line tool. @@ -88,7 +93,7 @@ func mapToEditAddArgs(val map[string]string) []string { return args } -func (k *kustomize) Build(opts *v1alpha1.ApplicationSourceKustomize, kustomizeOptions *v1alpha1.KustomizeOptions, envVars *v1alpha1.Env) ([]*unstructured.Unstructured, []Image, error) { +func (k *kustomize) Build(opts *v1alpha1.ApplicationSourceKustomize, kustomizeOptions *v1alpha1.KustomizeOptions, envVars *v1alpha1.Env, buildOpts *BuildOpts) ([]*unstructured.Unstructured, []Image, error) { env := os.Environ() if envVars != nil { @@ -298,7 +303,7 @@ func (k *kustomize) Build(opts *v1alpha1.ApplicationSourceKustomize, kustomizeOp var cmd *exec.Cmd if kustomizeOptions != nil && kustomizeOptions.BuildOptions != "" { - params := parseKustomizeBuildOptions(k.path, kustomizeOptions.BuildOptions) + params := parseKustomizeBuildOptions(k.path, kustomizeOptions.BuildOptions, buildOpts) cmd = exec.Command(k.getBinaryPath(), params...) } else { cmd = exec.Command(k.getBinaryPath(), "build", k.path) @@ -318,8 +323,25 @@ func (k *kustomize) Build(opts *v1alpha1.ApplicationSourceKustomize, kustomizeOp return objs, getImageParameters(objs), nil } -func parseKustomizeBuildOptions(path, buildOptions string) []string { - return append([]string{"build", path}, strings.Fields(buildOptions)...) +func parseKustomizeBuildOptions(path string, buildOptions string, buildOpts *BuildOpts) []string { + buildOptsParams := []string{"build", path} + if buildOpts != nil && !getSemverSafe().LessThan(semver.MustParse("v5.3.0")) && isHelmEnabled(buildOptions) { + if buildOpts.KubeVersion != "" { + buildOptsParams = append(buildOptsParams, "--helm-kube-version", buildOpts.KubeVersion) + } + for _, v := range buildOpts.APIVersions { + buildOptsParams = append(buildOptsParams, "--helm-api-versions", v) + } + } + if buildOptions != "" { + buildOptsParams = append(buildOptsParams, strings.Split(buildOptions, " ")...) + } + + return buildOptsParams +} + +func isHelmEnabled(buildOptions string) bool { + return strings.Contains(buildOptions, "--enable-helm") } var KustomizationNames = []string{"kustomization.yaml", "kustomization.yml", "Kustomization"} diff --git a/util/kustomize/kustomize_test.go b/util/kustomize/kustomize_test.go index b7a8e319c3295..c2c9c081e745c 100644 --- a/util/kustomize/kustomize_test.go +++ b/util/kustomize/kustomize_test.go @@ -69,7 +69,9 @@ func TestKustomizeBuild(t *testing.T) { }, }, } - objs, images, err := kustomize.Build(&kustomizeSource, nil, env) + objs, images, err := kustomize.Build(&kustomizeSource, nil, env, &BuildOpts{ + KubeVersion: "1.27", APIVersions: []string{"foo", "bar"}, + }) assert.Nil(t, err) if err != nil { assert.Equal(t, len(objs), 2) @@ -132,7 +134,7 @@ func TestFailKustomizeBuild(t *testing.T) { }, }, } - _, _, err = kustomize.Build(&kustomizeSource, nil, nil) + _, _, err = kustomize.Build(&kustomizeSource, nil, nil, nil) assert.EqualError(t, err, "expected integer value for count. Received: garbage") } @@ -156,10 +158,26 @@ func TestIsKustomization(t *testing.T) { } func TestParseKustomizeBuildOptions(t *testing.T) { - built := parseKustomizeBuildOptions("guestbook", "-v 6 --logtostderr") + built := parseKustomizeBuildOptions("guestbook", "-v 6 --logtostderr", &BuildOpts{ + KubeVersion: "1.27", APIVersions: []string{"foo", "bar"}, + }) + // Helm is not enabled so helm options are not in the params assert.Equal(t, []string{"build", "guestbook", "-v", "6", "--logtostderr"}, built) } +func TestParseKustomizeBuildHelmOptions(t *testing.T) { + built := parseKustomizeBuildOptions("guestbook", "-v 6 --logtostderr --enable-helm", &BuildOpts{ + KubeVersion: "1.27", + APIVersions: []string{"foo", "bar"}, + }) + assert.Equal(t, []string{ + "build", "guestbook", + "--helm-kube-version", "1.27", + "--helm-api-versions", "foo", "--helm-api-versions", "bar", + "-v", "6", "--logtostderr", "--enable-helm", + }, built) +} + func TestVersion(t *testing.T) { ver, err := Version(false) assert.NoError(t, err) @@ -223,7 +241,7 @@ func TestKustomizeBuildForceCommonLabels(t *testing.T) { appPath, err := testDataDir(t, tc.TestData) assert.Nil(t, err) kustomize := NewKustomizeApp(appPath, appPath, git.NopCreds{}, "", "") - objs, _, err := kustomize.Build(&tc.KustomizeSource, nil, tc.Env) + objs, _, err := kustomize.Build(&tc.KustomizeSource, nil, tc.Env, nil) switch tc.ExpectErr { case true: assert.Error(t, err) @@ -315,7 +333,7 @@ func TestKustomizeBuildForceCommonAnnotations(t *testing.T) { appPath, err := testDataDir(t, tc.TestData) assert.Nil(t, err) kustomize := NewKustomizeApp(appPath, appPath, git.NopCreds{}, "", "") - objs, _, err := kustomize.Build(&tc.KustomizeSource, nil, tc.Env) + objs, _, err := kustomize.Build(&tc.KustomizeSource, nil, tc.Env, nil) switch tc.ExpectErr { case true: assert.Error(t, err) @@ -341,7 +359,7 @@ func TestKustomizeCustomVersion(t *testing.T) { env := &v1alpha1.Env{ &v1alpha1.EnvEntry{Name: "ARGOCD_APP_NAME", Value: "argo-cd-tests"}, } - objs, images, err := kustomize.Build(&kustomizeSource, nil, env) + objs, images, err := kustomize.Build(&kustomizeSource, nil, env, nil) assert.Nil(t, err) if err != nil { assert.Equal(t, len(objs), 2) @@ -361,7 +379,7 @@ func TestKustomizeBuildComponents(t *testing.T) { kustomizeSource := v1alpha1.ApplicationSourceKustomize{ Components: []string{"./components"}, } - objs, _, err := kustomize.Build(&kustomizeSource, nil, nil) + objs, _, err := kustomize.Build(&kustomizeSource, nil, nil, nil) assert.Nil(t, err) obj := objs[0] assert.Equal(t, "nginx-deployment", obj.GetName()) @@ -394,7 +412,7 @@ func TestKustomizeBuildPatches(t *testing.T) { }, }, } - objs, _, err := kustomize.Build(&kustomizeSource, nil, nil) + objs, _, err := kustomize.Build(&kustomizeSource, nil, nil, nil) assert.Nil(t, err) obj := objs[0] containers, found, err := unstructured.NestedSlice(obj.Object, "spec", "template", "spec", "containers")