diff --git a/internal/auditlogging/auditlogging.go b/internal/auditlogging/auditlogging.go index c4b47aec..feac599d 100644 --- a/internal/auditlogging/auditlogging.go +++ b/internal/auditlogging/auditlogging.go @@ -147,9 +147,14 @@ func ApplyAuditLogConfig(shoot *gardener.Shoot, auditConfigFromFile map[string]m } changedExt, err := configureExtension(shoot, tenant) + + if err != nil { + return false, err + } + changedSec := configureSecret(shoot, tenant) - return changedExt || changedSec, err + return changedExt || changedSec, nil } func configureExtension(shoot *gardener.Shoot, config AuditLogData) (changed bool, err error) { diff --git a/internal/controller/runtime/fsm/runtime_fsm_configure_auditlog.go b/internal/controller/runtime/fsm/runtime_fsm_configure_auditlog.go index d03cb5d6..04f3a43c 100644 --- a/internal/controller/runtime/fsm/runtime_fsm_configure_auditlog.go +++ b/internal/controller/runtime/fsm/runtime_fsm_configure_auditlog.go @@ -2,6 +2,7 @@ package fsm import ( "context" + k8serrors "k8s.io/apimachinery/pkg/api/errors" imv1 "github.com/kyma-project/infrastructure-manager/api/v1" "github.com/kyma-project/infrastructure-manager/internal/auditlogging" @@ -14,7 +15,7 @@ func sFnConfigureAuditLog(ctx context.Context, m *fsm, s *systemState) (stateFn, wasAuditLogEnabled, err := m.AuditLogging.Enable(ctx, s.shoot) - if wasAuditLogEnabled { + if wasAuditLogEnabled && err == nil { m.log.Info("Audit Log configured for shoot: " + s.shoot.Name) s.instance.UpdateStatePending( imv1.ConditionTypeAuditLogConfigured, @@ -27,6 +28,16 @@ func sFnConfigureAuditLog(ctx context.Context, m *fsm, s *systemState) (stateFn, } if err != nil { //nolint:nestif + if k8serrors.IsConflict(err) { + m.log.Error(err, "Conflict while updating Shoot object after applying Audit Log configuration, retrying") + s.instance.UpdateStatePending( + imv1.ConditionTypeAuditLogConfigured, + imv1.ConditionReasonAuditLogError, + "True", + err.Error(), + ) + return updateStatusAndRequeue() + } errorMessage := err.Error() if errors.Is(err, auditlogging.ErrMissingMapping) { if m.RCCfg.AuditLogMandatory { diff --git a/internal/controller/runtime/fsm/runtime_fsm_configure_auditlog_test.go b/internal/controller/runtime/fsm/runtime_fsm_configure_auditlog_test.go index 925a93f2..b8bad745 100644 --- a/internal/controller/runtime/fsm/runtime_fsm_configure_auditlog_test.go +++ b/internal/controller/runtime/fsm/runtime_fsm_configure_auditlog_test.go @@ -3,6 +3,7 @@ package fsm import ( "context" "github.com/kyma-project/infrastructure-manager/internal/auditlogging" + k8serrors "k8s.io/apimachinery/pkg/api/errors" "testing" gardener "github.com/gardener/gardener/pkg/apis/core/v1beta1" @@ -236,6 +237,43 @@ func TestAuditLogState(t *testing.T) { assert.Equal(t, v1.RuntimeStateReady, string(systemState.instance.Status.State)) assert.Equal(t, expectedRuntimeConditions, systemState.instance.Status.Conditions) }) + + t.Run("Should requeue in case of Kubernetes object conflict error during update of Shoot object and set status on Runtime CR", func(t *testing.T) { + // given + ctx := context.Background() + auditLog := &mocks.AuditLogging{} + shoot := shootForTest() + instance := runtimeForTest() + systemState := &systemState{ + instance: instance, + shoot: shoot, + } + expectedRuntimeConditions := []metav1.Condition{ + { + Type: string(v1.ConditionTypeAuditLogConfigured), + Status: "True", + Reason: string(v1.ConditionReasonAuditLogError), + Message: k8serrors.NewConflict(gardener.Resource("shoots"), shoot.Name, errors.New("k8s conflict on update error")).Error(), + }, + } + + fsm := &fsm{AuditLogging: auditLog} + fsm.RCCfg.AuditLogMandatory = true + + auditLog.On("Enable", ctx, shoot).Return(false, k8serrors.NewConflict(gardener.Resource("shoots"), shoot.Name, errors.New("k8s conflict on update error"))).Once() + + // when + stateFn, _, _ := sFnConfigureAuditLog(ctx, fsm, systemState) + + // set the time to its zero value for comparison purposes + systemState.instance.Status.Conditions[0].LastTransitionTime = metav1.Time{} + + // then + auditLog.AssertExpectations(t) + require.Contains(t, stateFn.name(), "sFnUpdateStatus") + assert.Equal(t, v1.RuntimeStatePending, string(systemState.instance.Status.State)) + assert.Equal(t, expectedRuntimeConditions, systemState.instance.Status.Conditions) + }) } func shootForTest() *gardener.Shoot { diff --git a/internal/controller/runtime/fsm/runtime_fsm_waiting_for_shoot_reconcile.go b/internal/controller/runtime/fsm/runtime_fsm_waiting_for_shoot_reconcile.go index ce700502..a4a8fb5f 100644 --- a/internal/controller/runtime/fsm/runtime_fsm_waiting_for_shoot_reconcile.go +++ b/internal/controller/runtime/fsm/runtime_fsm_waiting_for_shoot_reconcile.go @@ -49,7 +49,7 @@ func sFnWaitForShootReconcile(_ context.Context, m *fsm, s *systemState) (stateF imv1.ConditionTypeRuntimeProvisioned, imv1.ConditionReasonAuditLogConfigured, "Runtime processing completed successfully", - sFnConfigureAuditLog) + sFnApplyClusterRoleBindings) } m.log.Info("Update did not processed, exiting with no retry")