@@ -8,13 +8,16 @@ import (
88 metainternal "k8s.io/apimachinery/pkg/apis/meta/internalversion"
99 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1010 "k8s.io/apimachinery/pkg/runtime"
11+ "k8s.io/apimachinery/pkg/util/wait"
1112 "k8s.io/apimachinery/pkg/watch"
1213 apirequest "k8s.io/apiserver/pkg/endpoints/request"
1314 "k8s.io/apiserver/pkg/registry/rest"
1415 corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
1516 "k8s.io/kubernetes/pkg/printers"
1617 printerstorage "k8s.io/kubernetes/pkg/printers/storage"
1718
19+ "k8s.io/klog/v2"
20+
1821 "github.com/openshift/api/project"
1922 "github.com/openshift/apiserver-library-go/pkg/authorization/scope"
2023 "github.com/openshift/openshift-apiserver/pkg/api/apihelpers"
@@ -208,32 +211,50 @@ func (s *REST) Update(ctx context.Context, name string, objInfo rest.UpdatedObje
208211
209212var _ = rest .GracefulDeleter (& REST {})
210213
214+ // maxRetriesOnConflict is the maximum retry count for Delete calls which
215+ // result in resource conflicts.
216+ const maxRetriesOnConflict = 10
217+
211218// Delete deletes a Project specified by its name
212219func (s * REST ) Delete (ctx context.Context , name string , objectFunc rest.ValidateObjectFunc , options * metav1.DeleteOptions ) (runtime.Object , bool , error ) {
220+ klog .V (2 ).Infof ("Project delete name=%s: start" , name )
213221 var opts metav1.DeleteOptions
214222 if options != nil {
215223 opts = * options
216224 }
217- if objectFunc != nil {
218- obj , err := s .Get (ctx , name , & metav1.GetOptions {})
219- if err != nil {
220- return nil , false , err
221- }
222- projectObj , ok := obj .(* projectapi.Project )
223- if ! ok || projectObj == nil {
224- return nil , false , fmt .Errorf ("not a project: %#v" , obj )
225- }
226-
227- // Make sure the object hasn't changed between Get and Delete - pass UID and RV to delete options
228- if opts .Preconditions == nil {
229- opts .Preconditions = & metav1.Preconditions {}
230- }
231- opts .Preconditions .UID = & projectObj .UID
232- opts .Preconditions .ResourceVersion = & projectObj .ResourceVersion
233-
234- if err := objectFunc (ctx , obj ); err != nil {
235- return nil , false , err
225+ err := wait .ExponentialBackoff (wait.Backoff {Steps : maxRetriesOnConflict }, func () (bool , error ) {
226+ if objectFunc != nil {
227+ klog .V (2 ).Infof ("Project delete name=%s: validation func=%#v" , name , objectFunc )
228+ obj , err := s .Get (ctx , name , & metav1.GetOptions {})
229+ if err != nil {
230+ klog .V (2 ).Infof ("Project delete name=%s: unable to get project: %#v" , name , err )
231+ return false , fmt .Errorf ("unable to get project: %w" , err )
232+ }
233+ projectObj , ok := obj .(* projectapi.Project )
234+ if ! ok || projectObj == nil {
235+ klog .V (2 ).Infof ("Project delete name=%s: not a project: %#v" , name , err )
236+ return false , fmt .Errorf ("not a project: %#v" , obj )
237+ }
238+
239+ // Make sure the object hasn't changed between Get and Delete - pass UID and RV to delete options
240+ if opts .Preconditions == nil {
241+ opts .Preconditions = & metav1.Preconditions {}
242+ }
243+ opts .Preconditions .UID = & projectObj .UID
244+ opts .Preconditions .ResourceVersion = & projectObj .ResourceVersion
245+
246+ if err := objectFunc (ctx , obj ); err != nil {
247+ klog .V (2 ).Infof ("Project delete name=%s: validation func failed: %#v" , name , err )
248+ return false , fmt .Errorf ("validation func failed: %w" , err )
249+ }
250+ klog .V (2 ).Infof ("Project delete name=%s: objectFunc validation complete" , name )
236251 }
252+ err := s .client .Delete (ctx , name , opts )
253+ klog .V (2 ).Infof ("Project delete name=%s: complete err=%v" , name , err )
254+ return true , err
255+ })
256+ if err != nil {
257+ return nil , false , err
237258 }
238- return & metav1.Status {Status : metav1 .StatusSuccess }, false , s . client . Delete ( ctx , name , opts )
259+ return & metav1.Status {Status : metav1 .StatusSuccess }, false , nil
239260}
0 commit comments