diff --git a/pkg/controllers/statefulset/statefulset_controller.go b/pkg/controllers/statefulset/statefulset_controller.go index f39ed9484..968128646 100644 --- a/pkg/controllers/statefulset/statefulset_controller.go +++ b/pkg/controllers/statefulset/statefulset_controller.go @@ -110,12 +110,20 @@ func (r *StatefulSetReconciler) processDelete(ctx context.Context, namespacedNam if err != nil { // StatusUpdater is a struct, not a pointer/interface. So we check if its Client field is initialized. if r.StatusUpdater.Client != nil { - r.StatusUpdater.DeleteFail(namespacedName, sts, err) + if sts == nil { + r.StatusUpdater.DeleteFail(namespacedName, nil, err) + } else { + r.StatusUpdater.DeleteFail(namespacedName, sts, err) + } } return common.ResultRequeue, err } if r.StatusUpdater.Client != nil { - r.StatusUpdater.DeleteSuccess(namespacedName, sts) + if sts == nil { + r.StatusUpdater.DeleteSuccess(namespacedName, nil) + } else { + r.StatusUpdater.DeleteSuccess(namespacedName, sts) + } } if pendingRunningPod { return ctrl.Result{RequeueAfter: stsSubnetPortPendingRequeueAfter}, nil diff --git a/pkg/controllers/statefulset/statefulset_controller_test.go b/pkg/controllers/statefulset/statefulset_controller_test.go index bb42617ad..076bdf6fb 100644 --- a/pkg/controllers/statefulset/statefulset_controller_test.go +++ b/pkg/controllers/statefulset/statefulset_controller_test.go @@ -1923,6 +1923,93 @@ func TestProcessDelete_ReleaseSubnetPortsError(t *testing.T) { assert.Equal(t, common.ResultRequeue, res) } +func TestProcessDelete_SuccessWithNilSts(t *testing.T) { + fakeClient := fake.NewClientBuilder().Build() + subnetPortService := &subnetportservice.SubnetPortService{SubnetPortStore: &subnetportservice.SubnetPortStore{}} + r := &StatefulSetReconciler{ + Client: fakeClient, + SubnetPortService: subnetPortService, + Recorder: fakeRecorder{}, + } + r.StatusUpdater = common.NewStatusUpdater(fakeClient, r.SubnetPortService.NSXConfig, r.Recorder, MetricResTypeStatefulSet, "SubnetPort", "StatefulSet") + + called := false + patches := gomonkey.ApplyFunc((*subnetportservice.SubnetPortService).ListSubnetPortByStsName, + func(s *subnetportservice.SubnetPortService, ns, stsName string) []*model.VpcSubnetPort { + return []*model.VpcSubnetPort{} + }) + patches.ApplyFunc((*common.StatusUpdater).DeleteSuccess, + func(u *common.StatusUpdater, namespacedName types.NamespacedName, obj client.Object) { + called = true + assert.Nil(t, obj) + }) + defer patches.Reset() + + res, err := r.processDelete(context.Background(), types.NamespacedName{Namespace: "default", Name: "sts"}, nil) + assert.NoError(t, err) + assert.Equal(t, common.ResultNormal, res) + assert.True(t, called) +} + +func TestProcessDelete_SuccessWithSts(t *testing.T) { + fakeClient := fake.NewClientBuilder().Build() + subnetPortService := &subnetportservice.SubnetPortService{SubnetPortStore: &subnetportservice.SubnetPortStore{}} + r := &StatefulSetReconciler{ + Client: fakeClient, + SubnetPortService: subnetPortService, + Recorder: fakeRecorder{}, + } + r.StatusUpdater = common.NewStatusUpdater(fakeClient, r.SubnetPortService.NSXConfig, r.Recorder, MetricResTypeStatefulSet, "SubnetPort", "StatefulSet") + + sts := &appsv1.StatefulSet{ObjectMeta: metav1.ObjectMeta{Name: "test-sts", Namespace: "default"}} + called := false + patches := gomonkey.ApplyFunc((*subnetportservice.SubnetPortService).ListSubnetPortByStsName, + func(s *subnetportservice.SubnetPortService, ns, stsName string) []*model.VpcSubnetPort { + return []*model.VpcSubnetPort{} + }) + patches.ApplyFunc((*common.StatusUpdater).DeleteSuccess, + func(u *common.StatusUpdater, namespacedName types.NamespacedName, obj client.Object) { + called = true + assert.Same(t, sts, obj) + }) + defer patches.Reset() + + res, err := r.processDelete(context.Background(), types.NamespacedName{Namespace: "default", Name: "sts"}, sts) + assert.NoError(t, err) + assert.Equal(t, common.ResultNormal, res) + assert.True(t, called) +} + +func TestProcessDelete_ErrorWithSts(t *testing.T) { + fakeClient := fake.NewClientBuilder().Build() + subnetPortService := &subnetportservice.SubnetPortService{SubnetPortStore: &subnetportservice.SubnetPortStore{}} + r := &StatefulSetReconciler{ + Client: fakeClient, + SubnetPortService: subnetPortService, + Recorder: fakeRecorder{}, + } + r.StatusUpdater = common.NewStatusUpdater(fakeClient, r.SubnetPortService.NSXConfig, r.Recorder, MetricResTypeStatefulSet, "SubnetPort", "StatefulSet") + + sts := &appsv1.StatefulSet{ObjectMeta: metav1.ObjectMeta{Name: "test-sts", Namespace: "default"}} + called := false + patches := gomonkey.ApplyFunc((*StatefulSetReconciler).releaseSubnetPortsForStatefulSet, + func(r *StatefulSetReconciler, ctx context.Context, namespace, name string) (bool, error) { + return false, errors.New("release error") + }) + patches.ApplyFunc((*common.StatusUpdater).DeleteFail, + func(u *common.StatusUpdater, namespacedName types.NamespacedName, obj client.Object, err error) { + called = true + assert.Same(t, sts, obj) + assert.EqualError(t, err, "release error") + }) + defer patches.Reset() + + res, err := r.processDelete(context.Background(), types.NamespacedName{Namespace: "default", Name: "sts"}, sts) + assert.Error(t, err) + assert.Equal(t, common.ResultRequeue, res) + assert.True(t, called) +} + func TestProcessDelete_PendingRunningPodRequeues(t *testing.T) { livePodUID := types.UID("aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee") fakeClient := fake.NewClientBuilder().WithObjects(&corev1.Pod{