fix(repo-server): support .argocd-source.yaml kustomize version (#23643) (#23644)

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Co-authored-by: rumstead <37445536+rumstead@users.noreply.github.com>
This commit is contained in:
Michael Crenshaw 2025-07-16 08:12:25 -07:00 committed by GitHub
parent 6b6512ae30
commit 8e00df5326
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
27 changed files with 1505 additions and 956 deletions

26
assets/swagger.json generated
View file

@ -8639,12 +8639,20 @@
"title": "KustomizeOptions are options for kustomize to use when building manifests",
"properties": {
"binaryPath": {
"description": "Deprecated: Use settings.Settings instead. See: settings.Settings.KustomizeVersions.\nIf this field is set, it will be used as the Kustomize binary path.\nOtherwise, Versions is used.",
"type": "string",
"title": "BinaryPath holds optional path to kustomize binary"
},
"buildOptions": {
"type": "string",
"title": "BuildOptions is a string of build parameters to use when calling `kustomize build`"
},
"versions": {
"description": "Versions is a list of Kustomize versions and their corresponding binary paths and build options.",
"type": "array",
"items": {
"$ref": "#/definitions/v1alpha1KustomizeVersion"
}
}
}
},
@ -8708,6 +8716,24 @@
}
}
},
"v1alpha1KustomizeVersion": {
"type": "object",
"title": "KustomizeVersion holds information about additional Kustomize versions",
"properties": {
"buildOptions": {
"type": "string",
"title": "BuildOptions that are specific to a Kustomize version"
},
"name": {
"type": "string",
"title": "Name holds Kustomize version name"
},
"path": {
"type": "string",
"title": "Path holds the corresponding binary path"
}
}
},
"v1alpha1ListGenerator": {
"type": "object",
"title": "ListGenerator include items info",

View file

@ -235,10 +235,6 @@ func (m *appStateManager) GetRepoObjs(app *v1alpha1.Application, sources []v1alp
if err != nil {
return nil, nil, false, fmt.Errorf("failed to get repo %q: %w", source.RepoURL, err)
}
kustomizeOptions, err := kustomizeSettings.GetOptions(source)
if err != nil {
return nil, nil, false, fmt.Errorf("failed to get Kustomize options for source %d of %d: %w", i+1, len(sources), err)
}
syncedRevision := app.Status.Sync.Revision
if app.Spec.HasMultipleSources() {
@ -315,7 +311,7 @@ func (m *appStateManager) GetRepoObjs(app *v1alpha1.Application, sources []v1alp
AppName: app.InstanceName(m.namespace),
Namespace: appNamespace,
ApplicationSource: &source,
KustomizeOptions: kustomizeOptions,
KustomizeOptions: kustomizeSettings,
KubeVersion: serverVersion,
ApiVersions: apiVersions,
VerifySignature: verifySignature,

View file

@ -0,0 +1,39 @@
# v3.1 to 3.2
## Argo CD Now Respects Kustomize Version in `.argocd-source.yaml`
Argo CD provides a way to [override Application `spec.source` values](../../user-guide/parameters.md#store-overrides-in-git)
using the `.argocd-source.yaml` file.
Before Argo CD v3.2, you could set the Kustomize version in the Application's `.spec.source.kustomize.version` field,
but you could not set it in the `.argocd-source.yaml` file.
Starting with Argo CD v3.2, you can now set the Kustomize version in the `.argocd-source.yaml` file like this:
```yaml
kustomize:
version: v4.5.7
```
## Deprecated fields in the repo-server GRPC service
The repo-server's GRPC service is generally considered an internal API and is not recommended for use by external
clients. No user-facing services or functionality have changed. However, if you are using the repo-server's GRPC service
directly, please note field deprecations in the following messages.
The `kustomizeOptions.binaryPath` field in the `ManifestRequest` and `RepoServerAppDetailsQuery` messages has been
deprecated. Instead of calculating the correct binary path client-side, the client is expected to populate the
`kustomizeOptions.versions` field with the [configured Kustomize binary paths](../../user-guide/kustomize.md#custom-kustomize-versions).
This allows the repo-server to select the correct binary path based on the Kustomize version configured in the
Application's source field as well as any [overrides configured via git](../../user-guide/parameters.md#store-overrides-in-git).
The `kustomizeOptions.binaryPath` will continue to be respected when `kustomizeOptions.versions` is not set, but this is
not recommended. It will prevent overrides configured via git from being respected. The `kustomizeOptions.binaryPath`
field will be removed in a future release.
If the repo-server encounters a request with the `kustomizeOptions.binaryPath` field set, it will log a warning message:
> kustomizeOptions.binaryPath is deprecated, use KustomizeOptions.versions instead
The `ManifestRequest` and `RepoServerAppDetailsQuery` messages are used by the following GRPC services:
`GenerateManifest`, `GenerateManifestWithFiles`, and `GetAppDetails`.

View file

@ -38,6 +38,7 @@ kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/<v
<hr/>
- [v3.1 to v3.2](./3.1-3.2.md)
- [v3.0 to v3.1](./3.0-3.1.md)
- [v2.14 to v3.0](./2.14-3.0.md)
- [v2.13 to v2.14](./2.13-2.14.md)

View file

@ -131,6 +131,7 @@ nav:
- operator-manual/server-commands/additional-configuration-method.md
- Upgrading:
- operator-manual/upgrading/overview.md
- operator-manual/upgrading/3.1-3.2.md
- operator-manual/upgrading/3.0-3.1.md
- operator-manual/upgrading/2.14-3.0.md
- operator-manual/upgrading/2.13-2.14.md

File diff suppressed because it is too large Load diff

View file

@ -1312,7 +1312,14 @@ message KustomizeOptions {
optional string buildOptions = 1;
// BinaryPath holds optional path to kustomize binary
//
// Deprecated: Use settings.Settings instead. See: settings.Settings.KustomizeVersions.
// If this field is set, it will be used as the Kustomize binary path.
// Otherwise, Versions is used.
optional string binaryPath = 2;
// Versions is a list of Kustomize versions and their corresponding binary paths and build options.
repeated KustomizeVersion versions = 3;
}
message KustomizePatch {
@ -1349,6 +1356,18 @@ message KustomizeSelector {
optional string labelSelector = 3;
}
// KustomizeVersion holds information about additional Kustomize versions
message KustomizeVersion {
// Name holds Kustomize version name
optional string name = 1;
// Path holds the corresponding binary path
optional string path = 2;
// BuildOptions that are specific to a Kustomize version
optional string buildOptions = 3;
}
// ListGenerator include items info
message ListGenerator {
// +kubebuilder:validation:Optional

View file

@ -3181,12 +3181,30 @@ type HelmOptions struct {
ValuesFileSchemes []string `protobuf:"bytes,1,opt,name=valuesFileSchemes"`
}
// KustomizeVersion holds information about additional Kustomize versions
type KustomizeVersion struct {
// Name holds Kustomize version name
Name string `protobuf:"bytes,1,opt,name=name"`
// Path holds the corresponding binary path
Path string `protobuf:"bytes,2,opt,name=path"`
// BuildOptions that are specific to a Kustomize version
BuildOptions string `protobuf:"bytes,3,opt,name=buildOptions"`
}
// KustomizeOptions are options for kustomize to use when building manifests
type KustomizeOptions struct {
// BuildOptions is a string of build parameters to use when calling `kustomize build`
BuildOptions string `protobuf:"bytes,1,opt,name=buildOptions"`
// BinaryPath holds optional path to kustomize binary
//
// Deprecated: Use settings.Settings instead. See: settings.Settings.KustomizeVersions.
// If this field is set, it will be used as the Kustomize binary path.
// Otherwise, Versions is used.
BinaryPath string `protobuf:"bytes,2,opt,name=binaryPath"`
// Versions is a list of Kustomize versions and their corresponding binary paths and build options.
Versions []KustomizeVersion `protobuf:"bytes,3,rep,name=versions"`
}
// ApplicationDestinationServiceAccount holds information about the service account to be impersonated for the application sync operation.

View file

@ -2507,6 +2507,11 @@ func (in KustomizeImages) DeepCopy() KustomizeImages {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *KustomizeOptions) DeepCopyInto(out *KustomizeOptions) {
*out = *in
if in.Versions != nil {
in, out := &in.Versions, &out.Versions
*out = make([]KustomizeVersion, len(*in))
copy(*out, *in)
}
return
}
@ -2641,6 +2646,22 @@ func (in *KustomizeSelector) DeepCopy() *KustomizeSelector {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *KustomizeVersion) DeepCopyInto(out *KustomizeVersion) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KustomizeVersion.
func (in *KustomizeVersion) DeepCopy() *KustomizeVersion {
if in == nil {
return nil
}
out := new(KustomizeVersion)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ListGenerator) DeepCopyInto(out *ListGenerator) {
*out = *in

View file

@ -62,6 +62,7 @@ import (
pathutil "github.com/argoproj/argo-cd/v3/util/io/path"
"github.com/argoproj/argo-cd/v3/util/kustomize"
"github.com/argoproj/argo-cd/v3/util/manifeststream"
"github.com/argoproj/argo-cd/v3/util/settings"
"github.com/argoproj/argo-cd/v3/util/versions"
)
@ -1498,9 +1499,10 @@ func GenerateManifests(ctx context.Context, appPath, repoRoot, revision string,
targetObjs, command, err = helmTemplate(appPath, repoRoot, env, q, isLocal, gitRepoPaths)
commands = append(commands, command)
case v1alpha1.ApplicationSourceTypeKustomize:
kustomizeBinary := ""
if q.KustomizeOptions != nil {
kustomizeBinary = q.KustomizeOptions.BinaryPath
var kustomizeBinary string
kustomizeBinary, err = settings.GetKustomizeBinaryPath(q.KustomizeOptions, *q.ApplicationSource)
if err != nil {
return nil, fmt.Errorf("error getting kustomize binary path: %w", err)
}
k := kustomize.NewKustomizeApp(repoRoot, appPath, q.Repo.GetGitCreds(gitCredsStore), repoURL, kustomizeBinary, q.Repo.Proxy, q.Repo.NoProxy)
targetObjs, _, commands, err = k.Build(q.ApplicationSource.Kustomize, q.KustomizeOptions, env, &kustomize.BuildOpts{
@ -1669,7 +1671,8 @@ func mergeSourceParameters(source *v1alpha1.ApplicationSource, path, appName str
return nil
}
// GetAppSourceType returns explicit application source type or examines a directory and determines its application source type
// GetAppSourceType returns explicit application source type or examines a directory and determines its application source type.
// Overrides are applied as a side effect on the given source.
func GetAppSourceType(ctx context.Context, source *v1alpha1.ApplicationSource, appPath, repoPath, appName string, enableGenerateManifests map[string]bool, tarExcludedGlobs []string, env []string) (v1alpha1.ApplicationSourceType, error) {
err := mergeSourceParameters(source, appPath, appName)
if err != nil {
@ -2300,9 +2303,9 @@ func walkHelmValueFilesInPath(root string, valueFiles *[]string) filepath.WalkFu
func populateKustomizeAppDetails(res *apiclient.RepoAppDetailsResponse, q *apiclient.RepoServerAppDetailsQuery, repoRoot string, appPath string, reversion string, credsStore git.CredsStore) error {
res.Kustomize = &apiclient.KustomizeAppSpec{}
kustomizeBinary := ""
if q.KustomizeOptions != nil {
kustomizeBinary = q.KustomizeOptions.BinaryPath
kustomizeBinary, err := settings.GetKustomizeBinaryPath(q.KustomizeOptions, *q.Source)
if err != nil {
return fmt.Errorf("failed to get kustomize binary path: %w", err)
}
k := kustomize.NewKustomizeApp(repoRoot, appPath, q.Repo.GetGitCreds(credsStore), q.Repo.Repo, kustomizeBinary, q.Repo.Proxy, q.Repo.NoProxy)
fakeManifestRequest := apiclient.ManifestRequest{

View file

@ -52,6 +52,7 @@ import (
utilio "github.com/argoproj/argo-cd/v3/util/io"
iomocks "github.com/argoproj/argo-cd/v3/util/io/mocks"
ocimocks "github.com/argoproj/argo-cd/v3/util/oci/mocks"
"github.com/argoproj/argo-cd/v3/util/settings"
)
const testSignature = `gpg: Signature made Wed Feb 26 23:22:34 2020 CET
@ -239,6 +240,37 @@ func TestGenerateYamlManifestInDir(t *testing.T) {
assert.Len(t, res2.Manifests, 3)
}
func Test_GenerateManifest_KustomizeWithVersionOverride(t *testing.T) {
t.Parallel()
service := newService(t, "../../util/kustomize/testdata/kustomize-with-version-override")
src := v1alpha1.ApplicationSource{Path: "."}
q := apiclient.ManifestRequest{
Repo: &v1alpha1.Repository{},
ApplicationSource: &src,
ProjectName: "something",
ProjectSourceRepos: []string{"*"},
KustomizeOptions: &v1alpha1.KustomizeOptions{
Versions: []v1alpha1.KustomizeVersion{},
},
}
_, err := service.GenerateManifest(t.Context(), &q)
require.ErrorAs(t, err, &settings.KustomizeVersionNotRegisteredError{Version: "v1.2.3"})
q.KustomizeOptions.Versions = []v1alpha1.KustomizeVersion{
{
Name: "v1.2.3",
Path: "kustomize",
},
}
res, err := service.GenerateManifest(t.Context(), &q)
require.NoError(t, err)
assert.NotNil(t, res)
}
func Test_GenerateManifests_NoOutOfBoundsAccess(t *testing.T) {
t.Parallel()
@ -1674,6 +1706,32 @@ func TestGetAppDetailsKustomize(t *testing.T) {
assert.Equal(t, []string{"nginx:1.15.4", "registry.k8s.io/nginx-slim:0.8"}, res.Kustomize.Images)
}
func TestGetAppDetailsKustomize_CustomVersion(t *testing.T) {
service := newService(t, "../../util/kustomize/testdata/kustomize-with-version-override")
q := &apiclient.RepoServerAppDetailsQuery{
Repo: &v1alpha1.Repository{},
Source: &v1alpha1.ApplicationSource{
Path: ".",
},
KustomizeOptions: &v1alpha1.KustomizeOptions{},
}
_, err := service.GetAppDetails(t.Context(), q)
require.ErrorAs(t, err, &settings.KustomizeVersionNotRegisteredError{Version: "v1.2.3"})
q.KustomizeOptions.Versions = []v1alpha1.KustomizeVersion{
{
Name: "v1.2.3",
Path: "kustomize",
},
}
res, err := service.GetAppDetails(t.Context(), q)
require.NoError(t, err)
assert.Equal(t, "Kustomize", res.Type)
}
func TestGetHelmCharts(t *testing.T) {
service := newService(t, "../..")
res, err := service.GetHelmCharts(t.Context(), &apiclient.HelmChartsRequest{Repo: &v1alpha1.Repository{}})

View file

@ -541,10 +541,6 @@ func (s *Server) GetManifests(ctx context.Context, q *application.ApplicationMan
return fmt.Errorf("error getting kustomize settings: %w", err)
}
kustomizeOptions, err := kustomizeSettings.GetOptions(source)
if err != nil {
return fmt.Errorf("error getting kustomize settings options: %w", err)
}
installationID, err := s.settingsMgr.GetInstallationID()
if err != nil {
return fmt.Errorf("error getting installation ID: %w", err)
@ -574,7 +570,7 @@ func (s *Server) GetManifests(ctx context.Context, q *application.ApplicationMan
Namespace: a.Spec.Destination.Namespace,
ApplicationSource: &source,
Repos: repos,
KustomizeOptions: kustomizeOptions,
KustomizeOptions: kustomizeSettings,
KubeVersion: serverVersion,
ApiVersions: argo.APIResourcesToStrings(apiResources, true),
HelmRepoCreds: helmRepoCreds,
@ -686,10 +682,6 @@ func (s *Server) GetManifestsWithFiles(stream application.ApplicationService_Get
if err != nil {
return fmt.Errorf("error getting kustomize settings: %w", err)
}
kustomizeOptions, err := kustomizeSettings.GetOptions(a.Spec.GetSource())
if err != nil {
return fmt.Errorf("error getting kustomize settings options: %w", err)
}
req := &apiclient.ManifestRequest{
Repo: repo,
@ -699,7 +691,7 @@ func (s *Server) GetManifestsWithFiles(stream application.ApplicationService_Get
Namespace: a.Spec.Destination.Namespace,
ApplicationSource: &source,
Repos: helmRepos,
KustomizeOptions: kustomizeOptions,
KustomizeOptions: kustomizeSettings,
KubeVersion: serverVersion,
ApiVersions: argo.APIResourcesToStrings(apiResources, true),
HelmRepoCreds: helmCreds,
@ -825,15 +817,11 @@ func (s *Server) Get(ctx context.Context, q *application.ApplicationQuery) (*v1a
if err != nil {
return fmt.Errorf("error getting trackingMethod from settings: %w", err)
}
kustomizeOptions, err := kustomizeSettings.GetOptions(a.Spec.GetSource())
if err != nil {
return fmt.Errorf("error getting kustomize settings options: %w", err)
}
_, err = client.GetAppDetails(ctx, &apiclient.RepoServerAppDetailsQuery{
Repo: repo,
Source: &source,
AppName: appName,
KustomizeOptions: kustomizeOptions,
KustomizeOptions: kustomizeSettings,
Repos: helmRepos,
NoCache: true,
TrackingMethod: trackingMethod,

View file

@ -382,10 +382,6 @@ func (s *Server) GetAppDetails(ctx context.Context, q *repositorypkg.RepoAppDeta
if err != nil {
return nil, err
}
kustomizeOptions, err := kustomizeSettings.GetOptions(*q.Source)
if err != nil {
return nil, err
}
helmOptions, err := s.settings.GetHelmSettings()
if err != nil {
return nil, err
@ -404,7 +400,7 @@ func (s *Server) GetAppDetails(ctx context.Context, q *repositorypkg.RepoAppDeta
Repo: repo,
Source: q.Source,
Repos: helmRepos,
KustomizeOptions: kustomizeOptions,
KustomizeOptions: kustomizeSettings,
HelmOptions: helmOptions,
AppName: q.AppName,
RefSources: refSources,

View file

@ -464,3 +464,9 @@ func (c *Context) Sources(sources []v1alpha1.ApplicationSource) *Context {
c.sources = sources
return c
}
func (c *Context) RegisterKustomizeVersion(version, path string) *Context {
c.t.Helper()
require.NoError(c.t, fixture.RegisterKustomizeVersion(version, path))
return c
}

View file

@ -64,6 +64,13 @@ func SyncStatusIs(expected v1alpha1.SyncStatusCode) Expectation {
}
}
func HydrationPhaseIs(expected v1alpha1.HydrateOperationPhase) Expectation {
return func(c *Consequences) (state, string) {
actual := c.app().Status.SourceHydrator.CurrentOperation.Phase
return simple(actual == expected, fmt.Sprintf("hydration phase to be %s, is %s", expected, actual))
}
}
func Condition(conditionType v1alpha1.ApplicationConditionType, conditionMessage string) Expectation {
return func(c *Consequences) (state, string) {
got := c.app().Status.Conditions

View file

@ -414,6 +414,13 @@ func updateGenericConfigMap(name string, updater func(cm *corev1.ConfigMap) erro
return nil
}
func RegisterKustomizeVersion(version, path string) error {
return updateSettingConfigMap(func(cm *corev1.ConfigMap) error {
cm.Data["kustomize.version."+version] = path
return nil
})
}
func SetEnableManifestGeneration(val map[v1alpha1.ApplicationSourceType]bool) error {
return updateSettingConfigMap(func(cm *corev1.ConfigMap) error {
for k, v := range val {

View file

@ -100,3 +100,30 @@ func TestAddingApp(t *testing.T) {
Then().
Expect(DoesNotExist())
}
func TestKustomizeVersionOverride(t *testing.T) {
Given(t).
Name("test-kustomize-version-override").
DrySourcePath("kustomize-with-version-override").
DrySourceRevision("HEAD").
SyncSourcePath("kustomize-with-version-override").
SyncSourceBranch("env/test").
When().
// Skip validation, otherwise app creation will fail on the unsupported kustomize version.
CreateApp("--validate=false").
Refresh(RefreshTypeNormal).
Then().
// Expect a failure at first because the kustomize version is not supported.
Expect(HydrationPhaseIs(HydrateOperationPhaseFailed)).
// Now register the kustomize version override and try again.
Given().
RegisterKustomizeVersion("v1.2.3", "kustomize").
When().
// Hard refresh so we don't use the cached error.
Refresh(RefreshTypeHard).
Wait("--hydrated").
Sync().
Then().
Expect(OperationPhaseIs(OperationSucceeded)).
Expect(SyncStatusIs(SyncStatusCodeSynced))
}

View file

@ -0,0 +1,2 @@
kustomize:
version: v1.2.3

View file

@ -0,0 +1,20 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-deployment
spec:
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: my-container
image: my-image:latest
ports:
- containerPort: 80
imagePullSecrets:
- name: my-registry-secret

View file

@ -0,0 +1,2 @@
resources:
- deployment.yaml

View file

@ -774,14 +774,6 @@ func verifyGenerateManifests(
})
continue
}
kustomizeOptions, err := kustomizeSettings.GetOptions(source)
if err != nil {
conditions = append(conditions, argoappv1.ApplicationCondition{
Type: argoappv1.ApplicationConditionInvalidSpecError,
Message: fmt.Sprintf("Error getting Kustomize options: %v", err),
})
continue
}
installationID, err := settingsMgr.GetInstallationID()
if err != nil {
conditions = append(conditions, argoappv1.ApplicationCondition{
@ -841,7 +833,7 @@ func verifyGenerateManifests(
Namespace: app.Spec.Destination.Namespace,
ApplicationSource: &source,
AppLabelKey: appLabelKey,
KustomizeOptions: kustomizeOptions,
KustomizeOptions: kustomizeSettings,
KubeVersion: kubeVersion,
ApiVersions: apiVersions,
HelmOptions: helmOptions,

View file

@ -0,0 +1,2 @@
kustomize:
version: v1.2.3

View file

@ -0,0 +1,20 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-deployment
spec:
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: my-container
image: my-image:latest
ports:
- containerPort: 80
imagePullSecrets:
- name: my-registry-secret

View file

@ -0,0 +1,2 @@
resources:
- deployment.yaml

View file

@ -66,14 +66,6 @@ func (svc *argoCDService) GetCommitMetadata(ctx context.Context, repoURL string,
}, nil
}
func (svc *argoCDService) getKustomizeOptions(source *v1alpha1.ApplicationSource) (*v1alpha1.KustomizeOptions, error) {
kustomizeSettings, err := svc.settingsMgr.GetKustomizeSettings()
if err != nil {
return nil, err
}
return kustomizeSettings.GetOptions(*source)
}
func (svc *argoCDService) GetAppDetails(ctx context.Context, app *v1alpha1.Application) (*shared.AppDetail, error) {
appSource := app.Spec.GetSourcePtrByIndex(0)
@ -86,7 +78,7 @@ func (svc *argoCDService) GetAppDetails(ctx context.Context, app *v1alpha1.Appli
if err != nil {
return nil, err
}
kustomizeOptions, err := svc.getKustomizeOptions(appSource)
kustomizeOptions, err := svc.settingsMgr.GetKustomizeSettings()
if err != nil {
return nil, err
}

View file

@ -216,22 +216,6 @@ type HelmRepoCredentials struct {
KeySecret *corev1.SecretKeySelector `json:"keySecret,omitempty"`
}
// KustomizeVersion holds information about additional Kustomize version
type KustomizeVersion struct {
// Name holds Kustomize version name
Name string
// Path holds corresponding binary path
Path string
// BuildOptions that are specific to Kustomize version
BuildOptions string
}
// KustomizeSettings holds kustomize settings
type KustomizeSettings struct {
BuildOptions string
Versions []KustomizeVersion
}
var (
ByClusterURLIndexer = "byClusterURL"
byClusterURLIndexerFunc = func(obj any) ([]string, error) {
@ -290,29 +274,39 @@ var (
}
)
func (ks *KustomizeSettings) GetOptions(source v1alpha1.ApplicationSource) (*v1alpha1.KustomizeOptions, error) {
binaryPath := ""
buildOptions := ""
// KustomizeVersionNotRegisteredError is an error type that indicates a requested Kustomize version is not registered in
// the Kustomize options in argocd-cm.
type KustomizeVersionNotRegisteredError struct {
// Version is the Kustomize version that is not registered
Version string
}
func (e KustomizeVersionNotRegisteredError) Error() string {
return fmt.Sprintf("kustomize version %s is not registered", e.Version)
}
// GetKustomizeBinaryPath returns the path to the kustomize binary based on the provided KustomizeOptions and ApplicationSource.
func GetKustomizeBinaryPath(ks *v1alpha1.KustomizeOptions, source v1alpha1.ApplicationSource) (string, error) {
if ks == nil {
// No versions or binary path specified, stick with defaults.
return "", nil
}
if ks.BinaryPath != "" { // nolint:staticcheck // BinaryPath is deprecated, but still supported for backward compatibility
log.Warn("kustomizeOptions.binaryPath is deprecated, use KustomizeOptions.versions instead")
// nolint:staticcheck // BinaryPath is deprecated, but if it's set, we'll use it to ensure backward compatibility
return ks.BinaryPath, nil
}
if source.Kustomize != nil && source.Kustomize.Version != "" {
for _, ver := range ks.Versions {
if ver.Name == source.Kustomize.Version {
// add version specific path and build options
binaryPath = ver.Path
buildOptions = ver.BuildOptions
break
return ver.Path, nil
}
}
if binaryPath == "" {
return nil, fmt.Errorf("kustomize version %s is not registered", source.Kustomize.Version)
}
} else {
// add build options for the default version
buildOptions = ks.BuildOptions
return "", KustomizeVersionNotRegisteredError{Version: source.Kustomize.Version}
}
return &v1alpha1.KustomizeOptions{
BuildOptions: buildOptions,
BinaryPath: binaryPath,
}, nil
return "", nil
}
// Credentials for accessing a Git repository
@ -1153,14 +1147,14 @@ func (mgr *SettingsManager) GetHelmSettings() (*v1alpha1.HelmOptions, error) {
}
// GetKustomizeSettings loads the kustomize settings from argocd-cm ConfigMap
func (mgr *SettingsManager) GetKustomizeSettings() (*KustomizeSettings, error) {
func (mgr *SettingsManager) GetKustomizeSettings() (*v1alpha1.KustomizeOptions, error) {
argoCDCM, err := mgr.getConfigMap()
if err != nil {
return nil, fmt.Errorf("error retrieving argocd-cm: %w", err)
}
kustomizeVersionsMap := map[string]KustomizeVersion{}
kustomizeVersionsMap := map[string]v1alpha1.KustomizeVersion{}
buildOptions := map[string]string{}
settings := &KustomizeSettings{}
settings := &v1alpha1.KustomizeOptions{}
// extract build options for the default version
if options, ok := argoCDCM.Data[kustomizeBuildOptionsKey]; ok {
@ -1200,12 +1194,12 @@ func (mgr *SettingsManager) GetKustomizeSettings() (*KustomizeSettings, error) {
return settings, nil
}
func addKustomizeVersion(prefix, name, path string, kvMap map[string]KustomizeVersion) error {
func addKustomizeVersion(prefix, name, path string, kvMap map[string]v1alpha1.KustomizeVersion) error {
version := name[len(prefix)+1:]
if _, ok := kvMap[version]; ok {
return fmt.Errorf("found duplicate kustomize version: %s", version)
}
kvMap[version] = KustomizeVersion{
kvMap[version] = v1alpha1.KustomizeVersion{
Name: version,
Path: path,
}

View file

@ -713,7 +713,7 @@ func TestSettingsManager_GetKustomizeBuildOptions(t *testing.T) {
require.NoError(t, err)
assert.Equal(t, "foo", options.BuildOptions)
assert.Equal(t, []KustomizeVersion{{Name: "v3.2.1", Path: "somePath"}}, options.Versions)
assert.Equal(t, []v1alpha1.KustomizeVersion{{Name: "v3.2.1", Path: "somePath"}}, options.Versions)
})
t.Run("Kustomize settings per-version", func(t *testing.T) {
@ -731,15 +731,15 @@ func TestSettingsManager_GetKustomizeBuildOptions(t *testing.T) {
require.NoError(t, err)
assert.Equal(t, "--global true", got.BuildOptions)
want := &KustomizeSettings{
want := &v1alpha1.KustomizeOptions{
BuildOptions: "--global true",
Versions: []KustomizeVersion{
Versions: []v1alpha1.KustomizeVersion{
{Name: "v3.2.1", Path: "/path_3.2.1"},
{Name: "v3.2.3", Path: "/path_3.2.3", BuildOptions: "--options v3.2.3"},
{Name: "v3.2.4", Path: "/path_3.2.4", BuildOptions: "--options v3.2.4"},
},
}
sortVersionsByName := func(versions []KustomizeVersion) {
sortVersionsByName := func(versions []v1alpha1.KustomizeVersion) {
sort.Slice(versions, func(i, j int) bool {
return versions[i].Name > versions[j].Name
})
@ -814,10 +814,10 @@ func TestSettingsManager_GetEventLabelKeys(t *testing.T) {
}
}
func TestKustomizeSettings_GetOptions(t *testing.T) {
settings := KustomizeSettings{
func Test_GetKustomizeBinaryPath(t *testing.T) {
ko := &v1alpha1.KustomizeOptions{
BuildOptions: "--opt1 val1",
Versions: []KustomizeVersion{
Versions: []v1alpha1.KustomizeVersion{
{Name: "v1", Path: "path_v1"},
{Name: "v2", Path: "path_v2"},
{Name: "v3", Path: "path_v3", BuildOptions: "--opt2 val2"},
@ -825,35 +825,42 @@ func TestKustomizeSettings_GetOptions(t *testing.T) {
}
t.Run("VersionDoesNotExist", func(t *testing.T) {
_, err := settings.GetOptions(v1alpha1.ApplicationSource{
_, err := GetKustomizeBinaryPath(ko, v1alpha1.ApplicationSource{
Kustomize: &v1alpha1.ApplicationSourceKustomize{Version: "v4"},
})
require.Error(t, err)
})
t.Run("DefaultBuildOptions", func(t *testing.T) {
ver, err := settings.GetOptions(v1alpha1.ApplicationSource{})
ver, err := GetKustomizeBinaryPath(ko, v1alpha1.ApplicationSource{})
require.NoError(t, err)
assert.Empty(t, ver.BinaryPath)
assert.Equal(t, "--opt1 val1", ver.BuildOptions)
assert.Empty(t, ver)
})
t.Run("VersionExists", func(t *testing.T) {
ver, err := settings.GetOptions(v1alpha1.ApplicationSource{
ver, err := GetKustomizeBinaryPath(ko, v1alpha1.ApplicationSource{
Kustomize: &v1alpha1.ApplicationSourceKustomize{Version: "v2"},
})
require.NoError(t, err)
assert.Equal(t, "path_v2", ver.BinaryPath)
assert.Empty(t, ver.BuildOptions)
assert.Equal(t, "path_v2", ver)
})
t.Run("VersionExistsWithBuildOption", func(t *testing.T) {
ver, err := settings.GetOptions(v1alpha1.ApplicationSource{
ver, err := GetKustomizeBinaryPath(ko, v1alpha1.ApplicationSource{
Kustomize: &v1alpha1.ApplicationSourceKustomize{Version: "v3"},
})
require.NoError(t, err)
assert.Equal(t, "path_v3", ver.BinaryPath)
assert.Equal(t, "--opt2 val2", ver.BuildOptions)
assert.Equal(t, "path_v3", ver)
})
t.Run("ExplicitVersionSet", func(t *testing.T) {
// nolint:staticcheck // test for backwards compatibility with deprecated field
ko.BinaryPath = "custom_path"
ver, err := GetKustomizeBinaryPath(ko, v1alpha1.ApplicationSource{
Kustomize: &v1alpha1.ApplicationSourceKustomize{Version: "v3"},
})
require.NoError(t, err)
assert.Equal(t, "custom_path", ver)
})
}