diff --git a/assets/swagger.json b/assets/swagger.json index ee979f520412f..0e34f71ae8eea 100644 --- a/assets/swagger.json +++ b/assets/swagger.json @@ -4367,6 +4367,7 @@ "type": "boolean" }, "configManagementPlugins": { + "description": "Deprecated: use sidecar plugins instead.", "type": "array", "items": { "$ref": "#/definitions/v1alpha1ConfigManagementPlugin" diff --git a/cmd/argocd/commands/admin/settings.go b/cmd/argocd/commands/admin/settings.go index 3a3f04ecc5fb5..73363b10145ae 100644 --- a/cmd/argocd/commands/admin/settings.go +++ b/cmd/argocd/commands/admin/settings.go @@ -233,13 +233,6 @@ var validatorsByGroup = map[string]settingValidator{ _, err := manager.GetGoogleAnalytics() return "", err }), - "plugins": func(manager *settings.SettingsManager) (string, error) { - plugins, err := manager.GetConfigManagementPlugins() - if err != nil { - return "", err - } - return fmt.Sprintf("%d plugins", len(plugins)), nil - }, "kustomize": func(manager *settings.SettingsManager) (string, error) { opts, err := manager.GetKustomizeSettings() if err != nil { diff --git a/cmd/argocd/commands/admin/settings_test.go b/cmd/argocd/commands/admin/settings_test.go index 696387d0e01fc..94f80667b8a6e 100644 --- a/cmd/argocd/commands/admin/settings_test.go +++ b/cmd/argocd/commands/admin/settings_test.go @@ -151,13 +151,6 @@ clientSecret: aaaabbbbccccddddeee`, }, containsSummary: "Dex is configured ('url' field is missing)", }, - "Plugins_ValidConfig": { - validator: "plugins", - data: map[string]string{ - "configManagementPlugins": `[{"name": "test1"}, {"name": "test2"}]`, - }, - containsSummary: "2 plugins", - }, "Kustomize_ModifiedOptions": { validator: "kustomize", containsSummary: "default options", diff --git a/cmd/argocd/commands/app.go b/cmd/argocd/commands/app.go index 995a559ce402d..dd245df71784e 100644 --- a/cmd/argocd/commands/app.go +++ b/cmd/argocd/commands/app.go @@ -845,8 +845,8 @@ func targetObjects(resources []*argoappv1.ResourceDiff) ([]*unstructured.Unstruc } func getLocalObjects(ctx context.Context, app *argoappv1.Application, proj *argoappv1.AppProject, local, localRepoRoot, appLabelKey, kubeVersion string, apiVersions []string, kustomizeOptions *argoappv1.KustomizeOptions, - configManagementPlugins []*argoappv1.ConfigManagementPlugin, trackingMethod string) []*unstructured.Unstructured { - manifestStrings := getLocalObjectsString(ctx, app, proj, local, localRepoRoot, appLabelKey, kubeVersion, apiVersions, kustomizeOptions, configManagementPlugins, trackingMethod) + trackingMethod string) []*unstructured.Unstructured { + manifestStrings := getLocalObjectsString(ctx, app, proj, local, localRepoRoot, appLabelKey, kubeVersion, apiVersions, kustomizeOptions, trackingMethod) objs := make([]*unstructured.Unstructured, len(manifestStrings)) for i := range manifestStrings { obj := unstructured.Unstructured{} @@ -858,7 +858,7 @@ func getLocalObjects(ctx context.Context, app *argoappv1.Application, proj *argo } func getLocalObjectsString(ctx context.Context, app *argoappv1.Application, proj *argoappv1.AppProject, local, localRepoRoot, appLabelKey, kubeVersion string, apiVersions []string, kustomizeOptions *argoappv1.KustomizeOptions, - configManagementPlugins []*argoappv1.ConfigManagementPlugin, trackingMethod string) []string { + trackingMethod string) []string { source := app.Spec.GetSource() res, err := repository.GenerateManifests(ctx, local, localRepoRoot, source.TargetRevision, &repoapiclient.ManifestRequest{ Repo: &argoappv1.Repository{Repo: source.RepoURL}, @@ -869,7 +869,6 @@ func getLocalObjectsString(ctx context.Context, app *argoappv1.Application, proj KustomizeOptions: kustomizeOptions, KubeVersion: kubeVersion, ApiVersions: apiVersions, - Plugins: configManagementPlugins, TrackingMethod: trackingMethod, ProjectName: proj.Name, ProjectSourceRepos: proj.Spec.SourceRepos, @@ -991,7 +990,7 @@ func NewApplicationDiffCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co } } proj := getProject(c, clientOpts, ctx, app.Spec.Project) - foundDiffs := findandPrintDiff(ctx, app, proj.Project, resources, argoSettings, appName, diffOption) + foundDiffs := findandPrintDiff(ctx, app, proj.Project, resources, argoSettings, diffOption) if foundDiffs && exitCode { os.Exit(1) } @@ -1019,13 +1018,13 @@ type DifferenceOption struct { } // findandPrintDiff ... Prints difference between application current state and state stored in git or locally, returns boolean as true if difference is found else returns false -func findandPrintDiff(ctx context.Context, app *argoappv1.Application, proj *argoappv1.AppProject, resources *application.ManagedResourcesResponse, argoSettings *settings.Settings, appName string, diffOptions *DifferenceOption) bool { +func findandPrintDiff(ctx context.Context, app *argoappv1.Application, proj *argoappv1.AppProject, resources *application.ManagedResourcesResponse, argoSettings *settings.Settings, diffOptions *DifferenceOption) bool { var foundDiffs bool liveObjs, err := cmdutil.LiveObjects(resources.Items) errors.CheckError(err) items := make([]objKeyLiveTarget, 0) if diffOptions.local != "" { - localObjs := groupObjsByKey(getLocalObjects(ctx, app, proj, diffOptions.local, diffOptions.localRepoRoot, argoSettings.AppLabelKey, diffOptions.cluster.Info.ServerVersion, diffOptions.cluster.Info.APIVersions, argoSettings.KustomizeOptions, argoSettings.ConfigManagementPlugins, argoSettings.TrackingMethod), liveObjs, app.Spec.Destination.Namespace) + localObjs := groupObjsByKey(getLocalObjects(ctx, app, proj, diffOptions.local, diffOptions.localRepoRoot, argoSettings.AppLabelKey, diffOptions.cluster.Info.ServerVersion, diffOptions.cluster.Info.APIVersions, argoSettings.KustomizeOptions, argoSettings.TrackingMethod), liveObjs, app.Spec.Destination.Namespace) items = groupObjsForDiff(resources, localObjs, items, argoSettings, app.InstanceName(argoSettings.ControllerNamespace)) } else if diffOptions.revision != "" { var unstructureds []*unstructured.Unstructured @@ -1690,7 +1689,7 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co argoio.Close(conn) proj := getProject(c, clientOpts, ctx, app.Spec.Project) - localObjsStrings = getLocalObjectsString(ctx, app, proj.Project, local, localRepoRoot, argoSettings.AppLabelKey, cluster.Info.ServerVersion, cluster.Info.APIVersions, argoSettings.KustomizeOptions, argoSettings.ConfigManagementPlugins, argoSettings.TrackingMethod) + localObjsStrings = getLocalObjectsString(ctx, app, proj.Project, local, localRepoRoot, argoSettings.AppLabelKey, cluster.Info.ServerVersion, cluster.Info.APIVersions, argoSettings.KustomizeOptions, argoSettings.TrackingMethod) errors.CheckError(err) diffOption.local = local diffOption.localRepoRoot = localRepoRoot @@ -1761,7 +1760,7 @@ func NewApplicationSyncCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co fmt.Printf("====== Previewing differences between live and desired state of application %s ======\n", appQualifiedName) proj := getProject(c, clientOpts, ctx, app.Spec.Project) - foundDiffs = findandPrintDiff(ctx, app, proj.Project, resources, argoSettings, appQualifiedName, diffOption) + foundDiffs = findandPrintDiff(ctx, app, proj.Project, resources, argoSettings, diffOption) if foundDiffs { if !diffChangesConfirm { yesno := cli.AskToProceed(fmt.Sprintf("Please review changes to application %s shown above. Do you want to continue the sync process? (y/n): ", appQualifiedName)) @@ -2374,7 +2373,7 @@ func NewApplicationManifestsCommand(clientOpts *argocdclient.ClientOptions) *cob errors.CheckError(err) proj := getProject(c, clientOpts, ctx, app.Spec.Project) - unstructureds = getLocalObjects(context.Background(), app, proj.Project, local, localRepoRoot, argoSettings.AppLabelKey, cluster.ServerVersion, cluster.Info.APIVersions, argoSettings.KustomizeOptions, argoSettings.ConfigManagementPlugins, argoSettings.TrackingMethod) + unstructureds = getLocalObjects(context.Background(), app, proj.Project, local, localRepoRoot, argoSettings.AppLabelKey, cluster.ServerVersion, cluster.Info.APIVersions, argoSettings.KustomizeOptions, argoSettings.TrackingMethod) } else if revision != "" { q := application.ApplicationManifestQuery{ Name: &appName, diff --git a/cmpserver/plugin/config_test.go b/cmpserver/plugin/config_test.go new file mode 100644 index 0000000000000..9e22dab1d3741 --- /dev/null +++ b/cmpserver/plugin/config_test.go @@ -0,0 +1,215 @@ +package plugin + +import ( + "fmt" + "os" + "path/filepath" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/argoproj/argo-cd/v2/common" +) + +func Test_IsDefined(t *testing.T) { + testCases := []struct { + name string + discover Discover + expected bool + }{ + { + name: "empty discover", + discover: Discover{}, + expected: false, + }, + { + name: "discover with find", + discover: Discover{ + Find: Find{ + Glob: "glob", + }, + }, + expected: true, + }, + { + name: "discover with fileName", + discover: Discover{ + FileName: "fileName", + }, + expected: true, + }, + { + name: "discover with empty command", + discover: Discover{ + Find: Find{ + Command: Command{ + Command: []string{}, + }, + }, + }, + expected: false, + }, + { + name: "discover with command", + discover: Discover{ + Find: Find{ + Command: Command{ + Command: []string{"command"}, + }, + }, + }, + expected: true, + }, + } + + for _, tc := range testCases { + tcc := tc + t.Run(tcc.name, func(t *testing.T) { + t.Parallel() + + actual := tcc.discover.IsDefined() + assert.Equal(t, tcc.expected, actual) + }) + } +} + +func Test_ReadPluginConfig(t *testing.T) { + testCases := []struct { + name string + fileContents string + expected *PluginConfig + expectedErr string + }{ + { + name: "empty metadata", + fileContents: ` +metadata: +`, + expected: nil, + expectedErr: "invalid plugin configuration file. metadata.name should be non-empty.", + }, + { + name: "empty metadata name", + fileContents: ` +metadata: + name: "" +`, + expected: nil, + expectedErr: "invalid plugin configuration file. metadata.name should be non-empty.", + }, + { + name: "invalid kind", + fileContents: ` +kind: invalid +metadata: + name: name +`, + expected: nil, + expectedErr: "invalid plugin configuration file. kind should be ConfigManagementPlugin, found invalid", + }, + { + name: "empty generate command", + fileContents: ` +kind: ConfigManagementPlugin +metadata: + name: name +`, + expected: nil, + expectedErr: "invalid plugin configuration file. spec.generate command should be non-empty", + }, + { + name: "valid config", + fileContents: ` +kind: ConfigManagementPlugin +metadata: + name: name +spec: + generate: + command: [command] +`, + expected: &PluginConfig{ + TypeMeta: v1.TypeMeta{ + Kind: ConfigManagementPluginKind, + }, + Metadata: v1.ObjectMeta{ + Name: "name", + }, + Spec: PluginConfigSpec{ + Generate: Command{ + Command: []string{"command"}, + }, + }, + }, + }, + } + + for _, tc := range testCases { + tcc := tc + t.Run(tcc.name, func(t *testing.T) { + t.Parallel() + // write test string to temporary file + tempDir := t.TempDir() + tempFile, err := os.Create(filepath.Join(tempDir, "plugin.yaml")) + require.NoError(t, err) + err = tempFile.Close() + require.NoError(t, err) + err = os.WriteFile(tempFile.Name(), []byte(tcc.fileContents), 0644) + require.NoError(t, err) + config, err := ReadPluginConfig(tempDir) + if tcc.expectedErr != "" { + assert.EqualError(t, err, tcc.expectedErr) + } else { + assert.NoError(t, err) + } + assert.Equal(t, tcc.expected, config) + }) + } +} + +func Test_PluginConfig_Address(t *testing.T) { + testCases := []struct { + name string + config *PluginConfig + expected string + }{ + { + name: "no version specified", + config: &PluginConfig{ + TypeMeta: v1.TypeMeta{ + Kind: ConfigManagementPluginKind, + }, + Metadata: v1.ObjectMeta{ + Name: "name", + }, + }, + expected: "name", + }, + { + name: "version specified", + config: &PluginConfig{ + TypeMeta: v1.TypeMeta{ + Kind: ConfigManagementPluginKind, + }, + Metadata: v1.ObjectMeta{ + Name: "name", + }, + Spec: PluginConfigSpec{ + Version: "version", + }, + }, + expected: "name-version", + }, + } + + for _, tc := range testCases { + tcc := tc + t.Run(tcc.name, func(t *testing.T) { + t.Parallel() + actual := tcc.config.Address() + expectedAddress := fmt.Sprintf("%s/%s.sock", common.GetPluginSockFilePath(), tcc.expected) + assert.Equal(t, expectedAddress, actual) + }) + } +} diff --git a/controller/state.go b/controller/state.go index c4b54b5c32b0e..9e6bdf9e44d09 100644 --- a/controller/state.go +++ b/controller/state.go @@ -128,19 +128,11 @@ func (m *appStateManager) getRepoObjs(app *v1alpha1.Application, sources []v1alp return nil, nil, err } - plugins, err := m.settingsMgr.GetConfigManagementPlugins() - if err != nil { - return nil, nil, err - } enabledSourceTypes, err := m.settingsMgr.GetEnabledSourceTypes() if err != nil { return nil, nil, err } ts.AddCheckpoint("plugins_ms") - tools := make([]*v1alpha1.ConfigManagementPlugin, len(plugins)) - for i := range plugins { - tools[i] = &plugins[i] - } kustomizeSettings, err := m.settingsMgr.GetKustomizeSettings() if err != nil { @@ -198,7 +190,6 @@ func (m *appStateManager) getRepoObjs(app *v1alpha1.Application, sources []v1alp AppName: app.InstanceName(m.namespace), Namespace: app.Spec.Destination.Namespace, ApplicationSource: &source, - Plugins: tools, KustomizeOptions: kustomizeOptions, KubeVersion: serverVersion, ApiVersions: argo.APIResourcesToStrings(apiResources, true), diff --git a/docs/operator-manual/config-management-plugins.md b/docs/operator-manual/config-management-plugins.md index 792cd7ca53a54..8e8f05594d25b 100644 --- a/docs/operator-manual/config-management-plugins.md +++ b/docs/operator-manual/config-management-plugins.md @@ -18,18 +18,6 @@ The following sections will describe how to create, install, and use plugins. Ch ## Installing a config management plugin -There are two ways to install a Config Management Plugin: - - * **Sidecar plugin** - - This is a good option for a more complex plugin that would clutter the Argo CD ConfigMap. A copy of the repository is - sent to the sidecar container as a tarball and processed individually per application. - - * **ConfigMap plugin** (**this method is deprecated and will be removed in a future - version**) - - The repo-server container will run your plugin's commands. - ### Sidecar plugin An operator can configure a plugin tool via a sidecar to repo-server. The following changes are required to configure a new plugin: @@ -216,45 +204,11 @@ volumes: 2. Make sure that sidecar container is running as user 999. 3. Make sure that plugin configuration file is present at `/home/argocd/cmp-server/config/plugin.yaml`. It can either be volume mapped via configmap or baked into image. -### ConfigMap plugin - -!!! warning "Deprecated" - ConfigMap plugins are deprecated and will no longer be supported in 2.7. - -The following changes are required to configure a new plugin: - -1. Make sure required binaries are available in `argocd-repo-server` pod. The binaries can be added via volume mounts or - using a custom image (see [custom_tools](../operator-manual/custom_tools.md) for examples of both). -2. Register a new plugin in `argocd-cm` ConfigMap: - - data: - configManagementPlugins: | - - name: pluginName - init: # Optional command to initialize application source directory - command: ["sample command"] - args: ["sample args"] - generate: # Command to generate manifests YAML - command: ["sample command"] - args: ["sample args"] - lockRepo: true # Defaults to false. See below. - - The `generate` command must print a valid YAML or JSON stream to stdout. Both `init` and `generate` commands are executed inside the application source directory or in `path` when specified for the app. - -3. [Create an Application which uses your new CMP](#using-a-cmp). - -More CMP examples are available in [argocd-example-apps](https://github.com/argoproj/argocd-example-apps/tree/master/plugins). - -!!!note "Repository locking" - If your plugin makes use of `git` (e.g. `git crypt`), it is advised to set - `lockRepo` to `true` so that your plugin will have exclusive access to the - repository at the time it is executed. Otherwise, two applications synced - at the same time may result in a race condition and sync failure. - ### Using environment variables in your plugin Plugin commands have access to -1. The system environment variables (of the repo-server container for argocd-cm plugins or of the sidecar for sidecar plugins) +1. The system environment variables of the sidecar 2. [Standard build environment variables](../user-guide/build-environment.md) 3. Variables in the Application spec (References to system and build variables will get interpolated in the variables' values): @@ -268,19 +222,12 @@ Plugin commands have access to value: bar - name: REV value: test-$ARGOCD_APP_REVISION - - !!! note - The `discover.find.command` command only has access to the above environment starting with v2.4. Before reaching the `init.command`, `generate.command`, and `discover.find.command` commands, Argo CD prefixes all user-supplied environment variables (#3 above) with `ARGOCD_ENV_`. This prevents users from directly setting potentially-sensitive environment variables. - - If your plugin was written before 2.4 and depends on user-supplied environment variables, then you will need to update - your plugin's behavior to work with 2.4. If you use a third-party plugin, make sure they explicitly advertise support - for 2.4. -4. (Starting in v2.6) Parameters in the Application spec: +4. Parameters in the Application spec: apiVersion: argoproj.io/v1alpha1 kind: Application @@ -327,14 +274,7 @@ Plugin commands have access to ## Using a config management plugin with an Application -If your CMP is defined in the `argocd-cm` ConfigMap, you can create a new Application using the CLI. Replace -`` with the name configured in `argocd-cm`. - -```bash -argocd app create --config-management-plugin -``` - -If your CMP is defined as a sidecar, you must manually define the Application manifest. You may leave the `name` field +You may leave the `name` field empty in the `plugin` section for the plugin to be automatically matched with the Application based on its discovery rules. If you do mention the name make sure it is either `-` if version is mentioned in the `ConfigManagementPlugin` spec or else just ``. When name is explicitly specified only that particular plugin will be used iff its discovery pattern/command matches the provided application repo. @@ -352,7 +292,6 @@ spec: targetRevision: HEAD path: guestbook plugin: - # For either argocd-cm- or sidecar-installed CMPs, you can pass environment variables to the CMP. env: - name: FOO value: bar @@ -365,7 +304,7 @@ If you don't need to set any environment variables, you can set an empty plugin ``` !!! important - If your sidecar CMP command runs too long, the command will be killed, and the UI will show an error. The CMP server + If your CMP command runs too long, the command will be killed, and the UI will show an error. The CMP server respects the timeouts set by the `server.repo.server.timeout.seconds` and `controller.repo.server.timeout.seconds` items in `argocd-cm`. Increase their values from the default of 60s. diff --git a/docs/operator-manual/upgrading/2.7-2.8.md b/docs/operator-manual/upgrading/2.7-2.8.md index 58c5098982246..f8db7f31cbae4 100644 --- a/docs/operator-manual/upgrading/2.7-2.8.md +++ b/docs/operator-manual/upgrading/2.7-2.8.md @@ -1,5 +1,12 @@ # v2.7 to 2.8 +## Support dropped for argocd-cm plugins + +Config Management Plugins installed via the argocd-cm ConfigMap will not work starting with v2.8. + +See the [migration guide](https://argo-cd.readthedocs.io/en/stable/operator-manual/config-management-plugins/#migrating-from-argocd-cm-plugins) +to upgrade your plugin. + ## Tini as entrypoint With the 2.8 release `entrypoint.sh` will be removed from the containers, @@ -15,4 +22,4 @@ properly before moving to 2.8. Prior to `v2.8`, the `List` endpoint on the `ClusterService` did **not** filter clusters when responding, despite accepting query parameters. This bug has been addressed, and query parameters are now taken into account to filter the -resulting list of clusters. \ No newline at end of file +resulting list of clusters. diff --git a/docs/user-guide/commands/argocd_admin_settings_validate.md b/docs/user-guide/commands/argocd_admin_settings_validate.md index bc839546a1d0b..61aee8a4e1f98 100644 --- a/docs/user-guide/commands/argocd_admin_settings_validate.md +++ b/docs/user-guide/commands/argocd_admin_settings_validate.md @@ -24,7 +24,7 @@ argocd admin settings validate --group accounts --group plugins --load-cluster-s ### Options ``` - --group stringArray Optional list of setting groups that have to be validated ( one of: accounts, general, kustomize, plugins, repositories, resource-overrides) + --group stringArray Optional list of setting groups that have to be validated ( one of: accounts, general, kustomize, repositories, resource-overrides) -h, --help help for validate ``` diff --git a/pkg/apiclient/settings/settings.pb.go b/pkg/apiclient/settings/settings.pb.go index 5fdb92a10f9f9..be5d129f6834f 100644 --- a/pkg/apiclient/settings/settings.pb.go +++ b/pkg/apiclient/settings/settings.pb.go @@ -84,9 +84,10 @@ type Settings struct { GoogleAnalytics *GoogleAnalyticsConfig `protobuf:"bytes,7,opt,name=googleAnalytics,proto3" json:"googleAnalytics,omitempty"` KustomizeOptions *v1alpha1.KustomizeOptions `protobuf:"bytes,8,opt,name=kustomizeOptions,proto3" json:"kustomizeOptions,omitempty"` // Help settings - Help *Help `protobuf:"bytes,9,opt,name=help,proto3" json:"help,omitempty"` - Plugins []*Plugin `protobuf:"bytes,10,rep,name=plugins,proto3" json:"plugins,omitempty"` - UserLoginsDisabled bool `protobuf:"varint,11,opt,name=userLoginsDisabled,proto3" json:"userLoginsDisabled,omitempty"` + Help *Help `protobuf:"bytes,9,opt,name=help,proto3" json:"help,omitempty"` + Plugins []*Plugin `protobuf:"bytes,10,rep,name=plugins,proto3" json:"plugins,omitempty"` + UserLoginsDisabled bool `protobuf:"varint,11,opt,name=userLoginsDisabled,proto3" json:"userLoginsDisabled,omitempty"` + // Deprecated: use sidecar plugins instead. ConfigManagementPlugins []*v1alpha1.ConfigManagementPlugin `protobuf:"bytes,12,rep,name=configManagementPlugins,proto3" json:"configManagementPlugins,omitempty"` KustomizeVersions []string `protobuf:"bytes,13,rep,name=kustomizeVersions,proto3" json:"kustomizeVersions,omitempty"` UiCssURL string `protobuf:"bytes,14,opt,name=uiCssURL,proto3" json:"uiCssURL,omitempty"` diff --git a/reposerver/apiclient/repository.pb.go b/reposerver/apiclient/repository.pb.go index 68967f0b9eac3..4c05248b87e16 100644 --- a/reposerver/apiclient/repository.pb.go +++ b/reposerver/apiclient/repository.pb.go @@ -36,14 +36,15 @@ type ManifestRequest struct { NoCache bool `protobuf:"varint,3,opt,name=noCache,proto3" json:"noCache,omitempty"` AppLabelKey string `protobuf:"bytes,4,opt,name=appLabelKey,proto3" json:"appLabelKey,omitempty"` // Name of the application for which the request is triggered - AppName string `protobuf:"bytes,5,opt,name=appName,proto3" json:"appName,omitempty"` - Namespace string `protobuf:"bytes,8,opt,name=namespace,proto3" json:"namespace,omitempty"` - ApplicationSource *v1alpha1.ApplicationSource `protobuf:"bytes,10,opt,name=applicationSource,proto3" json:"applicationSource,omitempty"` - Repos []*v1alpha1.Repository `protobuf:"bytes,11,rep,name=repos,proto3" json:"repos,omitempty"` - Plugins []*v1alpha1.ConfigManagementPlugin `protobuf:"bytes,12,rep,name=plugins,proto3" json:"plugins,omitempty"` - KustomizeOptions *v1alpha1.KustomizeOptions `protobuf:"bytes,13,opt,name=kustomizeOptions,proto3" json:"kustomizeOptions,omitempty"` - KubeVersion string `protobuf:"bytes,14,opt,name=kubeVersion,proto3" json:"kubeVersion,omitempty"` - ApiVersions []string `protobuf:"bytes,15,rep,name=apiVersions,proto3" json:"apiVersions,omitempty"` + AppName string `protobuf:"bytes,5,opt,name=appName,proto3" json:"appName,omitempty"` + Namespace string `protobuf:"bytes,8,opt,name=namespace,proto3" json:"namespace,omitempty"` + ApplicationSource *v1alpha1.ApplicationSource `protobuf:"bytes,10,opt,name=applicationSource,proto3" json:"applicationSource,omitempty"` + Repos []*v1alpha1.Repository `protobuf:"bytes,11,rep,name=repos,proto3" json:"repos,omitempty"` + // Deprecated: use sidecar plugins instead. + Plugins []*v1alpha1.ConfigManagementPlugin `protobuf:"bytes,12,rep,name=plugins,proto3" json:"plugins,omitempty"` + KustomizeOptions *v1alpha1.KustomizeOptions `protobuf:"bytes,13,opt,name=kustomizeOptions,proto3" json:"kustomizeOptions,omitempty"` + KubeVersion string `protobuf:"bytes,14,opt,name=kubeVersion,proto3" json:"kubeVersion,omitempty"` + ApiVersions []string `protobuf:"bytes,15,rep,name=apiVersions,proto3" json:"apiVersions,omitempty"` // Request to verify the signature when generating the manifests (only for Git repositories) VerifySignature bool `protobuf:"varint,16,opt,name=verifySignature,proto3" json:"verifySignature,omitempty"` HelmRepoCreds []*v1alpha1.RepoCreds `protobuf:"bytes,17,rep,name=helmRepoCreds,proto3" json:"helmRepoCreds,omitempty"` diff --git a/reposerver/repository/repository.go b/reposerver/repository/repository.go index f2939cda88533..bcc61a6cdd192 100644 --- a/reposerver/repository/repository.go +++ b/reposerver/repository/repository.go @@ -10,7 +10,6 @@ import ( "io/fs" "net/url" "os" - "os/exec" "path" "path/filepath" "regexp" @@ -56,7 +55,6 @@ import ( argopath "github.com/argoproj/argo-cd/v2/util/app/path" "github.com/argoproj/argo-cd/v2/util/argo" "github.com/argoproj/argo-cd/v2/util/cmp" - executil "github.com/argoproj/argo-cd/v2/util/exec" "github.com/argoproj/argo-cd/v2/util/git" "github.com/argoproj/argo-cd/v2/util/glob" "github.com/argoproj/argo-cd/v2/util/gpg" @@ -1340,28 +1338,14 @@ func GenerateManifests(ctx context.Context, appPath, repoRoot, revision string, k := kustomize.NewKustomizeApp(appPath, q.Repo.GetGitCreds(gitCredsStore), repoURL, kustomizeBinary) targetObjs, _, err = k.Build(q.ApplicationSource.Kustomize, q.KustomizeOptions, env) case v1alpha1.ApplicationSourceTypePlugin: - var plugin *v1alpha1.ConfigManagementPlugin - if q.ApplicationSource.Plugin != nil && q.ApplicationSource.Plugin.Name != "" { - plugin = findPlugin(q.Plugins, q.ApplicationSource.Plugin.Name) + pluginName := "" + if q.ApplicationSource.Plugin != nil { + pluginName = q.ApplicationSource.Plugin.Name } - if plugin != nil { - // argocd-cm deprecated plugin is being used - targetObjs, err = runConfigManagementPlugin(appPath, repoRoot, env, q, q.Repo.GetGitCreds(gitCredsStore), plugin) - log.WithFields(map[string]interface{}{ - "application": q.AppName, - "plugin": q.ApplicationSource.Plugin.Name, - }).Warnf(common.ConfigMapPluginDeprecationWarning) - } else { - // if the named plugin was not found in argocd-cm try sidecar plugin - pluginName := "" - if q.ApplicationSource.Plugin != nil { - pluginName = q.ApplicationSource.Plugin.Name - } - // if pluginName is provided it has to be `-` or just `` if plugin version is empty - targetObjs, err = runConfigManagementPluginSidecars(ctx, appPath, repoRoot, pluginName, env, q, q.Repo.GetGitCreds(gitCredsStore), opt.cmpTarDoneCh, opt.cmpTarExcludedGlobs) - if err != nil { - err = fmt.Errorf("plugin sidecar failed. %s", err.Error()) - } + // if pluginName is provided it has to be `-` or just `` if plugin version is empty + targetObjs, err = runConfigManagementPluginSidecars(ctx, appPath, repoRoot, pluginName, env, q, q.Repo.GetGitCreds(gitCredsStore), opt.cmpTarDoneCh, opt.cmpTarExcludedGlobs) + if err != nil { + err = fmt.Errorf("plugin sidecar failed. %s", err.Error()) } case v1alpha1.ApplicationSourceTypeDirectory: var directory *v1alpha1.ApplicationSourceDirectory @@ -1818,74 +1802,17 @@ func makeJsonnetVm(appPath string, repoRoot string, sourceJsonnet v1alpha1.Appli return vm, nil } -func runCommand(command v1alpha1.Command, path string, env []string) (string, error) { - if len(command.Command) == 0 { - return "", fmt.Errorf("Command is empty") - } - cmd := exec.Command(command.Command[0], append(command.Command[1:], command.Args...)...) - cmd.Env = env - cmd.Dir = path - return executil.Run(cmd) -} - -func findPlugin(plugins []*v1alpha1.ConfigManagementPlugin, name string) *v1alpha1.ConfigManagementPlugin { - for _, plugin := range plugins { - if plugin.Name == name { - return plugin - } - } - return nil -} - -func runConfigManagementPlugin(appPath, repoRoot string, envVars *v1alpha1.Env, q *apiclient.ManifestRequest, creds git.Creds, plugin *v1alpha1.ConfigManagementPlugin) ([]*unstructured.Unstructured, error) { - // Plugins can request to lock the complete repository when they need to - // use git client operations. - if plugin.LockRepo { - manifestGenerateLock.Lock(repoRoot) - defer manifestGenerateLock.Unlock(repoRoot) - } else { - concurrencyAllowed := isConcurrencyAllowed(appPath) - if !concurrencyAllowed { - manifestGenerateLock.Lock(appPath) - defer manifestGenerateLock.Unlock(appPath) - } - } - - env, err := getPluginEnvs(envVars, q, creds, false) - if err != nil { - return nil, err - } - - if plugin.Init != nil { - _, err := runCommand(*plugin.Init, appPath, env) - if err != nil { - return nil, err - } - } - out, err := runCommand(plugin.Generate, appPath, env) - if err != nil { - return nil, err - } - return kube.SplitYAML([]byte(out)) -} - -func getPluginEnvs(env *v1alpha1.Env, q *apiclient.ManifestRequest, creds git.Creds, remote bool) ([]string, error) { +func getPluginEnvs(env *v1alpha1.Env, q *apiclient.ManifestRequest, creds git.Creds) ([]string, error) { envVars := env.Environ() envVars = append(envVars, "KUBE_VERSION="+text.SemVer(q.KubeVersion)) envVars = append(envVars, "KUBE_API_VERSIONS="+strings.Join(q.ApiVersions, ",")) - return getPluginParamEnvs(envVars, q.ApplicationSource.Plugin, creds, remote) + return getPluginParamEnvs(envVars, q.ApplicationSource.Plugin, creds) } // getPluginParamEnvs gets environment variables for plugin parameter announcement generation. -func getPluginParamEnvs(envVars []string, plugin *v1alpha1.ApplicationSourcePlugin, creds git.Creds, remote bool) ([]string, error) { +func getPluginParamEnvs(envVars []string, plugin *v1alpha1.ApplicationSourcePlugin, creds git.Creds) ([]string, error) { env := envVars - // Local plugins need also to have access to the local environment variables. - // Remote sidecar plugins will use the environment in the sidecar - // container. - if !remote { - env = append(os.Environ(), envVars...) - } if creds != nil { closer, environ, err := creds.Environ() if err != nil { @@ -1922,12 +1849,12 @@ func getPluginParamEnvs(envVars []string, plugin *v1alpha1.ApplicationSourcePlug func runConfigManagementPluginSidecars(ctx context.Context, appPath, repoPath, pluginName string, envVars *v1alpha1.Env, q *apiclient.ManifestRequest, creds git.Creds, tarDoneCh chan<- bool, tarExcludedGlobs []string) ([]*unstructured.Unstructured, error) { // compute variables. - env, err := getPluginEnvs(envVars, q, creds, true) + env, err := getPluginEnvs(envVars, q, creds) if err != nil { return nil, err } - // detect config management plugin server (sidecar) + // detect config management plugin server conn, cmpClient, err := discovery.DetectConfigManagementPlugin(ctx, appPath, repoPath, pluginName, env, tarExcludedGlobs) if err != nil { return nil, err @@ -2173,7 +2100,7 @@ func populatePluginAppDetails(ctx context.Context, res *apiclient.RepoAppDetails fmt.Sprintf("ARGOCD_APP_SOURCE_TARGET_REVISION=%s", q.Source.TargetRevision), } - env, err := getPluginParamEnvs(envVars, q.Source.Plugin, creds, true) + env, err := getPluginParamEnvs(envVars, q.Source.Plugin, creds) if err != nil { return fmt.Errorf("failed to get env vars for plugin: %w", err) } diff --git a/reposerver/repository/repository.proto b/reposerver/repository/repository.proto index 8f40867c243c1..8e4b69000f7e1 100644 --- a/reposerver/repository/repository.proto +++ b/reposerver/repository/repository.proto @@ -18,6 +18,7 @@ message ManifestRequest { string namespace = 8; github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.ApplicationSource applicationSource = 10; repeated github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.Repository repos = 11; + // Deprecated: use sidecar plugins instead. repeated github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.ConfigManagementPlugin plugins = 12; github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.KustomizeOptions kustomizeOptions = 13; string kubeVersion = 14; diff --git a/reposerver/repository/repository_test.go b/reposerver/repository/repository_test.go index 0e53aa837d3ad..c13f7a365e909 100644 --- a/reposerver/repository/repository_test.go +++ b/reposerver/repository/repository_test.go @@ -1266,51 +1266,6 @@ func TestIdentifyAppSourceTypeByAppDirWithKustomizations(t *testing.T) { assert.Equal(t, argoappv1.ApplicationSourceTypeKustomize, sourceType) } -func TestRunCustomTool(t *testing.T) { - service := newService(".") - - res, err := service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{ - AppName: "test-app", - Namespace: "test-namespace", - ApplicationSource: &argoappv1.ApplicationSource{ - Plugin: &argoappv1.ApplicationSourcePlugin{ - Name: "test", - Env: argoappv1.Env{ - { - Name: "TEST_REVISION", - Value: "prefix-$ARGOCD_APP_REVISION", - }, - }, - }, - }, - Plugins: []*argoappv1.ConfigManagementPlugin{{ - Name: "test", - Generate: argoappv1.Command{ - Command: []string{"sh", "-c"}, - Args: []string{`echo "{\"kind\": \"FakeObject\", \"metadata\": { \"name\": \"$ARGOCD_APP_NAME\", \"namespace\": \"$ARGOCD_APP_NAMESPACE\", \"annotations\": {\"GIT_ASKPASS\": \"$GIT_ASKPASS\", \"GIT_USERNAME\": \"$GIT_USERNAME\", \"GIT_PASSWORD\": \"$GIT_PASSWORD\"}, \"labels\": {\"revision\": \"$ARGOCD_ENV_TEST_REVISION\"}}}"`}, - }, - }}, - Repo: &argoappv1.Repository{ - Username: "foo", Password: "bar", - }, - ProjectName: "something", - ProjectSourceRepos: []string{"*"}, - }) - - assert.NoError(t, err) - assert.Equal(t, 1, len(res.Manifests)) - - obj := &unstructured.Unstructured{} - assert.NoError(t, json.Unmarshal([]byte(res.Manifests[0]), obj)) - - assert.Equal(t, obj.GetName(), "test-app") - assert.Equal(t, obj.GetNamespace(), "test-namespace") - assert.Empty(t, obj.GetAnnotations()["GIT_USERNAME"]) - assert.Empty(t, obj.GetAnnotations()["GIT_PASSWORD"]) - // Git client is mocked, so the revision is always mock.Anything - assert.Equal(t, map[string]string{"revision": "prefix-mock.Anything"}, obj.GetLabels()) -} - func TestGenerateFromUTF16(t *testing.T) { q := apiclient.ManifestRequest{ Repo: &argoappv1.Repository{}, diff --git a/server/application/application.go b/server/application/application.go index 97fe50415ef45..ffd206b126b7d 100644 --- a/server/application/application.go +++ b/server/application/application.go @@ -402,10 +402,6 @@ func (s *Server) GetManifests(ctx context.Context, q *application.ApplicationMan return fmt.Errorf("error getting app instance label key from settings: %w", err) } - plugins, err := s.plugins() - if err != nil { - return fmt.Errorf("error getting plugins: %w", err) - } config, err := s.getApplicationClusterConfig(ctx, a) if err != nil { return fmt.Errorf("error getting application cluster config: %w", err) @@ -434,7 +430,6 @@ func (s *Server) GetManifests(ctx context.Context, q *application.ApplicationMan Namespace: a.Spec.Destination.Namespace, ApplicationSource: &source, Repos: helmRepos, - Plugins: plugins, KustomizeOptions: kustomizeOptions, KubeVersion: serverVersion, ApiVersions: argo.APIResourcesToStrings(apiResources, true), @@ -503,10 +498,6 @@ func (s *Server) GetManifestsWithFiles(stream application.ApplicationService_Get return fmt.Errorf("error getting app instance label key from settings: %w", err) } - plugins, err := s.plugins() - if err != nil { - return fmt.Errorf("error getting plugins: %w", err) - } config, err := s.getApplicationClusterConfig(ctx, a) if err != nil { return fmt.Errorf("error getting application cluster config: %w", err) @@ -537,7 +528,6 @@ func (s *Server) GetManifestsWithFiles(stream application.ApplicationService_Get Namespace: a.Spec.Destination.Namespace, ApplicationSource: &source, Repos: helmRepos, - Plugins: plugins, KustomizeOptions: kustomizeOptions, KubeVersion: serverVersion, ApiVersions: argo.APIResourcesToStrings(apiResources, true), @@ -1111,10 +1101,6 @@ func (s *Server) validateAndNormalizeApp(ctx context.Context, app *appv1.Applica return err } } - plugins, err := s.plugins() - if err != nil { - return fmt.Errorf("error getting plugins: %w", err) - } if err := argo.ValidateDestination(ctx, &app.Spec.Destination, s.db); err != nil { return status.Errorf(codes.InvalidArgument, "application destination spec for %s is invalid: %s", app.Name, err.Error()) @@ -1124,7 +1110,7 @@ func (s *Server) validateAndNormalizeApp(ctx context.Context, app *appv1.Applica if validate { conditions := make([]appv1.ApplicationCondition, 0) - condition, err := argo.ValidateRepo(ctx, app, s.repoClientset, s.db, plugins, s.kubectl, proj, s.settingsMgr) + condition, err := argo.ValidateRepo(ctx, app, s.repoClientset, s.db, s.kubectl, proj, s.settingsMgr) if err != nil { return fmt.Errorf("error validating the repo: %w", err) } @@ -2235,19 +2221,6 @@ func splitStatusPatch(patch []byte) ([]byte, []byte, error) { return nonStatusPatch, statusPatch, nil } -func (s *Server) plugins() ([]*appv1.ConfigManagementPlugin, error) { - plugins, err := s.settingsMgr.GetConfigManagementPlugins() - if err != nil { - return nil, fmt.Errorf("error getting config management plugin: %w", err) - } - tools := make([]*appv1.ConfigManagementPlugin, len(plugins)) - for i, p := range plugins { - p := p - tools[i] = &p - } - return tools, nil -} - func (s *Server) GetApplicationSyncWindows(ctx context.Context, q *application.ApplicationSyncWindowsQuery) (*application.ApplicationSyncWindowsResponse, error) { a, err := s.getApplicationEnforceRBACClient(ctx, rbacpolicy.ActionGet, q.GetAppNamespace(), q.GetName(), "") if err != nil { diff --git a/server/settings/settings.go b/server/settings/settings.go index 5dfd3597b569e..2f797d552f4ce 100644 --- a/server/settings/settings.go +++ b/server/settings/settings.go @@ -62,10 +62,6 @@ func (s *Server) Get(ctx context.Context, q *settingspkg.SettingsQuery) (*settin if err != nil { return nil, err } - plugins, err := s.plugins(ctx, false) - if err != nil { - return nil, err - } userLoginsDisabled := true accounts, err := s.mgr.GetAccounts() if err != nil { @@ -110,7 +106,6 @@ func (s *Server) Get(ctx context.Context, q *settingspkg.SettingsQuery) (*settin ChatText: help.ChatText, BinaryUrls: help.BinaryURLs, }, - Plugins: plugins, UserLoginsDisabled: userLoginsDisabled, KustomizeVersions: kustomizeVersions, UiCssURL: argoCDSettings.UiCssURL, @@ -121,15 +116,6 @@ func (s *Server) Get(ctx context.Context, q *settingspkg.SettingsQuery) (*settin } if sessionmgr.LoggedIn(ctx) || s.disableAuth { - configManagementPlugins, err := s.mgr.GetConfigManagementPlugins() - if err != nil { - return nil, err - } - tools := make([]*v1alpha1.ConfigManagementPlugin, len(configManagementPlugins)) - for i := range configManagementPlugins { - tools[i] = &configManagementPlugins[i] - } - set.ConfigManagementPlugins = tools set.UiBannerContent = argoCDSettings.UiBannerContent set.UiBannerURL = argoCDSettings.UiBannerURL set.UiBannerPermanent = argoCDSettings.UiBannerPermanent @@ -160,39 +146,29 @@ func (s *Server) Get(ctx context.Context, q *settingspkg.SettingsQuery) (*settin // GetPlugins returns a list of plugins func (s *Server) GetPlugins(ctx context.Context, q *settingspkg.SettingsQuery) (*settingspkg.SettingsPluginsResponse, error) { - plugins, err := s.plugins(ctx, true) + plugins, err := s.plugins(ctx) if err != nil { return nil, err } return &settingspkg.SettingsPluginsResponse{Plugins: plugins}, nil } -func (s *Server) plugins(ctx context.Context, includeV2Plugins bool) ([]*settingspkg.Plugin, error) { - in, err := s.mgr.GetConfigManagementPlugins() +func (s *Server) plugins(ctx context.Context) ([]*settingspkg.Plugin, error) { + closer, client, err := s.repoClient.NewRepoServerClient() if err != nil { - return nil, err - } - var out []*settingspkg.Plugin - for _, p := range in { - out = append(out, &settingspkg.Plugin{Name: p.Name}) + return nil, fmt.Errorf("error creating repo server client: %w", err) } + defer ioutil.Close(closer) - if includeV2Plugins { - closer, client, err := s.repoClient.NewRepoServerClient() - if err != nil { - return nil, fmt.Errorf("error creating repo server client: %w", err) - } - defer ioutil.Close(closer) - - pluginList, err := client.ListPlugins(ctx, &empty.Empty{}) - if err != nil { - return nil, fmt.Errorf("failed to list sidecar plugins from reposerver: %w", err) - } + pluginList, err := client.ListPlugins(ctx, &empty.Empty{}) + if err != nil { + return nil, fmt.Errorf("failed to list sidecar plugins from reposerver: %w", err) + } - if pluginList != nil && len(pluginList.Items) > 0 { - for _, p := range pluginList.Items { - out = append(out, &settingspkg.Plugin{Name: p.Name}) - } + var out []*settingspkg.Plugin + if pluginList != nil && len(pluginList.Items) > 0 { + for _, p := range pluginList.Items { + out = append(out, &settingspkg.Plugin{Name: p.Name}) } } diff --git a/server/settings/settings.proto b/server/settings/settings.proto index 932da5269d2d4..9f95c9433b545 100644 --- a/server/settings/settings.proto +++ b/server/settings/settings.proto @@ -28,6 +28,7 @@ message Settings { Help help = 9; repeated Plugin plugins = 10; bool userLoginsDisabled = 11; + // Deprecated: use sidecar plugins instead. repeated github.com.argoproj.argo_cd.v2.pkg.apis.application.v1alpha1.ConfigManagementPlugin configManagementPlugins = 12; repeated string kustomizeVersions = 13; string uiCssURL = 14; diff --git a/test/e2e/custom_tool_test.go b/test/e2e/custom_tool_test.go index f99129e2bee2f..4469931795332 100644 --- a/test/e2e/custom_tool_test.go +++ b/test/e2e/custom_tool_test.go @@ -2,6 +2,7 @@ package e2e import ( "os" + "path/filepath" "sort" "strings" "testing" @@ -22,21 +23,16 @@ import ( func TestCustomToolWithGitCreds(t *testing.T) { ctx := Given(t) ctx. - // path does not matter, we ignore it - ConfigManagementPlugin( - ConfigManagementPlugin{ - Name: Name(), - Generate: Command{ - Command: []string{"sh", "-c"}, - Args: []string{`echo "{\"kind\": \"ConfigMap\", \"apiVersion\": \"v1\", \"metadata\": { \"name\": \"$ARGOCD_APP_NAME\", \"namespace\": \"$ARGOCD_APP_NAMESPACE\", \"annotations\": {\"GitAskpass\": \"$GIT_ASKPASS\"}}}"`}, - }, - }, - ). + And(func() { + go startCMPServer(t, "./testdata/cmp-gitcreds") + time.Sleep(1 * time.Second) + t.Setenv("ARGOCD_BINARY_NAME", "argocd") + }). CustomCACertAdded(). // add the private repo with credentials HTTPSRepoURLAdded(true). RepoURLType(RepoURLTypeHTTPS). - Path("https-kustomize-base"). + Path("cmp-gitcreds"). When(). CreateApp(). Sync(). @@ -55,23 +51,18 @@ func TestCustomToolWithGitCreds(t *testing.T) { func TestCustomToolWithGitCredsTemplate(t *testing.T) { ctx := Given(t) ctx. - // path does not matter, we ignore it - ConfigManagementPlugin( - ConfigManagementPlugin{ - Name: Name(), - Generate: Command{ - Command: []string{"sh", "-c"}, - Args: []string{`echo "{\"kind\": \"ConfigMap\", \"apiVersion\": \"v1\", \"metadata\": { \"name\": \"$ARGOCD_APP_NAME\", \"namespace\": \"$ARGOCD_APP_NAMESPACE\", \"annotations\": {\"GitAskpass\": \"$GIT_ASKPASS\", \"GitUsername\": \"$GIT_USERNAME\", \"GitPassword\": \"$GIT_PASSWORD\"}}}"`}, - }, - }, - ). + And(func() { + go startCMPServer(t, "./testdata/cmp-gitcredstemplate") + time.Sleep(1 * time.Second) + t.Setenv("ARGOCD_BINARY_NAME", "argocd") + }). CustomCACertAdded(). // add the git creds template HTTPSCredentialsUserPassAdded(). // add the private repo without credentials HTTPSRepoURLAdded(false). RepoURLType(RepoURLTypeHTTPS). - Path("https-kustomize-base"). + Path("cmp-gitcredstemplate"). When(). CreateApp(). Sync(). @@ -100,24 +91,21 @@ func TestCustomToolWithGitCredsTemplate(t *testing.T) { func TestCustomToolWithEnv(t *testing.T) { ctx := Given(t) ctx. - // path does not matter, we ignore it - ConfigManagementPlugin( - ConfigManagementPlugin{ - Name: Name(), - Generate: Command{ - Command: []string{"sh", "-c"}, - Args: []string{`echo "{\"kind\": \"ConfigMap\", \"apiVersion\": \"v1\", \"metadata\": { \"name\": \"$ARGOCD_APP_NAME\", \"namespace\": \"$ARGOCD_APP_NAMESPACE\", \"annotations\": {\"Foo\": \"$ARGOCD_ENV_FOO\", \"KubeVersion\": \"$KUBE_VERSION\", \"KubeApiVersion\": \"$KUBE_API_VERSIONS\",\"Bar\": \"baz\"}}}"`}, - }, - }, - ). + And(func() { + go startCMPServer(t, "./testdata/cmp-fileName") + time.Sleep(1 * time.Second) + t.Setenv("ARGOCD_BINARY_NAME", "argocd") + }). // does not matter what the path is - Path("guestbook"). + Path("cmp-fileName"). When(). CreateFromFile(func(app *Application) { - app.Spec.GetSource().Plugin.Env = Env{{ - Name: "FOO", - Value: "bar", - }} + app.Spec.Source.Plugin = &ApplicationSourcePlugin{ + Env: Env{{ + Name: "FOO", + Value: "bar", + }}, + } }). Sync(). Then(). @@ -159,23 +147,21 @@ func TestCustomToolWithEnv(t *testing.T) { // make sure we can sync and diff with --local func TestCustomToolSyncAndDiffLocal(t *testing.T) { + testdataPath, err := filepath.Abs("testdata") + require.NoError(t, err) ctx := Given(t) + appPath := filepath.Join(testdataPath, "guestbook") ctx. - // path does not matter, we ignore it - ConfigManagementPlugin( - ConfigManagementPlugin{ - Name: Name(), - Generate: Command{ - Command: []string{"sh", "-c"}, - Args: []string{`echo "{\"kind\": \"ConfigMap\", \"apiVersion\": \"v1\", \"metadata\": { \"name\": \"$ARGOCD_APP_NAME\", \"namespace\": \"$ARGOCD_APP_NAMESPACE\", \"annotations\": {\"Foo\": \"$ARGOCD_ENV_FOO\", \"KubeVersion\": \"$KUBE_VERSION\", \"KubeApiVersion\": \"$KUBE_API_VERSIONS\",\"Bar\": \"baz\"}}}"`}, - }, - }, - ). + And(func() { + go startCMPServer(t, "./testdata/cmp-kustomize") + time.Sleep(1 * time.Second) + t.Setenv("ARGOCD_BINARY_NAME", "argocd") + }). // does not matter what the path is Path("guestbook"). When(). - CreateApp("--config-management-plugin", ctx.AppName()). - Sync("--local", "testdata/guestbook"). + CreateApp("--config-management-plugin", "cmp-kustomize-v1.0"). + Sync("--local", appPath, "--local-repo-root", testdataPath). Then(). Expect(OperationPhaseIs(OperationSucceeded)). Expect(SyncStatusIs(SyncStatusCodeSynced)). @@ -184,22 +170,22 @@ func TestCustomToolSyncAndDiffLocal(t *testing.T) { time.Sleep(1 * time.Second) }). And(func(app *Application) { - FailOnErr(RunCli("app", "sync", ctx.AppName(), "--local", "testdata/guestbook")) + FailOnErr(RunCli("app", "sync", ctx.AppName(), "--local", appPath, "--local-repo-root", testdataPath)) }). And(func(app *Application) { - FailOnErr(RunCli("app", "diff", ctx.AppName(), "--local", "testdata/guestbook")) + FailOnErr(RunCli("app", "diff", ctx.AppName(), "--local", appPath, "--local-repo-root", testdataPath)) }) } -func startCMPServer(configFile string) { +func startCMPServer(t *testing.T, configFile string) { pluginSockFilePath := TmpDir + PluginSockFilePath - os.Setenv("ARGOCD_BINARY_NAME", "argocd-cmp-server") + t.Setenv("ARGOCD_BINARY_NAME", "argocd-cmp-server") // ARGOCD_PLUGINSOCKFILEPATH should be set as the same value as repo server env var - os.Setenv("ARGOCD_PLUGINSOCKFILEPATH", pluginSockFilePath) + t.Setenv("ARGOCD_PLUGINSOCKFILEPATH", pluginSockFilePath) if _, err := os.Stat(pluginSockFilePath); os.IsNotExist(err) { // path/to/whatever does not exist err := os.Mkdir(pluginSockFilePath, 0700) - CheckError(err) + require.NoError(t, err) } FailOnErr(RunWithStdin("", "", "../../dist/argocd", "--config-dir-path", configFile)) } @@ -209,9 +195,9 @@ func TestCMPDiscoverWithFileName(t *testing.T) { pluginName := "cmp-fileName" Given(t). And(func() { - go startCMPServer("./testdata/cmp-fileName") + go startCMPServer(t, "./testdata/cmp-fileName") time.Sleep(1 * time.Second) - os.Setenv("ARGOCD_BINARY_NAME", "argocd") + t.Setenv("ARGOCD_BINARY_NAME", "argocd") }). Path(pluginName + "/subdir"). When(). @@ -227,9 +213,9 @@ func TestCMPDiscoverWithFileName(t *testing.T) { func TestCMPDiscoverWithFindGlob(t *testing.T) { Given(t). And(func() { - go startCMPServer("./testdata/cmp-find-glob") + go startCMPServer(t, "./testdata/cmp-find-glob") time.Sleep(1 * time.Second) - os.Setenv("ARGOCD_BINARY_NAME", "argocd") + t.Setenv("ARGOCD_BINARY_NAME", "argocd") }). Path("guestbook"). When(). @@ -245,9 +231,9 @@ func TestCMPDiscoverWithFindGlob(t *testing.T) { func TestCMPDiscoverWithPluginName(t *testing.T) { Given(t). And(func() { - go startCMPServer("./testdata/cmp-find-glob") + go startCMPServer(t, "./testdata/cmp-find-glob") time.Sleep(1 * time.Second) - os.Setenv("ARGOCD_BINARY_NAME", "argocd") + t.Setenv("ARGOCD_BINARY_NAME", "argocd") }). Path("guestbook"). When(). @@ -268,9 +254,9 @@ func TestCMPDiscoverWithFindCommandWithEnv(t *testing.T) { ctx := Given(t) ctx. And(func() { - go startCMPServer("./testdata/cmp-find-command") + go startCMPServer(t, "./testdata/cmp-find-command") time.Sleep(1 * time.Second) - os.Setenv("ARGOCD_BINARY_NAME", "argocd") + t.Setenv("ARGOCD_BINARY_NAME", "argocd") }). Path(pluginName). When(). @@ -311,9 +297,9 @@ func TestCMPDiscoverWithFindCommandWithEnv(t *testing.T) { func TestPruneResourceFromCMP(t *testing.T) { Given(t). And(func() { - go startCMPServer("./testdata/cmp-find-glob") + go startCMPServer(t, "./testdata/cmp-find-glob") time.Sleep(1 * time.Second) - os.Setenv("ARGOCD_BINARY_NAME", "argocd") + t.Setenv("ARGOCD_BINARY_NAME", "argocd") }). Path("guestbook"). When(). @@ -334,9 +320,9 @@ func TestPruneResourceFromCMP(t *testing.T) { func TestPreserveFileModeForCMP(t *testing.T) { Given(t). And(func() { - go startCMPServer("./testdata/cmp-preserve-file-mode") + go startCMPServer(t, "./testdata/cmp-preserve-file-mode") time.Sleep(1 * time.Second) - os.Setenv("ARGOCD_BINARY_NAME", "argocd") + t.Setenv("ARGOCD_BINARY_NAME", "argocd") }). Path("cmp-preserve-file-mode"). When(). @@ -354,9 +340,9 @@ func TestPreserveFileModeForCMP(t *testing.T) { func TestCMPWithSymlinkPartialFiles(t *testing.T) { Given(t, WithTestData("testdata2")). And(func() { - go startCMPServer("./testdata2/cmp-symlink") + go startCMPServer(t, "./testdata2/cmp-symlink") time.Sleep(1 * time.Second) - os.Setenv("ARGOCD_BINARY_NAME", "argocd") + t.Setenv("ARGOCD_BINARY_NAME", "argocd") }). Path("guestbook-partial-symlink-files"). When(). @@ -371,9 +357,9 @@ func TestCMPWithSymlinkPartialFiles(t *testing.T) { func TestCMPWithSymlinkFiles(t *testing.T) { Given(t, WithTestData("testdata2")). And(func() { - go startCMPServer("./testdata2/cmp-symlink") + go startCMPServer(t, "./testdata2/cmp-symlink") time.Sleep(1 * time.Second) - os.Setenv("ARGOCD_BINARY_NAME", "argocd") + t.Setenv("ARGOCD_BINARY_NAME", "argocd") }). Path("guestbook-symlink-files"). When(). @@ -388,9 +374,9 @@ func TestCMPWithSymlinkFiles(t *testing.T) { func TestCMPWithSymlinkFolder(t *testing.T) { Given(t, WithTestData("testdata2")). And(func() { - go startCMPServer("./testdata2/cmp-symlink") + go startCMPServer(t, "./testdata2/cmp-symlink") time.Sleep(1 * time.Second) - os.Setenv("ARGOCD_BINARY_NAME", "argocd") + t.Setenv("ARGOCD_BINARY_NAME", "argocd") }). Path("guestbook-symlink-folder"). When(). diff --git a/test/e2e/fixture/app/context.go b/test/e2e/fixture/app/context.go index f0befbe456c27..d653b6a0280ca 100644 --- a/test/e2e/fixture/app/context.go +++ b/test/e2e/fixture/app/context.go @@ -300,13 +300,6 @@ func (c *Context) ResourceFilter(filter settings.ResourcesFilter) *Context { return c } -// this both configures the plugin, but forces use of it -func (c *Context) ConfigManagementPlugin(plugin v1alpha1.ConfigManagementPlugin) *Context { - fixture.SetConfigManagementPlugins(plugin) - c.configManagementPlugin = plugin.Name - return c -} - func (c *Context) And(block func()) *Context { block() return c diff --git a/test/e2e/fixture/fixture.go b/test/e2e/fixture/fixture.go index 0e6861eccae87..095b3e2f116be 100644 --- a/test/e2e/fixture/fixture.go +++ b/test/e2e/fixture/fixture.go @@ -450,17 +450,6 @@ func SetPermissions(permissions []ACL, username string, roleName string) { }) } -func SetConfigManagementPlugins(plugin ...v1alpha1.ConfigManagementPlugin) { - updateSettingConfigMap(func(cm *corev1.ConfigMap) error { - yamlBytes, err := yaml.Marshal(plugin) - if err != nil { - return err - } - cm.Data["configManagementPlugins"] = string(yamlBytes) - return nil - }) -} - func SetResourceFilter(filters settings.ResourcesFilter) { updateSettingConfigMap(func(cm *corev1.ConfigMap) error { exclusions, err := yaml.Marshal(filters.ResourceExclusions) diff --git a/test/e2e/testdata/cmp-fileName/plugin.yaml b/test/e2e/testdata/cmp-fileName/plugin.yaml index 766278c79e773..b3f8068de2100 100644 --- a/test/e2e/testdata/cmp-fileName/plugin.yaml +++ b/test/e2e/testdata/cmp-fileName/plugin.yaml @@ -5,6 +5,6 @@ metadata: spec: version: v1.0 generate: - command: [sh, -c, 'echo "{\"kind\": \"ConfigMap\", \"apiVersion\": \"v1\", \"metadata\": { \"name\": \"$ARGOCD_APP_NAME\", \"namespace\": \"$ARGOCD_APP_NAMESPACE\", \"annotations\": {\"Foo\": \"$FOO\", \"KubeVersion\": \"$KUBE_VERSION\", \"KubeApiVersion\": \"$KUBE_API_VERSIONS\",\"Bar\": \"baz\"}}}"'] + command: [sh, -c, 'echo "{\"kind\": \"ConfigMap\", \"apiVersion\": \"v1\", \"metadata\": { \"name\": \"$ARGOCD_APP_NAME\", \"namespace\": \"$ARGOCD_APP_NAMESPACE\", \"annotations\": {\"Foo\": \"$ARGOCD_ENV_FOO\", \"KubeVersion\": \"$KUBE_VERSION\", \"KubeApiVersion\": \"$KUBE_API_VERSIONS\",\"Bar\": \"baz\"}}}"'] discover: fileName: "subdir/s*.yaml" diff --git a/test/e2e/testdata/cmp-gitcreds/plugin.yaml b/test/e2e/testdata/cmp-gitcreds/plugin.yaml new file mode 100644 index 0000000000000..024804f495cc9 --- /dev/null +++ b/test/e2e/testdata/cmp-gitcreds/plugin.yaml @@ -0,0 +1,10 @@ +apiVersion: argoproj.io/v1alpha1 +kind: ConfigManagementPlugin +metadata: + name: cmp-gitcreds +spec: + version: v1.0 + generate: + command: [sh, -c, 'echo "{\"kind\": \"ConfigMap\", \"apiVersion\": \"v1\", \"metadata\": { \"name\": \"$ARGOCD_APP_NAME\", \"namespace\": \"$ARGOCD_APP_NAMESPACE\", \"annotations\": {\"GitAskpass\": \"$GIT_ASKPASS\"}}}"'] + discover: + fileName: "subdir/s*.yaml" diff --git a/test/e2e/testdata/cmp-gitcreds/subdir/special.yaml b/test/e2e/testdata/cmp-gitcreds/subdir/special.yaml new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/test/e2e/testdata/cmp-gitcredstemplate/plugin.yaml b/test/e2e/testdata/cmp-gitcredstemplate/plugin.yaml new file mode 100644 index 0000000000000..e57ee747bd078 --- /dev/null +++ b/test/e2e/testdata/cmp-gitcredstemplate/plugin.yaml @@ -0,0 +1,10 @@ +apiVersion: argoproj.io/v1alpha1 +kind: ConfigManagementPlugin +metadata: + name: cmp-gitcredstemplate +spec: + version: v1.0 + generate: + command: [sh, -c, 'echo "{\"kind\": \"ConfigMap\", \"apiVersion\": \"v1\", \"metadata\": { \"name\": \"$ARGOCD_APP_NAME\", \"namespace\": \"$ARGOCD_APP_NAMESPACE\", \"annotations\": {\"GitAskpass\": \"$GIT_ASKPASS\", \"GitUsername\": \"$GIT_USERNAME\", \"GitPassword\": \"$GIT_PASSWORD\"}}}"'] + discover: + fileName: "subdir/s*.yaml" diff --git a/test/e2e/testdata/cmp-gitcredstemplate/subdir/special.yaml b/test/e2e/testdata/cmp-gitcredstemplate/subdir/special.yaml new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/test/e2e/testdata/cmp-kustomize/plugin.yaml b/test/e2e/testdata/cmp-kustomize/plugin.yaml new file mode 100644 index 0000000000000..3cdcc6d643758 --- /dev/null +++ b/test/e2e/testdata/cmp-kustomize/plugin.yaml @@ -0,0 +1,10 @@ +apiVersion: argoproj.io/v1alpha1 +kind: ConfigManagementPlugin +metadata: + name: cmp-kustomize +spec: + version: v1.0 + generate: + command: [kustomize, build, .] + discover: + fileName: "kustomization.yaml" diff --git a/util/argo/argo.go b/util/argo/argo.go index 33f8bdd7e2c6a..194f8a46c07d6 100644 --- a/util/argo/argo.go +++ b/util/argo/argo.go @@ -272,12 +272,13 @@ func TestRepoWithKnownType(ctx context.Context, repoClient apiclient.RepoServerS // * the repository is accessible // * the path contains valid manifests // * there are parameters of only one app source type +// +// The plugins parameter is no longer used. It is kept for compatibility with the old signature until Argo CD v3.0. func ValidateRepo( ctx context.Context, app *argoappv1.Application, repoClientset apiclient.Clientset, db db.ArgoDB, - plugins []*argoappv1.ConfigManagementPlugin, kubectl kube.Kubectl, proj *argoappv1.AppProject, settingsMgr *settings.SettingsManager, @@ -343,7 +344,6 @@ func ValidateRepo( db, app.Spec.GetSources(), repoClient, - plugins, permittedHelmRepos, helmOptions, cluster, @@ -365,7 +365,6 @@ func validateRepo(ctx context.Context, db db.ArgoDB, sources []argoappv1.ApplicationSource, repoClient apiclient.RepoServerServiceClient, - plugins []*argoappv1.ConfigManagementPlugin, permittedHelmRepos []*argoappv1.Repository, helmOptions *argoappv1.HelmOptions, cluster *argoappv1.Cluster, @@ -423,7 +422,6 @@ func validateRepo(ctx context.Context, proj, sources, repoClient, - plugins, cluster.ServerVersion, APIResourcesToStrings(apiGroups, true), permittedHelmCredentials, @@ -709,7 +707,6 @@ func verifyGenerateManifests( proj *argoappv1.AppProject, sources []argoappv1.ApplicationSource, repoClient apiclient.RepoServerServiceClient, - plugins []*argoappv1.ConfigManagementPlugin, kubeVersion string, apiVersions []string, repositoryCredentials []*argoappv1.RepoCreds, @@ -764,7 +761,6 @@ func verifyGenerateManifests( AppName: name, Namespace: dest.Namespace, ApplicationSource: &source, - Plugins: plugins, KustomizeOptions: kustomizeOptions, KubeVersion: kubeVersion, ApiVersions: apiVersions, diff --git a/util/argo/argo_test.go b/util/argo/argo_test.go index a096f2c58de32..1d8deca0f8be2 100644 --- a/util/argo/argo_test.go +++ b/util/argo/argo_test.go @@ -414,7 +414,7 @@ func TestValidateRepo(t *testing.T) { kubeClient := fake.NewSimpleClientset(&cm) settingsMgr := settings.NewSettingsManager(context.Background(), kubeClient, test.FakeArgoCDNamespace) - conditions, err := ValidateRepo(context.Background(), app, repoClientSet, db, nil, &kubetest.MockKubectlCmd{Version: kubeVersion, APIResources: apiResources}, proj, settingsMgr) + conditions, err := ValidateRepo(context.Background(), app, repoClientSet, db, &kubetest.MockKubectlCmd{Version: kubeVersion, APIResources: apiResources}, proj, settingsMgr) assert.NoError(t, err) assert.Empty(t, conditions) diff --git a/util/settings/settings.go b/util/settings/settings.go index f884a3a4906f3..f00d724027612 100644 --- a/util/settings/settings.go +++ b/util/settings/settings.go @@ -423,8 +423,6 @@ const ( resourceInclusionsKey = "resource.inclusions" // resourceCustomLabelKey is the key to a custom label to show in node info, if present resourceCustomLabelsKey = "resource.customLabels" - // configManagementPluginsKey is the key to the list of config management plugins - configManagementPluginsKey = "configManagementPlugins" // kustomizeBuildOptionsKey is a string of kustomize build parameters kustomizeBuildOptionsKey = "kustomize.buildOptions" // kustomizeVersionKeyPrefix is a kustomize version key prefix @@ -745,21 +743,6 @@ func (mgr *SettingsManager) GetServerRBACLogEnforceEnable() (bool, error) { return strconv.ParseBool(argoCDCM.Data[settingsServerRBACLogEnforceEnableKey]) } -func (mgr *SettingsManager) GetConfigManagementPlugins() ([]v1alpha1.ConfigManagementPlugin, error) { - argoCDCM, err := mgr.getConfigMap() - if err != nil { - return nil, err - } - plugins := make([]v1alpha1.ConfigManagementPlugin, 0) - if value, ok := argoCDCM.Data[configManagementPluginsKey]; ok { - err := yaml.Unmarshal([]byte(value), &plugins) - if err != nil { - return nil, err - } - } - return plugins, nil -} - func (mgr *SettingsManager) GetDeepLinks(deeplinkType string) ([]DeepLink, error) { argoCDCM, err := mgr.getConfigMap() if err != nil { diff --git a/util/settings/settings_test.go b/util/settings/settings_test.go index afb6cb4891415..3e274417262c4 100644 --- a/util/settings/settings_test.go +++ b/util/settings/settings_test.go @@ -121,25 +121,6 @@ func TestGetResourceFilter(t *testing.T) { }, filter) } -func TestGetConfigManagementPlugins(t *testing.T) { - data := map[string]string{ - "configManagementPlugins": ` - - name: kasane - init: - command: [kasane, update] - generate: - command: [kasane, show]`, - } - _, settingsManager := fixtures(data) - plugins, err := settingsManager.GetConfigManagementPlugins() - assert.NoError(t, err) - assert.ElementsMatch(t, []v1alpha1.ConfigManagementPlugin{{ - Name: "kasane", - Init: &v1alpha1.Command{Command: []string{"kasane", "update"}}, - Generate: v1alpha1.Command{Command: []string{"kasane", "show"}}, - }}, plugins) -} - func TestInClusterServerAddressEnabled(t *testing.T) { _, settingsManager := fixtures(map[string]string{ "cluster.inClusterEnabled": "true",