formolcli/pkg/controllers/restoresession_controller.go

124 lines
4.9 KiB
Go

package controllers
import (
"context"
"fmt"
formolv1alpha1 "github.com/desmo999r/formol/api/v1alpha1"
"github.com/desmo999r/formolcli/pkg/restic"
formolcliutils "github.com/desmo999r/formolcli/pkg/utils"
"github.com/go-logr/logr"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"os"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/event"
"sigs.k8s.io/controller-runtime/pkg/predicate"
"strings"
"time"
)
type RestoreSessionReconciler struct {
client.Client
Log logr.Logger
Scheme *runtime.Scheme
RestoreSession *formolv1alpha1.RestoreSession
BackupSession *formolv1alpha1.BackupSession
BackupConf *formolv1alpha1.BackupConfiguration
}
func (r *RestoreSessionReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
time.Sleep(300 * time.Millisecond)
ctx := context.Background()
log := r.Log.WithValues("restoresession", req.NamespacedName)
r.RestoreSession = &formolv1alpha1.RestoreSession{}
if err := r.Get(ctx, req.NamespacedName, r.RestoreSession); err != nil {
log.Error(err, "unable to get restoresession")
return ctrl.Result{}, client.IgnoreNotFound(err)
}
r.BackupSession = &formolv1alpha1.BackupSession{}
if err := r.Get(ctx, client.ObjectKey{
Namespace: r.RestoreSession.Spec.BackupSessionRef.Namespace,
Name: r.RestoreSession.Spec.BackupSessionRef.Name}, r.BackupSession); err != nil {
log.Error(err, "unable to get backupsession", "namespace", r.RestoreSession.Spec.BackupSessionRef.Namespace, "name", r.RestoreSession.Spec.BackupSessionRef.Name)
return ctrl.Result{}, client.IgnoreNotFound(err)
}
r.BackupConf = &formolv1alpha1.BackupConfiguration{}
if err := r.Get(ctx, client.ObjectKey{Namespace: r.BackupSession.Namespace,
Name: r.BackupSession.Spec.Ref.Name}, r.BackupConf); err != nil {
log.Error(err, "unable to get backupconfiguration")
return ctrl.Result{}, client.IgnoreNotFound(err)
}
deploymentName := os.Getenv("POD_DEPLOYMENT")
for _, target := range r.BackupConf.Spec.Targets {
switch target.Kind {
case "Deployment":
if target.Name == deploymentName {
for i, status := range r.RestoreSession.Status.Targets {
if status.Name == target.Name {
log.V(0).Info("It's for us!", "target", target.Name)
switch status.SessionState {
case formolv1alpha1.New:
log.V(0).Info("New session, run the beforeBackup hooks if any")
result := formolv1alpha1.Running
if err := formolcliutils.RunBeforeBackup(target); err != nil {
result = formolv1alpha1.Failure
}
r.RestoreSession.Status.Targets[i].SessionState = result
if err := r.Status().Update(ctx, r.RestoreSession); err != nil {
log.Error(err, " unable to update restoresession status")
return ctrl.Result{RequeueAfter: 30 * time.Second}, err
}
case formolv1alpha1.Running:
log.V(0).Info("Running session. Do the restore")
status.StartTime = &metav1.Time{Time: time.Now()}
result := formolv1alpha1.Success
repo := &formolv1alpha1.Repo{}
if err := r.Get(ctx, client.ObjectKey{
Namespace: r.BackupConf.Namespace,
Name: r.BackupConf.Spec.Repository.Name,
}, repo); err != nil {
log.Error(err, "unable to get Repo from BackupConf")
return ctrl.Result{}, err
}
url := fmt.Sprintf("s3:http://%s/%s/%s-%s", repo.Spec.Backend.S3.Server, repo.Spec.Backend.S3.Bucket, strings.ToUpper(r.BackupConf.Namespace), strings.ToLower(r.BackupConf.Name))
log.V(0).Info("restoring", "url", url, "snapshot", r.BackupSession.Status.Targets[i].SnapshotId)
output, err := restic.RestorePaths(url, r.BackupSession.Status.Targets[i].SnapshotId)
if err != nil {
log.Error(err, "unable to restore deployment", "output", string(output))
result = formolv1alpha1.Failure
} else {
duration := restic.GetRestoreResults(output)
r.RestoreSession.Status.Targets[i].Duration = &metav1.Duration{Duration: duration}
}
r.RestoreSession.Status.Targets[i].SessionState = result
log.V(1).Info("current restoresession status", "status", result)
if err := r.Status().Update(ctx, r.RestoreSession); err != nil {
log.Error(err, "unable to update restoresession status")
return ctrl.Result{RequeueAfter: 30 * time.Second}, err
}
case formolv1alpha1.Failure, formolv1alpha1.Success:
log.V(0).Info("Restore is over, run afterBackup hooks if any")
formolcliutils.RunAfterBackup(target)
}
}
}
}
}
}
return ctrl.Result{}, nil
}
func (r *RestoreSessionReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&formolv1alpha1.RestoreSession{}).
WithEventFilter(predicate.Funcs{
CreateFunc: func(e event.CreateEvent) bool { return false },
DeleteFunc: func(e event.DeleteEvent) bool { return false },
}).
Complete(r)
}