in oracle/controllers/backupcontroller/backup_controller.go [227:336]
func (r *BackupReconciler) reconcileBackupCreation(ctx context.Context, backup *v1alpha1.Backup, log logr.Logger) (ctrl.Result, error) {
if v := r.BackupCtrl.ValidateBackupSpec(backup); !v {
return ctrl.Result{}, r.BackupCtrl.UpdateStatus(backup)
}
state := ""
backupReadyCond := k8s.FindCondition(backup.Status.Conditions, k8s.Ready)
if backupReadyCond != nil {
state = backupReadyCond.Reason
}
switch state {
case "":
backup.Status.Conditions = k8s.Upsert(backup.Status.Conditions, k8s.Ready, v1.ConditionFalse, k8s.BackupPending, "Waiting for the instance to be ready.")
backup.Status.Phase = commonv1alpha1.BackupPending
log.Info("reconcileBackupCreation: ->BackupPending")
return ctrl.Result{RequeueAfter: requeueInterval}, r.BackupCtrl.UpdateStatus(backup)
case k8s.BackupPending:
inst, err := r.instReady(ctx, backup.Namespace, backup.Spec.Instance)
// ensure the inst is ready to create a backup
if err != nil {
msg := fmt.Sprintf("instance not ready: %v", err)
r.Recorder.Event(backup, corev1.EventTypeWarning, k8s.BackupFailed, msg)
backup.Status.Conditions = k8s.Upsert(backup.Status.Conditions, k8s.Ready, v1.ConditionFalse, k8s.BackupFailed, msg)
backup.Status.Phase = commonv1alpha1.BackupFailed
log.Info("reconcileBackupCreation: BackupPending->BackupFailed")
return ctrl.Result{}, r.BackupCtrl.UpdateStatus(backup)
}
// backup type is validated in validateBackupSpec
b := r.OracleBackupFactory.newOracleBackup(r, backup, inst, log)
if backup.Status.BackupID == "" || backup.Status.BackupTime == "" || backup.Status.StartTime == nil {
backup.Status.BackupID = b.generateID()
backup.Status.BackupTime = timeNow().Format("20060102150405")
startTime := metav1.NewTime(timeNow())
backup.Status.StartTime = &startTime
log.Info("backup started at:", "StartTime", backup.Status.StartTime)
// commit backup id and time
return ctrl.Result{RequeueAfter: requeueInterval}, r.updateBackupStatus(ctx, backup, inst)
}
if err := r.addBackupMetadata(ctx, backup, &oracleBackupMetadata{
incarnation: inst.Status.CurrentDatabaseIncarnation,
parentIncarnation: inst.Status.LastDatabaseIncarnation,
databaseImage: inst.Status.ActiveImages["service"],
}); err != nil {
return ctrl.Result{}, err
}
if err := b.create(ctx); err != nil {
// default retry
return ctrl.Result{}, err
}
backup.Status.Conditions = k8s.Upsert(backup.Status.Conditions, k8s.Ready, v1.ConditionFalse, k8s.BackupInProgress, "Starting to create a backup.")
log.Info("reconcileBackupCreation: BackupPending->BackupInProgress")
return ctrl.Result{RequeueAfter: requeueInterval}, r.updateBackupStatus(ctx, backup, inst)
case k8s.BackupInProgress:
inst, err := r.BackupCtrl.GetInstance(backup.Spec.Instance, backup.Namespace)
if err != nil {
return ctrl.Result{}, err
}
// backup type is validated in validateBackupSpec
b := r.OracleBackupFactory.newOracleBackup(r, backup, inst, log)
done, err := b.status(ctx)
if err != nil && strings.Contains(err.Error(), "code = NotFound") {
// The backup was interrupted and the LRO is lost.
backup.Status.Conditions = k8s.Upsert(backup.Status.Conditions, k8s.Ready, v1.ConditionFalse, k8s.BackupFailed, "Backup interrupted")
return ctrl.Result{}, r.updateBackupStatus(ctx, backup, inst)
}
if done {
if err == nil {
r.Recorder.Eventf(backup, corev1.EventTypeNormal, "BackupCompleted", "BackupId:%v, Elapsed time: %v", backup.Status.BackupID, k8s.ElapsedTimeFromLastTransitionTime(k8s.FindCondition(backup.Status.Conditions, k8s.Ready), time.Second))
backupMetadata, err := b.metadata(ctx)
if err != nil {
return ctrl.Result{}, err
}
if err := r.addBackupMetadata(ctx, backup, backupMetadata); err != nil {
return ctrl.Result{}, err
}
backup.Status.Conditions = k8s.Upsert(backup.Status.Conditions, k8s.Ready, v1.ConditionTrue, k8s.BackupReady, "")
duration := metav1.Duration{Duration: metav1.Now().Sub(backup.Status.StartTime.Time)}
backup.Status.Duration = &duration
backup.Status.GcsPath = controllers.GetBackupGcsPath(backup)
log.Info("reconcileBackupCreation: BackupInProgress->BackupReady")
} else {
r.Recorder.Event(backup, corev1.EventTypeWarning, "BackupFailed", err.Error())
backup.Status.Conditions = k8s.Upsert(backup.Status.Conditions, k8s.Ready, v1.ConditionFalse, k8s.BackupFailed, err.Error())
log.Info("reconcileBackupCreation: BackupInProgress->BackupFailed")
}
log.Info("reconciling backup creation: DONE")
return ctrl.Result{}, r.updateBackupStatus(ctx, backup, inst)
}
log.Info("reconciling backup creation: InProgress")
return ctrl.Result{RequeueAfter: statusCheckInterval}, nil
case k8s.BackupReady:
// Add finalizer to clean backup data in case of deletion.
if !controllerutil.ContainsFinalizer(backup, controllers.FinalizerName) {
log.Info("Adding backup finalizer.")
controllerutil.AddFinalizer(backup, controllers.FinalizerName)
// Immediately return to update the object and do the rest of work in the next reconcile cycle.
return ctrl.Result{}, r.Update(ctx, backup)
}
return ctrl.Result{}, nil
default:
log.Info("no action needed", "backupReady", backupReadyCond)
return ctrl.Result{}, nil
}
}