Skip to content

Commit 8679782

Browse files
authored
Fix error tracking - btpoperator cleanup (#2892)
* Fix error tracking and adjust fake provider * Fix retryOnError and add test in case of error * Linter check
1 parent e76e29f commit 8679782

File tree

2 files changed

+94
-5
lines changed

2 files changed

+94
-5
lines changed

internal/process/deprovisioning/btp_operator_cleanup.go

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ func (s *BTPOperatorCleanupStep) Name() string {
5555
func (s *BTPOperatorCleanupStep) softDelete(operation internal.Operation, k8sClient client.Client, log *slog.Logger) (internal.Operation, time.Duration, error) {
5656
namespaces := corev1.NamespaceList{}
5757
if err := k8sClient.List(context.Background(), &namespaces); err != nil {
58-
return s.retryOnError(operation, nil, err, log, "failed to list namespaces")
58+
err = kebError.AsTemporaryError(err, "failed to list namespaces")
59+
return s.retryOnError(operation, k8sClient, err, log, "failed to list namespaces")
5960
}
6061

6162
var errors []string
@@ -65,7 +66,7 @@ func (s *BTPOperatorCleanupStep) softDelete(operation internal.Operation, k8sCli
6566
return operation, 0, err
6667
}
6768
if SBCrdExists {
68-
s.removeResources(k8sClient, gvk, namespaces, errors)
69+
errors = s.removeResources(k8sClient, gvk, namespaces, errors)
6970
}
7071

7172
gvk.Kind = btpOperatorServiceInstance
@@ -74,11 +75,13 @@ func (s *BTPOperatorCleanupStep) softDelete(operation internal.Operation, k8sCli
7475
return operation, 0, err
7576
}
7677
if SICrdExists {
77-
s.removeResources(k8sClient, gvk, namespaces, errors)
78+
errors = s.removeResources(k8sClient, gvk, namespaces, errors)
7879
}
7980

8081
if len(errors) != 0 {
81-
return s.retryOnError(operation, nil, fmt.Errorf("%s", strings.Join(errors, ";")), log, "failed to cleanup")
82+
err := fmt.Errorf("%s", strings.Join(errors, ";"))
83+
err = kebError.AsTemporaryError(err, "failed to cleanup BTP operator resources")
84+
return s.retryOnError(operation, k8sClient, err, log, "failed to cleanup")
8285
}
8386
return operation, 0, nil
8487
}
@@ -235,7 +238,7 @@ func (s *BTPOperatorCleanupStep) checkCRDExistence(k8sClient client.Client, gvk
235238
return true, nil
236239
}
237240

238-
func (s *BTPOperatorCleanupStep) removeResources(k8sClient client.Client, gvk schema.GroupVersionKind, namespaces corev1.NamespaceList, errors []string) {
241+
func (s *BTPOperatorCleanupStep) removeResources(k8sClient client.Client, gvk schema.GroupVersionKind, namespaces corev1.NamespaceList, errors []string) []string {
239242
for _, ns := range namespaces.Items {
240243
obj := &unstructured.Unstructured{}
241244
obj.SetGroupVersionKind(gvk)
@@ -246,4 +249,5 @@ func (s *BTPOperatorCleanupStep) removeResources(k8sClient client.Client, gvk sc
246249
if err := s.removeFinalizers(k8sClient, namespaces, gvk); err != nil {
247250
errors = append(errors, err.Error())
248251
}
252+
return errors
249253
}

internal/process/deprovisioning/btp_operator_cleanup_test.go

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,10 +362,84 @@ func TestBTPOperatorCleanupStep_NoRuntimeID(t *testing.T) {
362362
assert.Zero(t, backoff)
363363
}
364364

365+
func TestBTPOperatorCleanupStep_ErrorCollection(t *testing.T) {
366+
log := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
367+
Level: slog.LevelInfo,
368+
})).With("step", "TEST")
369+
370+
t.Run("should collect errors from DeleteAllOf", func(t *testing.T) {
371+
// given
372+
ms := storage.NewMemoryStorage()
373+
ns := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "kyma-system"}}
374+
375+
scheme := internal.NewSchemeForTests(t)
376+
err := apiextensionsv1.AddToScheme(scheme)
377+
require.NoError(t, err)
378+
decoder := serializer.NewCodecFactory(scheme).UniversalDeserializer()
379+
obj, _, err := decoder.Decode(siCRD, nil, nil)
380+
require.NoError(t, err)
381+
382+
// fake client that returns error on DeleteAllOf
383+
k8sCli := &fakeK8sClientWrapper{
384+
fake: fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(obj, ns).Build(),
385+
deleteAllOfError: fmt.Errorf("simulated DeleteAllOf error"),
386+
}
387+
388+
op := fixture.FixDeprovisioningOperation(fixOperationID, fixInstanceID)
389+
op.Temporary = true
390+
op.ProvisioningParameters.PlanID = broker.TrialPlanID
391+
op.UserAgent = broker.AccountCleanupJob
392+
op.State = operationStateInProgress
393+
step := NewBTPOperatorCleanupStep(ms, kubeconfig.NewFakeK8sClientProvider(k8sCli))
394+
395+
// when
396+
_, backoff, err := step.Run(op.Operation, log)
397+
398+
// then
399+
// handleError consumes the error and returns backoff for retry instead
400+
assert.NoError(t, err, "handleError returns nil error, only backoff")
401+
assert.NotZero(t, backoff, "should return non-zero backoff for retry on temporary errors")
402+
assert.True(t, k8sCli.cleanupInstances, "DeleteAllOf should have been called for ServiceInstances")
403+
})
404+
405+
t.Run("should collect errors from List operation", func(t *testing.T) {
406+
// given
407+
ms := storage.NewMemoryStorage()
408+
ns := &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "kyma-system"}}
409+
410+
scheme := internal.NewSchemeForTests(t)
411+
err := apiextensionsv1.AddToScheme(scheme)
412+
require.NoError(t, err)
413+
414+
// fake client that returns error on List
415+
k8sCli := &fakeK8sClientWrapper{
416+
fake: fake.NewClientBuilder().WithScheme(scheme).WithRuntimeObjects(ns).Build(),
417+
listError: fmt.Errorf("simulated List error"),
418+
}
419+
420+
op := fixture.FixDeprovisioningOperation(fixOperationID, fixInstanceID)
421+
op.Temporary = true
422+
op.ProvisioningParameters.PlanID = broker.TrialPlanID
423+
op.UserAgent = broker.AccountCleanupJob
424+
op.State = operationStateInProgress
425+
step := NewBTPOperatorCleanupStep(ms, kubeconfig.NewFakeK8sClientProvider(k8sCli))
426+
427+
// when
428+
_, backoff, err := step.Run(op.Operation, log)
429+
430+
// then
431+
// handleError consumes the error and returns backoff for retry instead
432+
assert.NoError(t, err, "handleError returns nil error, only backoff")
433+
assert.NotZero(t, backoff, "should return non-zero backoff for retry on temporary errors")
434+
})
435+
}
436+
365437
type fakeK8sClientWrapper struct {
366438
fake client.Client
367439
cleanupInstances bool
368440
cleanupBindings bool
441+
deleteAllOfError error
442+
listError error
369443
}
370444

371445
func (f *fakeK8sClientWrapper) Apply(ctx context.Context, obj runtime.ApplyConfiguration, opts ...client.ApplyOption) error {
@@ -377,6 +451,9 @@ func (f *fakeK8sClientWrapper) Get(ctx context.Context, key client.ObjectKey, ob
377451
}
378452

379453
func (f *fakeK8sClientWrapper) List(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error {
454+
if f.listError != nil {
455+
return f.listError
456+
}
380457
if u, ok := list.(*unstructured.UnstructuredList); ok {
381458
switch u.Object["kind"] {
382459
case "ServiceBindingList":
@@ -409,8 +486,16 @@ func (f *fakeK8sClientWrapper) DeleteAllOf(ctx context.Context, obj client.Objec
409486
switch u.Object["kind"] {
410487
case "ServiceBinding":
411488
f.cleanupBindings = true
489+
if f.deleteAllOfError != nil {
490+
return f.deleteAllOfError
491+
}
492+
return nil
412493
case "ServiceInstance":
413494
f.cleanupInstances = true
495+
if f.deleteAllOfError != nil {
496+
return f.deleteAllOfError
497+
}
498+
return nil
414499
}
415500
}
416501
return f.fake.DeleteAllOf(ctx, obj, opts...)

0 commit comments

Comments
 (0)