Skip to content

Commit

Permalink
implement ReconcileAsSecondary
Browse files Browse the repository at this point in the history
Signed-off-by: Ryotaro Banno <ryotaro.banno@gmail.com>
  • Loading branch information
ushitora-anqou committed Oct 22, 2024
1 parent 16f3258 commit 20688c2
Show file tree
Hide file tree
Showing 2 changed files with 161 additions and 10 deletions.
164 changes: 159 additions & 5 deletions internal/controller/mantlebackup_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -379,8 +379,46 @@ func (r *MantleBackupReconciler) ReconcileAsPrimary(ctx context.Context, backup
return r.replicate(ctx, backup)
}

func (r *MantleBackupReconciler) ReconcileAsSecondary(_ context.Context, _ *mantlev1.MantleBackup) (ctrl.Result, error) {
return ctrl.Result{}, nil
func (r *MantleBackupReconciler) ReconcileAsSecondary(ctx context.Context, backup *mantlev1.MantleBackup) (ctrl.Result, error) {
logger := log.FromContext(ctx)

if !isCreatedWhenMantleControllerWasSecondary(backup) {
logger.Info(
"skipping to reconcile the MantleBackup created by a different mantle-controller to prevent accidental data loss",
)
return ctrl.Result{}, nil
}

target, result, getSnapshotTargetErr := r.getSnapshotTarget(ctx, backup)
switch {
case getSnapshotTargetErr == errSkipProcessing:
return ctrl.Result{}, nil
case isErrTargetPVCNotFound(getSnapshotTargetErr):
// deletion logic may run.
case getSnapshotTargetErr == nil:
default:
return ctrl.Result{}, getSnapshotTargetErr
}
if result.Requeue {
return result, nil
}

if !backup.ObjectMeta.DeletionTimestamp.IsZero() {
return r.finalize(ctx, backup, target, isErrTargetPVCNotFound(getSnapshotTargetErr))
}

if getSnapshotTargetErr != nil {
return ctrl.Result{}, getSnapshotTargetErr
}

if !meta.IsStatusConditionTrue(backup.Status.Conditions, mantlev1.BackupConditionReadyToUse) {
result, err := r.startImport(ctx, backup, target)
if err != nil || !result.IsZero() {
return result, err
}
}

return r.secondaryCleanup(ctx, backup)
}

func scheduleExpire(_ context.Context, evt event.GenericEvent, q workqueue.RateLimitingInterface) {
Expand Down Expand Up @@ -600,9 +638,20 @@ func (r *MantleBackupReconciler) finalize(
return ctrl.Result{Requeue: true}, nil
}

result, err := r.primaryCleanup(ctx, backup)
if err != nil || result != (ctrl.Result{}) {
return result, err
switch r.role {
case RoleStandalone:
fallthrough
case RolePrimary:
result, err := r.primaryCleanup(ctx, backup)
if err != nil || result != (ctrl.Result{}) {
return result, err
}

case RoleSecondary:
result, err := r.secondaryCleanup(ctx, backup)
if err != nil || result != (ctrl.Result{}) {
return result, err
}
}

if !controllerutil.ContainsFinalizer(backup, MantleBackupFinalizerName) {
Expand Down Expand Up @@ -780,6 +829,104 @@ func (r *MantleBackupReconciler) export(
return ctrl.Result{}, nil
}

func (r *MantleBackupReconciler) startImport(
ctx context.Context,
backup *mantlev1.MantleBackup,
target *snapshotTarget,
) (ctrl.Result, error) { //nolint:unparam
if result, err := r.checkExportDataAlreadyUploaded(ctx, backup); err != nil || !result.IsZero() {
return result, err
}

// Requeue if the PV is smaller than the PVC. (This may be the case if pvc-autoresizer is used.)
if isPVSmallerThanPVC(target.pv, target.pvc) {
return ctrl.Result{Requeue: true}, nil
}

if err := r.updateStatusManifests(ctx, backup, target.pv, target.pvc); err != nil {
return ctrl.Result{}, err
}

if result, err := r.reconcileDiscardJob(ctx, backup, target); err != nil || !result.IsZero() {
return result, err
}

if result, err := r.reconcileImportJob(ctx, backup, target); err != nil || !result.IsZero() {
return result, err
}

return ctrl.Result{}, nil
}

func (r *MantleBackupReconciler) checkExportDataAlreadyUploaded(
_ context.Context,
_ *mantlev1.MantleBackup,
) (ctrl.Result, error) { //nolint:unparam
return ctrl.Result{}, nil
}

func isPVSmallerThanPVC(
pv *corev1.PersistentVolume,
pvc *corev1.PersistentVolumeClaim,
) bool {
return pv.Spec.Capacity.Storage().Cmp(*pvc.Spec.Resources.Requests.Storage()) == -1
}

func (r *MantleBackupReconciler) updateStatusManifests(
ctx context.Context,
backup *mantlev1.MantleBackup,
pv *corev1.PersistentVolume,
pvc *corev1.PersistentVolumeClaim,
) error {
return updateStatus(ctx, r.Client, backup, func() error {
pvJSON, err := json.Marshal(*pv)
if err != nil {
return err
}
backup.Status.PVManifest = string(pvJSON)

pvcJSON, err := json.Marshal(*pvc)
if err != nil {
return err
}
backup.Status.PVCManifest = string(pvcJSON)

return nil
})
}

func (r *MantleBackupReconciler) reconcileDiscardJob(
_ context.Context,
backup *mantlev1.MantleBackup,
_ *snapshotTarget,
) (ctrl.Result, error) { //nolint:unparam
if backup.GetAnnotations()[annotSyncMode] != syncModeFull {
return ctrl.Result{}, nil
}

// FIXME: implement here later

return ctrl.Result{}, nil
}

func (r *MantleBackupReconciler) reconcileImportJob(
ctx context.Context,
backup *mantlev1.MantleBackup,
_ *snapshotTarget,
) (ctrl.Result, error) { //nolint:unparam
// FIXME: implement here later

if err := r.updateStatusCondition(ctx, backup, metav1.Condition{
Type: mantlev1.BackupConditionReadyToUse,
Status: metav1.ConditionTrue,
Reason: mantlev1.BackupReasonNone,
}); err != nil {
return ctrl.Result{}, err
}

return ctrl.Result{}, nil
}

func (r *MantleBackupReconciler) primaryCleanup(
ctx context.Context,
backup *mantlev1.MantleBackup,
Expand All @@ -799,3 +946,10 @@ func (r *MantleBackupReconciler) primaryCleanup(

return ctrl.Result{}, nil
}

func (r *MantleBackupReconciler) secondaryCleanup(
_ context.Context,
_ *mantlev1.MantleBackup,
) (ctrl.Result, error) { // nolint:unparam
return ctrl.Result{}, nil
}
7 changes: 2 additions & 5 deletions test/e2e/multik8s/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,11 +151,8 @@ func replicationTestSuite() {
if secondaryMB.Status.SnapID != nil {
return errors.New(".Status.SapID is incorrectly populated")
}
if secondaryMB.Status.PVManifest != "" {
return errors.New(".Status.PVManifest is incorrectly populated")
}
if secondaryMB.Status.PVCManifest != "" {
return errors.New(".Status.PVCManifest is incorrectly populated")
if !meta.IsStatusConditionTrue(secondaryMB.Status.Conditions, "ReadyToUse") {
return errors.New("ReadyToUse of .Status.Conditions is not True")
}

return nil
Expand Down

0 comments on commit 20688c2

Please sign in to comment.