diff --git a/reposerver/repository/repository.go b/reposerver/repository/repository.go index f66bc71ac4621..46807d7d36a4b 100644 --- a/reposerver/repository/repository.go +++ b/reposerver/repository/repository.go @@ -1374,7 +1374,10 @@ func GenerateManifests(ctx context.Context, appPath, repoRoot, revision string, kustomizeBinary = q.KustomizeOptions.BinaryPath } k := kustomize.NewKustomizeApp(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 { @@ -2115,7 +2118,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 2487b14b4903b..e44252a520eea 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. @@ -85,7 +90,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 { @@ -293,13 +298,11 @@ func (k *kustomize) Build(opts *v1alpha1.ApplicationSourceKustomize, kustomizeOp } } - var cmd *exec.Cmd - if kustomizeOptions != nil && kustomizeOptions.BuildOptions != "" { - params := parseKustomizeBuildOptions(k.path, kustomizeOptions.BuildOptions) - cmd = exec.Command(k.getBinaryPath(), params...) - } else { - cmd = exec.Command(k.getBinaryPath(), "build", k.path) + buildOptions := "" + if kustomizeOptions != nil { + buildOptions = kustomizeOptions.BuildOptions } + cmd := exec.Command(k.getBinaryPath(), parseKustomizeBuildOptions(k.path, buildOptions, buildOpts)...) cmd.Env = env out, err := executil.Run(cmd) if err != nil { @@ -314,8 +317,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.Split(buildOptions, " ")...) +func parseKustomizeBuildOptions(kustomizePath string, buildOptions string, buildOpts *BuildOpts) []string { + buildOptsParams := []string{"build", kustomizePath} + if buildOpts != nil && getSemverSafe().GreaterThan(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 a6275cf01ae1b..98f9438c200ae 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,25 @@ 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", + }, built) +} + func TestVersion(t *testing.T) { ver, err := Version(false) assert.NoError(t, err) @@ -223,7 +240,7 @@ func TestKustomizeBuildForceCommonLabels(t *testing.T) { appPath, err := testDataDir(t, tc.TestData) assert.Nil(t, err) kustomize := NewKustomizeApp(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 +332,7 @@ func TestKustomizeBuildForceCommonAnnotations(t *testing.T) { appPath, err := testDataDir(t, tc.TestData) assert.Nil(t, err) kustomize := NewKustomizeApp(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 +358,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 +378,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 +411,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")