Signed-off-by: Andrey Kolkov <androndo@gmail.com>
(cherry picked from commit 5e15a75d89)
Signed-off-by: Timofei Larkin <lllamnyp@gmail.com>
111 lines
3.5 KiB
Go
111 lines
3.5 KiB
Go
package backupcontroller
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
|
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
|
"k8s.io/apimachinery/pkg/api/meta"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apimachinery/pkg/runtime"
|
|
"k8s.io/apimachinery/pkg/types"
|
|
"k8s.io/client-go/dynamic"
|
|
"k8s.io/client-go/rest"
|
|
"k8s.io/client-go/tools/record"
|
|
ctrl "sigs.k8s.io/controller-runtime"
|
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
|
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
|
|
"sigs.k8s.io/controller-runtime/pkg/log"
|
|
|
|
strategyv1alpha1 "github.com/cozystack/cozystack/api/backups/strategy/v1alpha1"
|
|
backupsv1alpha1 "github.com/cozystack/cozystack/api/backups/v1alpha1"
|
|
)
|
|
|
|
// BackupVeleroStrategyReconciler reconciles BackupJob with a strategy referencing
|
|
// Velero.strategy.backups.cozystack.io objects.
|
|
type BackupJobReconciler struct {
|
|
client.Client
|
|
dynamic.Interface
|
|
meta.RESTMapper
|
|
Scheme *runtime.Scheme
|
|
Recorder record.EventRecorder
|
|
}
|
|
|
|
func (r *BackupJobReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
|
|
logger := log.FromContext(ctx)
|
|
logger.Info("reconciling BackupJob", "namespace", req.Namespace, "name", req.Name)
|
|
|
|
j := &backupsv1alpha1.BackupJob{}
|
|
err := r.Get(ctx, types.NamespacedName{Namespace: req.Namespace, Name: req.Name}, j)
|
|
if err != nil {
|
|
if apierrors.IsNotFound(err) {
|
|
logger.V(1).Info("BackupJob not found, skipping")
|
|
return ctrl.Result{}, nil
|
|
}
|
|
logger.Error(err, "failed to get BackupJob")
|
|
return ctrl.Result{}, err
|
|
}
|
|
|
|
if j.Spec.StrategyRef.APIGroup == nil {
|
|
return r.markBackupJobFailed(ctx, j, "StrategyRef.APIGroup is nil")
|
|
}
|
|
|
|
if *j.Spec.StrategyRef.APIGroup != strategyv1alpha1.GroupVersion.Group {
|
|
// skip if the strategy group foreign to this controller
|
|
return ctrl.Result{}, nil
|
|
}
|
|
|
|
logger.Info("processing BackupJob", "backupjob", j.Name, "strategyKind", j.Spec.StrategyRef.Kind)
|
|
switch j.Spec.StrategyRef.Kind {
|
|
case strategyv1alpha1.JobStrategyKind:
|
|
return r.reconcileJob(ctx, j)
|
|
case strategyv1alpha1.VeleroStrategyKind:
|
|
return r.reconcileVelero(ctx, j)
|
|
default:
|
|
return r.markBackupJobFailed(ctx, j, fmt.Sprintf("StrategyRef.Kind not supported: %s", j.Spec.StrategyRef.Kind))
|
|
}
|
|
}
|
|
|
|
// SetupWithManager registers our controller with the Manager and sets up watches.
|
|
func (r *BackupJobReconciler) SetupWithManager(mgr ctrl.Manager) error {
|
|
cfg := mgr.GetConfig()
|
|
var err error
|
|
if r.Interface, err = dynamic.NewForConfig(cfg); err != nil {
|
|
return err
|
|
}
|
|
var h *http.Client
|
|
if h, err = rest.HTTPClientFor(cfg); err != nil {
|
|
return err
|
|
}
|
|
if r.RESTMapper, err = apiutil.NewDynamicRESTMapper(cfg, h); err != nil {
|
|
return err
|
|
}
|
|
return ctrl.NewControllerManagedBy(mgr).
|
|
For(&backupsv1alpha1.BackupJob{}).
|
|
Complete(r)
|
|
}
|
|
|
|
func (r *BackupJobReconciler) markBackupJobFailed(ctx context.Context, backupJob *backupsv1alpha1.BackupJob, message string) (ctrl.Result, error) {
|
|
logger := getLogger(ctx)
|
|
now := metav1.Now()
|
|
backupJob.Status.CompletedAt = &now
|
|
backupJob.Status.Phase = backupsv1alpha1.BackupJobPhaseFailed
|
|
backupJob.Status.Message = message
|
|
|
|
// Add condition
|
|
backupJob.Status.Conditions = append(backupJob.Status.Conditions, metav1.Condition{
|
|
Type: "Ready",
|
|
Status: metav1.ConditionFalse,
|
|
Reason: "BackupFailed",
|
|
Message: message,
|
|
LastTransitionTime: now,
|
|
})
|
|
|
|
if err := r.Status().Update(ctx, backupJob); err != nil {
|
|
logger.Error(err, "failed to update BackupJob status to Failed")
|
|
return ctrl.Result{}, err
|
|
}
|
|
logger.Debug("BackupJob failed", "message", message)
|
|
return ctrl.Result{}, nil
|
|
}
|