From 561f30815c628e562bb80b1d4beaaa39c8575e16 Mon Sep 17 00:00:00 2001 From: rachelwang20 <62673041+rachelwang20@users.noreply.github.com> Date: Tue, 14 Jul 2020 14:53:56 -0700 Subject: [PATCH] feat: Orphaned ignore list cli support (#3922) * Include sub and and iat in PermissionDenied message * Run test-local * Fix typo * Fix lint error * iat fromat changing * Adding MapClaims convertion * Fix lint issue * Fix golang lint * Fix blank space * Fix missing field * Adding Orphaned exception list * Fixed lint error * Rebased on master * Adding group kind label * golangci-lint run * Addressed comments * Fixed lint errors * Method rename * orphaned ignore list cli support --- cmd/argocd/commands/project.go | 91 ++++++++++++++++++++++++++++- test/e2e/project_management_test.go | 84 ++++++++++++++++++++++++++ 2 files changed, 173 insertions(+), 2 deletions(-) diff --git a/cmd/argocd/commands/project.go b/cmd/argocd/commands/project.go index 43a0109f0f..19325c8c5d 100644 --- a/cmd/argocd/commands/project.go +++ b/cmd/argocd/commands/project.go @@ -102,6 +102,8 @@ func NewProjectCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { command.AddCommand(NewProjectAllowNamespaceResourceCommand(clientOpts)) command.AddCommand(NewProjectDenyNamespaceResourceCommand(clientOpts)) command.AddCommand(NewProjectWindowsCommand(clientOpts)) + command.AddCommand(NewProjectAddOrphanedIgnoreCommand(clientOpts)) + command.AddCommand(NewProjectRemoveOrphanedIgnoreCommand(clientOpts)) return command } @@ -254,7 +256,7 @@ func NewProjectSetCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command return command } -// NewProjectAddSignatureKeyCommand returns a new instance of an `argocd proj add-destination` command +// NewProjectAddSignatureKeyCommand returns a new instance of an `argocd proj add-signature-key` command func NewProjectAddSignatureKeyCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { var command = &cobra.Command{ Use: "add-signature-key PROJECT KEY-ID", @@ -290,7 +292,7 @@ func NewProjectAddSignatureKeyCommand(clientOpts *argocdclient.ClientOptions) *c return command } -// NewProjectRemoveDestinationCommand returns a new instance of an `argocd proj remove-destination` command +// NewProjectRemoveSignatureKeyCommand returns a new instance of an `argocd proj remove-signature-key` command func NewProjectRemoveSignatureKeyCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { var command = &cobra.Command{ Use: "remove-signature-key PROJECT KEY-ID", @@ -400,6 +402,91 @@ func NewProjectRemoveDestinationCommand(clientOpts *argocdclient.ClientOptions) return command } +// NewProjectAddOrphanedIgnoreCommand returns a new instance of an `argocd proj add-orphaned-ignore` command +func NewProjectAddOrphanedIgnoreCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { + var command = &cobra.Command{ + Use: "add-orphaned-ignore PROJECT GROUP KIND NAME", + Short: "Add a resource to orphaned ignore list", + Run: func(c *cobra.Command, args []string) { + if len(args) != 4 { + c.HelpFunc()(c, args) + os.Exit(1) + } + projName := args[0] + group := args[1] + kind := args[2] + name := args[3] + conn, projIf := argocdclient.NewClientOrDie(clientOpts).NewProjectClientOrDie() + defer argoio.Close(conn) + + proj, err := projIf.Get(context.Background(), &projectpkg.ProjectQuery{Name: projName}) + errors.CheckError(err) + + if proj.Spec.OrphanedResources == nil { + settings := v1alpha1.OrphanedResourcesMonitorSettings{} + settings.Ignore = []v1alpha1.OrphanedResourceKey{{Group: group, Kind: kind, Name: name}} + proj.Spec.OrphanedResources = &settings + } else { + for _, ignore := range proj.Spec.OrphanedResources.Ignore { + if ignore.Group == group && ignore.Kind == kind && ignore.Name == name { + log.Fatal("Specified resource is already defined in the orphaned ignore list of project") + return + } + } + proj.Spec.OrphanedResources.Ignore = append(proj.Spec.OrphanedResources.Ignore, v1alpha1.OrphanedResourceKey{Group: group, Kind: kind, Name: name}) + } + _, err = projIf.Update(context.Background(), &projectpkg.ProjectUpdateRequest{Project: proj}) + errors.CheckError(err) + }, + } + return command +} + +// NewProjectRemoveOrphanedIgnoreCommand returns a new instance of an `argocd proj remove-orphaned-ignore` command +func NewProjectRemoveOrphanedIgnoreCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { + var command = &cobra.Command{ + Use: "remove-orphaned-ignore PROJECT GROUP KIND NAME", + Short: "Remove a resource from orphaned ignore list", + Run: func(c *cobra.Command, args []string) { + if len(args) != 4 { + c.HelpFunc()(c, args) + os.Exit(1) + } + projName := args[0] + group := args[1] + kind := args[2] + name := args[3] + conn, projIf := argocdclient.NewClientOrDie(clientOpts).NewProjectClientOrDie() + defer argoio.Close(conn) + + proj, err := projIf.Get(context.Background(), &projectpkg.ProjectQuery{Name: projName}) + errors.CheckError(err) + + if proj.Spec.OrphanedResources == nil { + log.Fatal("Specified resource does not exist in the orphaned ignore list of project") + return + } + + index := -1 + for i, ignore := range proj.Spec.OrphanedResources.Ignore { + if ignore.Group == group && ignore.Kind == kind && ignore.Name == name { + index = i + break + } + } + if index == -1 { + log.Fatal("Specified resource does not exist in the orphaned ignore of project") + } else { + proj.Spec.OrphanedResources.Ignore = append(proj.Spec.OrphanedResources.Ignore[:index], proj.Spec.OrphanedResources.Ignore[index+1:]...) + _, err = projIf.Update(context.Background(), &projectpkg.ProjectUpdateRequest{Project: proj}) + errors.CheckError(err) + } + }, + } + + return command +} + // NewProjectAddSourceCommand returns a new instance of an `argocd proj add-src` command func NewProjectAddSourceCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command { var command = &cobra.Command{ diff --git a/test/e2e/project_management_test.go b/test/e2e/project_management_test.go index 096f74ec79..7eeb49cb4c 100644 --- a/test/e2e/project_management_test.go +++ b/test/e2e/project_management_test.go @@ -11,6 +11,7 @@ import ( "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/fields" + "k8s.io/utils/pointer" "github.com/argoproj/argo-cd/common" "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1" @@ -336,3 +337,86 @@ func TestUseJWTToken(t *testing.T) { assert.Nil(t, newProj.Spec.Roles[0].JWTTokens) } + +func TestAddOrphanedIgnore(t *testing.T) { + fixture.EnsureCleanState(t) + + projectName := "proj-" + strconv.FormatInt(time.Now().Unix(), 10) + _, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.ArgoCDNamespace).Create(&v1alpha1.AppProject{ObjectMeta: metav1.ObjectMeta{Name: projectName}}) + if err != nil { + t.Fatalf("Unable to create project %v", err) + } + + _, err = fixture.RunCli("proj", "add-orphaned-ignore", projectName, + "group", + "kind", + "name", + ) + + if err != nil { + t.Fatalf("Unable to add resource to orphaned ignore %v", err) + } + + _, err = fixture.RunCli("proj", "add-orphaned-ignore", projectName, + "group", + "kind", + "name", + ) + assert.Error(t, err) + assert.True(t, strings.Contains(err.Error(), "already defined")) + + proj, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.ArgoCDNamespace).Get(projectName, metav1.GetOptions{}) + assert.NoError(t, err) + assert.Equal(t, projectName, proj.Name) + assert.Equal(t, 1, len(proj.Spec.OrphanedResources.Ignore)) + + assert.Equal(t, "group", proj.Spec.OrphanedResources.Ignore[0].Group) + assert.Equal(t, "kind", proj.Spec.OrphanedResources.Ignore[0].Kind) + assert.Equal(t, "name", proj.Spec.OrphanedResources.Ignore[0].Name) + assertProjHasEvent(t, proj, "update", argo.EventReasonResourceUpdated) +} + +func TestRemoveOrphanedIgnore(t *testing.T) { + fixture.EnsureCleanState(t) + + projectName := "proj-" + strconv.FormatInt(time.Now().Unix(), 10) + _, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.ArgoCDNamespace).Create(&v1alpha1.AppProject{ + ObjectMeta: metav1.ObjectMeta{Name: projectName}, + Spec: v1alpha1.AppProjectSpec{ + OrphanedResources: &v1alpha1.OrphanedResourcesMonitorSettings{ + Warn: pointer.BoolPtr(true), + Ignore: []v1alpha1.OrphanedResourceKey{{Group: "group", Kind: "kind", Name: "name"}}, + }, + }, + }) + + if err != nil { + t.Fatalf("Unable to create project %v", err) + } + + _, err = fixture.RunCli("proj", "remove-orphaned-ignore", projectName, + "group", + "kind", + "name", + ) + + if err != nil { + t.Fatalf("Unable to remove resource from orphaned ignore list %v", err) + } + + _, err = fixture.RunCli("proj", "remove-orphaned-ignore", projectName, + "group", + "kind", + "name", + ) + assert.Error(t, err) + assert.Contains(t, err.Error(), "does not exist") + + proj, err := fixture.AppClientset.ArgoprojV1alpha1().AppProjects(fixture.ArgoCDNamespace).Get(projectName, metav1.GetOptions{}) + if err != nil { + t.Fatalf("Unable to get project %v", err) + } + assert.Equal(t, projectName, proj.Name) + assert.Equal(t, 0, len(proj.Spec.OrphanedResources.Ignore)) + assertProjHasEvent(t, proj, "update", argo.EventReasonResourceUpdated) +}