From ea72ce8b9ec6bc2b2a822e588afd954bfeb5cf59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20B=C3=BChlmann?= Date: Tue, 3 Dec 2024 17:35:57 +0100 Subject: [PATCH] Don't delete GitLab top-level groups with attribute 'permanently_remove=true' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Benjamin Bühlmann --- pkg/controller/groups/groups/group.go | 4 ++- pkg/controller/groups/groups/group_test.go | 37 ++++++++++++++++++++-- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/pkg/controller/groups/groups/group.go b/pkg/controller/groups/groups/group.go index 01cd572..922bdfb 100644 --- a/pkg/controller/groups/groups/group.go +++ b/pkg/controller/groups/groups/group.go @@ -251,7 +251,9 @@ func (e *external) Delete(ctx context.Context, mg resource.Managed) (managed.Ext return managed.ExternalDelete{}, errors.Wrap(err, errDeleteFailed) } - if cr.Spec.ForProvider.PermanentlyRemove != nil && *cr.Spec.ForProvider.PermanentlyRemove { + // permanent deletion is only available on subgroups; when executed against top-level groups the backend will return an error + isSubGroup := cr.Status.AtProvider.FullPath != nil && *cr.Status.AtProvider.FullPath != cr.Spec.ForProvider.Path + if cr.Spec.ForProvider.PermanentlyRemove != nil && *cr.Spec.ForProvider.PermanentlyRemove && isSubGroup { _, err = e.client.DeleteGroup(meta.GetExternalName(cr), &gitlab.DeleteGroupOptions{ PermanentlyRemove: cr.Spec.ForProvider.PermanentlyRemove, FullPath: cr.Spec.ForProvider.FullPathToRemove, diff --git a/pkg/controller/groups/groups/group_test.go b/pkg/controller/groups/groups/group_test.go index 651950c..768e8c5 100644 --- a/pkg/controller/groups/groups/group_test.go +++ b/pkg/controller/groups/groups/group_test.go @@ -918,16 +918,47 @@ func TestDelete(t *testing.T) { cr: group( withExternalName("0"), withPermanentlyRemove(gitlab.Ptr(true)), - withFullPathToRemove(gitlab.Ptr("path/to/remove"))), + withPath("group"), + withFullPathToRemove(gitlab.Ptr("path/to/group")), + withStatus(v1alpha1.GroupObservation{FullPath: gitlab.Ptr("path/to/group")})), }, want: want{ cr: group( withExternalName("0"), withPermanentlyRemove(gitlab.Ptr(true)), - withFullPathToRemove(gitlab.Ptr("path/to/remove"))), + withPath("group"), + withFullPathToRemove(gitlab.Ptr("path/to/group")), + withStatus(v1alpha1.GroupObservation{FullPath: gitlab.Ptr("path/to/group")})), + calls: []deleteGroupCalls{ + {Pid: "0", Opt: &gitlab.DeleteGroupOptions{}}, + {Pid: "0", Opt: &gitlab.DeleteGroupOptions{PermanentlyRemove: gitlab.Ptr(true), FullPath: gitlab.Ptr("path/to/group")}}, + }, + err: nil, + }, + }, + "SuccessfulPermanentlyTopLevelGroupDeletion": { + args: args{ + group: &fake.MockClient{ + MockDeleteGroup: func(pid interface{}, opt *gitlab.DeleteGroupOptions, options ...gitlab.RequestOptionFunc) (*gitlab.Response, error) { + recordedCalls = append(recordedCalls, deleteGroupCalls{Pid: pid, Opt: opt}) + return &gitlab.Response{}, nil + }, + }, + cr: group( + withExternalName("0"), + withPermanentlyRemove(gitlab.Ptr(true)), + withPath("top-level-group"), + withStatus(v1alpha1.GroupObservation{FullPath: gitlab.Ptr("top-level-group")})), + }, + want: want{ + cr: group( + withExternalName("0"), + withPermanentlyRemove(gitlab.Ptr(true)), + withPath("top-level-group"), + withStatus(v1alpha1.GroupObservation{FullPath: gitlab.Ptr("top-level-group")}), + ), calls: []deleteGroupCalls{ {Pid: "0", Opt: &gitlab.DeleteGroupOptions{}}, - {Pid: "0", Opt: &gitlab.DeleteGroupOptions{PermanentlyRemove: gitlab.Ptr(true), FullPath: gitlab.Ptr("path/to/remove")}}, }, err: nil, },