moved to kubebuilder 0.8.3 and removed unecessary loops and check if the restore job exists before creating it

This commit is contained in:
jandre 2021-05-08 23:00:55 +02:00
parent 477022347d
commit 9c15bcc470
4 changed files with 225 additions and 185 deletions

View File

@ -33,7 +33,7 @@ import (
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller"
//"sigs.k8s.io/controller-runtime/pkg/predicate"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
formolv1alpha1 "github.com/desmo999r/formol/api/v1alpha1"
)
@ -45,6 +45,8 @@ type BackupConfigurationReconciler struct {
Scheme *runtime.Scheme
}
var _ reconcile.Reconciler = &BackupConfigurationReconciler{}
// +kubebuilder:rbac:groups=formol.desmojim.fr,resources=*,verbs=*
// +kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=apps,resources=replicasets,verbs=get;list;watch;create;update;patch;delete
@ -57,9 +59,8 @@ type BackupConfigurationReconciler struct {
// +kubebuilder:rbac:groups=batch,resources=cronjobs,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=batch,resources=cronjobs/status,verbs=get
func (r *BackupConfigurationReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
func (r *BackupConfigurationReconciler) Reconcile(ctx context.Context, req reconcile.Request) (reconcile.Result, error) {
var changed bool
ctx := context.Background()
log := r.Log.WithValues("backupconfiguration", req.NamespacedName)
//time.Sleep(300 * time.Millisecond)
@ -67,7 +68,7 @@ func (r *BackupConfigurationReconciler) Reconcile(req ctrl.Request) (ctrl.Result
backupConf := &formolv1alpha1.BackupConfiguration{}
if err := r.Get(ctx, req.NamespacedName, backupConf); err != nil {
return ctrl.Result{}, client.IgnoreNotFound(err)
return reconcile.Result{}, client.IgnoreNotFound(err)
}
getDeployment := func(namespace string, name string) (*appsv1.Deployment, error) {
@ -307,12 +308,12 @@ func (r *BackupConfigurationReconciler) Reconcile(req ctrl.Request) (ctrl.Result
backupConf.ObjectMeta.Finalizers = formolutils.RemoveString(backupConf.ObjectMeta.Finalizers, finalizerName)
if err := r.Update(context.Background(), backupConf); err != nil {
log.Error(err, "unable to remove finalizer")
return ctrl.Result{}, err
return reconcile.Result{}, err
}
}
// We have been deleted. Return here
log.V(0).Info("backupconf deleted", "backupconf", backupConf.Name)
return ctrl.Result{}, nil
return reconcile.Result{}, nil
}
// Add finalizer
@ -322,11 +323,11 @@ func (r *BackupConfigurationReconciler) Reconcile(req ctrl.Request) (ctrl.Result
if err != nil {
log.Error(err, "unable to append finalizer")
}
return ctrl.Result{}, err
return reconcile.Result{}, err
}
if err := addCronJob(); err != nil {
return ctrl.Result{}, nil
return reconcile.Result{}, nil
} else {
backupConf.Status.ActiveCronJob = true
}
@ -335,7 +336,7 @@ func (r *BackupConfigurationReconciler) Reconcile(req ctrl.Request) (ctrl.Result
switch target.Kind {
case formolv1alpha1.SidecarKind:
if err := addSidecarContainer(target); err != nil {
return ctrl.Result{}, client.IgnoreNotFound(err)
return reconcile.Result{}, client.IgnoreNotFound(err)
} else {
backupConf.Status.ActiveSidecar = true
}
@ -347,11 +348,11 @@ func (r *BackupConfigurationReconciler) Reconcile(req ctrl.Request) (ctrl.Result
log.V(1).Info("updating backupconf")
if err := r.Status().Update(ctx, backupConf); err != nil {
log.Error(err, "unable to update backupconf", "backupconf", backupConf)
return ctrl.Result{}, err
return reconcile.Result{}, err
}
}
return ctrl.Result{}, nil
return reconcile.Result{}, nil
}
func (r *BackupConfigurationReconciler) SetupWithManager(mgr ctrl.Manager) error {

View File

@ -32,6 +32,7 @@ import (
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
formolv1alpha1 "github.com/desmo999r/formol/api/v1alpha1"
formolutils "github.com/desmo999r/formol/pkg/utils"
@ -50,19 +51,20 @@ type BackupSessionReconciler struct {
Scheme *runtime.Scheme
}
var _ reconcile.Reconciler = &BackupSessionReconciler{}
// +kubebuilder:rbac:groups=formol.desmojim.fr,resources=backupsessions,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=formol.desmojim.fr,resources=backupsessions/status,verbs=get;update;patch;create;delete
// +kubebuilder:rbac:groups=formol.desmojim.fr,resources=functions,verbs=get;list;watch
// +kubebuilder:rbac:groups=batch,resources=jobs,verbs=get;list;create;update;patch;delete;watch
func (r *BackupSessionReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
func (r *BackupSessionReconciler) Reconcile(ctx context.Context, req reconcile.Request) (reconcile.Result, error) {
log := r.Log.WithValues("backupsession", req.NamespacedName)
ctx := context.Background()
backupSession := &formolv1alpha1.BackupSession{}
if err := r.Get(ctx, req.NamespacedName, backupSession); err != nil {
log.Error(err, "unable to get backupsession")
return ctrl.Result{}, client.IgnoreNotFound(err)
return reconcile.Result{}, client.IgnoreNotFound(err)
}
backupConf := &formolv1alpha1.BackupConfiguration{}
if err := r.Get(ctx, client.ObjectKey{
@ -70,7 +72,7 @@ func (r *BackupSessionReconciler) Reconcile(req ctrl.Request) (ctrl.Result, erro
Name: backupSession.Spec.Ref.Name,
}, backupConf); err != nil {
log.Error(err, "unable to get backupConfiguration")
return ctrl.Result{}, client.IgnoreNotFound(err)
return reconcile.Result{}, client.IgnoreNotFound(err)
}
// helper functions
@ -358,23 +360,23 @@ func (r *BackupSessionReconciler) Reconcile(req ctrl.Request) (ctrl.Result, erro
if err != nil {
log.Error(err, "unable to add finalizer")
}
return ctrl.Result{}, err
return reconcile.Result{}, err
}
// Brand new backupsession
if isBackupOngoing() {
log.V(0).Info("There is an ongoing backup. Let's reschedule this operation")
return ctrl.Result{RequeueAfter: 30 * time.Second}, nil
return reconcile.Result{RequeueAfter: 30 * time.Second}, nil
}
// start the first task
backupSession.Status.SessionState = formolv1alpha1.Running
targetStatus, err := startNextTask()
if err != nil {
return ctrl.Result{}, err
return reconcile.Result{}, err
}
log.V(0).Info("New backup. Start the first task", "task", targetStatus)
if err := r.Status().Update(ctx, backupSession); err != nil {
log.Error(err, "unable to update BackupSession status")
return ctrl.Result{}, err
return reconcile.Result{}, err
}
case formolv1alpha1.Running:
// Backup ongoing. Check the status of the last task to decide what to do
@ -388,7 +390,7 @@ func (r *BackupSessionReconciler) Reconcile(req ctrl.Request) (ctrl.Result, erro
targetStatus, err := startNextTask()
log.V(0).Info("last task was a success. start a new one", "currentTargetStatus", currentTargetStatus, "targetStatus", targetStatus)
if err != nil {
return ctrl.Result{}, err
return reconcile.Result{}, err
}
if targetStatus == nil {
// No more task to start. The backup is a success
@ -398,7 +400,7 @@ func (r *BackupSessionReconciler) Reconcile(req ctrl.Request) (ctrl.Result, erro
}
if err := r.Status().Update(ctx, backupSession); err != nil {
log.Error(err, "unable to update BackupSession status")
return ctrl.Result{}, err
return reconcile.Result{}, err
}
case formolv1alpha1.Failure:
// last task failed. Try to run it again
@ -413,7 +415,7 @@ func (r *BackupSessionReconciler) Reconcile(req ctrl.Request) (ctrl.Result, erro
if err := createBackupJob(currentTarget); err != nil {
log.V(0).Info("unable to create task", "task", currentTarget)
currentTargetStatus.SessionState = formolv1alpha1.Failure
return ctrl.Result{}, err
return reconcile.Result{}, err
}
}
} else {
@ -422,7 +424,7 @@ func (r *BackupSessionReconciler) Reconcile(req ctrl.Request) (ctrl.Result, erro
}
if err := r.Status().Update(ctx, backupSession); err != nil {
log.Error(err, "unable to update BackupSession status")
return ctrl.Result{}, err
return reconcile.Result{}, err
}
}
case formolv1alpha1.Success:
@ -435,29 +437,29 @@ func (r *BackupSessionReconciler) Reconcile(req ctrl.Request) (ctrl.Result, erro
backupSession.Status.StartTime = &metav1.Time{Time: time.Now()}
if err := r.Status().Update(ctx, backupSession); err != nil {
log.Error(err, "unable to update backupSession")
return ctrl.Result{}, err
return reconcile.Result{}, err
}
}
} else {
log.V(0).Info("backupsession being deleted", "backupsession", backupSession.Name)
if controllerutil.ContainsFinalizer(backupSession, finalizerName) {
if err := deleteExternalResources(); err != nil {
return ctrl.Result{}, err
return reconcile.Result{}, err
}
}
controllerutil.RemoveFinalizer(backupSession, finalizerName)
if err := r.Update(ctx, backupSession); err != nil {
log.Error(err, "unable to remove finalizer")
return ctrl.Result{}, err
return reconcile.Result{}, err
}
// We have been deleted. Return here
return ctrl.Result{}, nil
return reconcile.Result{}, nil
}
return ctrl.Result{}, nil
return reconcile.Result{}, nil
}
func (r *BackupSessionReconciler) SetupWithManager(mgr ctrl.Manager) error {
if err := mgr.GetFieldIndexer().IndexField(context.TODO(), &formolv1alpha1.BackupSession{}, sessionState, func(rawObj runtime.Object) []string {
if err := mgr.GetFieldIndexer().IndexField(context.TODO(), &formolv1alpha1.BackupSession{}, sessionState, func(rawObj client.Object) []string {
session := rawObj.(*formolv1alpha1.BackupSession)
return []string{string(session.Status.SessionState)}
}); err != nil {

View File

@ -31,6 +31,8 @@ import (
"k8s.io/apimachinery/pkg/runtime"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
formolv1alpha1 "github.com/desmo999r/formol/api/v1alpha1"
formolutils "github.com/desmo999r/formol/pkg/utils"
@ -39,6 +41,7 @@ import (
const (
RESTORESESSION string = "restoresession"
UPDATESTATUS string = "updatestatus"
jobOwnerKey string = ".metadata.controller"
)
// RestoreSessionReconciler reconciles a RestoreSession object
@ -48,20 +51,21 @@ type RestoreSessionReconciler struct {
Scheme *runtime.Scheme
}
var _ reconcile.Reconciler = &RestoreSessionReconciler{}
// +kubebuilder:rbac:groups=formol.desmojim.fr,resources=restoresessions,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=formol.desmojim.fr,resources=restoresessions/status,verbs=get;update;patch
func (r *RestoreSessionReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
ctx := context.Background()
log := r.Log.WithValues("restoresession", req.NamespacedName)
func (r *RestoreSessionReconciler) Reconcile(ctx context.Context, req reconcile.Request) (reconcile.Result, error) {
log := log.FromContext(ctx).WithValues("restoresession", req.NamespacedName)
// Get the RestoreSession
restoreSession := &formolv1alpha1.RestoreSession{}
if err := r.Get(ctx, req.NamespacedName, restoreSession); err != nil {
log.Error(err, "unable to get restoresession")
return ctrl.Result{}, client.IgnoreNotFound(err)
return reconcile.Result{}, client.IgnoreNotFound(err)
}
log.V(1).Info("got restoresession", "restoreSession", restoreSession)
log = r.Log.WithValues("restoresession", req.NamespacedName, "version", restoreSession.ObjectMeta.ResourceVersion)
// Get the BackupSession the RestoreSession references
backupSession := &formolv1alpha1.BackupSession{}
if err := r.Get(ctx, client.ObjectKey{
@ -73,10 +77,10 @@ func (r *RestoreSessionReconciler) Reconcile(req ctrl.Request) (ctrl.Result, err
Spec: restoreSession.Spec.BackupSessionRef.Spec,
Status: restoreSession.Spec.BackupSessionRef.Status,
}
log.V(1).Info("generated backupsession", "backupsession", backupSession)
log.V(1).Info("generated backupsession", "spec", backupSession.Spec, "status", backupSession.Status)
} else {
log.Error(err, "unable to get backupsession", "restoresession", restoreSession.Spec)
return ctrl.Result{}, client.IgnoreNotFound(err)
return reconcile.Result{}, client.IgnoreNotFound(err)
}
}
// Get the BackupConfiguration linked to the BackupSession
@ -86,11 +90,24 @@ func (r *RestoreSessionReconciler) Reconcile(req ctrl.Request) (ctrl.Result, err
Name: backupSession.Spec.Ref.Name,
}, backupConf); err != nil {
log.Error(err, "unable to get backupConfiguration", "name", backupSession.Spec.Ref, "namespace", backupSession.Namespace)
return ctrl.Result{}, client.IgnoreNotFound(err)
return reconcile.Result{}, client.IgnoreNotFound(err)
}
// Helper functions
createRestoreJob := func(target formolv1alpha1.Target) error {
createRestoreJob := func(target formolv1alpha1.Target, snapshotId string) error {
// TODO: Get the list of existing jobs and see if there is already one scheduled for the target
var jobList batchv1.JobList
if err := r.List(ctx, &jobList, client.InNamespace(restoreSession.Namespace), client.MatchingFields{jobOwnerKey: restoreSession.Name}); err != nil {
log.Error(err, "unable to get job list")
return err
}
log.V(1).Info("Found jobs", "jobs", jobList.Items)
for _, job := range jobList.Items {
if job.Annotations["targetName"] == target.Name && job.Annotations["snapshotId"] == snapshotId {
log.V(0).Info("there is already a cronjob to restore that target", "targetName", target.Name, "snapshotId", snapshotId)
return nil
}
}
restoreSessionEnv := []corev1.EnvVar{
corev1.EnvVar{
Name: "TARGET_NAME",
@ -110,91 +127,95 @@ func (r *RestoreSessionReconciler) Reconcile(req ctrl.Request) (ctrl.Result, err
Name: "output",
MountPath: "/output",
}
for _, targetStatus := range backupSession.Status.Targets {
if targetStatus.Name == target.Name {
snapshotId := targetStatus.SnapshotId
restic := corev1.Container{
Name: "restic",
Image: "desmo999r/formolcli:latest",
Args: []string{"volume", "restore", "--snapshot-id", snapshotId},
VolumeMounts: []corev1.VolumeMount{output},
Env: restoreSessionEnv,
}
finalizer := corev1.Container{
Name: "finalizer",
Image: "desmo999r/formolcli:latest",
Args: []string{"target", "finalize"},
VolumeMounts: []corev1.VolumeMount{output},
Env: restoreSessionEnv,
}
repo := &formolv1alpha1.Repo{}
if err := r.Get(ctx, client.ObjectKey{
Namespace: backupConf.Namespace,
Name: backupConf.Spec.Repository,
}, repo); err != nil {
log.Error(err, "unable to get Repo from BackupConfiguration")
return err
}
// S3 backing storage
var ttl int32 = 300
restic.Env = append(restic.Env, formolutils.ConfigureResticEnvVar(backupConf, repo)...)
job := &batchv1.Job{
ObjectMeta: metav1.ObjectMeta{
GenerateName: fmt.Sprintf("%s-%s-", restoreSession.Name, target.Name),
Namespace: restoreSession.Namespace,
},
Spec: batchv1.JobSpec{
TTLSecondsAfterFinished: &ttl,
Template: corev1.PodTemplateSpec{
Spec: corev1.PodSpec{
InitContainers: []corev1.Container{restic},
Containers: []corev1.Container{finalizer},
Volumes: []corev1.Volume{
corev1.Volume{Name: "output"},
},
RestartPolicy: corev1.RestartPolicyOnFailure,
},
//for _, targetStatus := range backupSession.Status.Targets {
//if targetStatus.Name == target.Name {
//snapshotId := targetStatus.SnapshotId
restic := corev1.Container{
Name: "restic",
Image: "desmo999r/formolcli:latest",
Args: []string{"volume", "restore", "--snapshot-id", snapshotId},
VolumeMounts: []corev1.VolumeMount{output},
Env: restoreSessionEnv,
}
finalizer := corev1.Container{
Name: "finalizer",
Image: "desmo999r/formolcli:latest",
Args: []string{"target", "finalize"},
VolumeMounts: []corev1.VolumeMount{output},
Env: restoreSessionEnv,
}
repo := &formolv1alpha1.Repo{}
if err := r.Get(ctx, client.ObjectKey{
Namespace: backupConf.Namespace,
Name: backupConf.Spec.Repository,
}, repo); err != nil {
log.Error(err, "unable to get Repo from BackupConfiguration")
return err
}
// S3 backing storage
var ttl int32 = 300
restic.Env = append(restic.Env, formolutils.ConfigureResticEnvVar(backupConf, repo)...)
job := &batchv1.Job{
ObjectMeta: metav1.ObjectMeta{
GenerateName: fmt.Sprintf("%s-%s-", restoreSession.Name, target.Name),
Namespace: restoreSession.Namespace,
Annotations: map[string]string{
"targetName": target.Name,
"snapshotId": snapshotId,
},
},
Spec: batchv1.JobSpec{
TTLSecondsAfterFinished: &ttl,
Template: corev1.PodTemplateSpec{
Spec: corev1.PodSpec{
InitContainers: []corev1.Container{restic},
Containers: []corev1.Container{finalizer},
Volumes: []corev1.Volume{
corev1.Volume{Name: "output"},
},
RestartPolicy: corev1.RestartPolicyOnFailure,
},
}
for _, step := range target.Steps {
function := &formolv1alpha1.Function{}
// get the backup function
if err := r.Get(ctx, client.ObjectKey{
Namespace: restoreSession.Namespace,
Name: step.Name,
}, function); err != nil {
log.Error(err, "unable to get backup function", "name", step.Name)
return err
}
var restoreName string
if function.Annotations["restoreFunction"] != "" {
restoreName = function.Annotations["restoreFunction"]
} else {
restoreName = strings.Replace(step.Name, "backup", "restore", 1)
}
if err := r.Get(ctx, client.ObjectKey{
Namespace: restoreSession.Namespace,
Name: restoreName,
}, function); err != nil {
log.Error(err, "unable to get function", "function", step)
return err
}
function.Spec.Name = function.Name
function.Spec.Env = append(step.Env, restoreSessionEnv...)
function.Spec.VolumeMounts = append(function.Spec.VolumeMounts, output)
job.Spec.Template.Spec.InitContainers = append(job.Spec.Template.Spec.InitContainers, function.Spec)
}
if err := ctrl.SetControllerReference(restoreSession, job, r.Scheme); err != nil {
log.Error(err, "unable to set controller on job", "job", job, "restoresession", restoreSession)
return err
}
log.V(0).Info("creating a restore job", "target", target.Name)
if err := r.Create(ctx, job); err != nil {
log.Error(err, "unable to create job", "job", job)
return err
}
},
},
}
for _, step := range target.Steps {
function := &formolv1alpha1.Function{}
// get the backup function
if err := r.Get(ctx, client.ObjectKey{
Namespace: restoreSession.Namespace,
Name: step.Name,
}, function); err != nil {
log.Error(err, "unable to get backup function", "name", step.Name)
return err
}
var restoreName string
if function.Annotations["restoreFunction"] != "" {
restoreName = function.Annotations["restoreFunction"]
} else {
restoreName = strings.Replace(step.Name, "backup", "restore", 1)
}
if err := r.Get(ctx, client.ObjectKey{
Namespace: restoreSession.Namespace,
Name: restoreName,
}, function); err != nil {
log.Error(err, "unable to get function", "function", step)
return err
}
function.Spec.Name = function.Name
function.Spec.Env = append(step.Env, restoreSessionEnv...)
function.Spec.VolumeMounts = append(function.Spec.VolumeMounts, output)
job.Spec.Template.Spec.InitContainers = append(job.Spec.Template.Spec.InitContainers, function.Spec)
}
if err := ctrl.SetControllerReference(restoreSession, job, r.Scheme); err != nil {
log.Error(err, "unable to set controller on job", "job", job, "restoresession", restoreSession)
return err
}
log.V(0).Info("creating a restore job", "target", target.Name)
if err := r.Create(ctx, job); err != nil {
log.Error(err, "unable to create job", "job", job)
return err
//}
//}
}
return nil
}
@ -225,7 +246,7 @@ func (r *RestoreSessionReconciler) Reconcile(req ctrl.Request) (ctrl.Result, err
return nil
}
createRestoreInitContainer := func(target formolv1alpha1.Target) error {
createRestoreInitContainer := func(target formolv1alpha1.Target, snapshotId string) error {
deployment := &appsv1.Deployment{}
if err := r.Get(context.Background(), client.ObjectKey{
Namespace: restoreSession.Namespace,
@ -241,51 +262,51 @@ func (r *RestoreSessionReconciler) Reconcile(req ctrl.Request) (ctrl.Result, err
return nil
}
}
for _, targetStatus := range backupSession.Status.Targets {
if targetStatus.Name == target.Name && targetStatus.Kind == target.Kind {
snapshotId := targetStatus.SnapshotId
restoreSessionEnv := []corev1.EnvVar{
corev1.EnvVar{
Name: formolv1alpha1.TARGET_NAME,
Value: target.Name,
},
corev1.EnvVar{
Name: formolv1alpha1.RESTORESESSION_NAME,
Value: restoreSession.Name,
},
corev1.EnvVar{
Name: formolv1alpha1.RESTORESESSION_NAMESPACE,
Value: restoreSession.Namespace,
},
}
initContainer := corev1.Container{
Name: RESTORESESSION,
Image: formolutils.FORMOLCLI,
Args: []string{"volume", "restore", "--snapshot-id", snapshotId},
VolumeMounts: target.VolumeMounts,
Env: restoreSessionEnv,
}
repo := &formolv1alpha1.Repo{}
if err := r.Get(ctx, client.ObjectKey{
Namespace: backupConf.Namespace,
Name: backupConf.Spec.Repository,
}, repo); err != nil {
log.Error(err, "unable to get Repo from BackupConfiguration")
return err
}
// S3 backing storage
initContainer.Env = append(initContainer.Env, formolutils.ConfigureResticEnvVar(backupConf, repo)...)
deployment.Spec.Template.Spec.InitContainers = append([]corev1.Container{initContainer},
deployment.Spec.Template.Spec.InitContainers...)
if err := r.Update(ctx, deployment); err != nil {
log.Error(err, "unable to update deployment")
return err
}
return nil
}
//for _, targetStatus := range backupSession.Status.Targets {
//if targetStatus.Name == target.Name && targetStatus.Kind == target.Kind {
//snapshotId := targetStatus.SnapshotId
restoreSessionEnv := []corev1.EnvVar{
corev1.EnvVar{
Name: formolv1alpha1.TARGET_NAME,
Value: target.Name,
},
corev1.EnvVar{
Name: formolv1alpha1.RESTORESESSION_NAME,
Value: restoreSession.Name,
},
corev1.EnvVar{
Name: formolv1alpha1.RESTORESESSION_NAMESPACE,
Value: restoreSession.Namespace,
},
}
initContainer := corev1.Container{
Name: RESTORESESSION,
Image: formolutils.FORMOLCLI,
Args: []string{"volume", "restore", "--snapshot-id", snapshotId},
VolumeMounts: target.VolumeMounts,
Env: restoreSessionEnv,
}
repo := &formolv1alpha1.Repo{}
if err := r.Get(ctx, client.ObjectKey{
Namespace: backupConf.Namespace,
Name: backupConf.Spec.Repository,
}, repo); err != nil {
log.Error(err, "unable to get Repo from BackupConfiguration")
return err
}
// S3 backing storage
initContainer.Env = append(initContainer.Env, formolutils.ConfigureResticEnvVar(backupConf, repo)...)
deployment.Spec.Template.Spec.InitContainers = append([]corev1.Container{initContainer},
deployment.Spec.Template.Spec.InitContainers...)
if err := r.Update(ctx, deployment); err != nil {
log.Error(err, "unable to update deployment")
return err
}
return nil
//}
//}
//return nil
}
startNextTask := func() (*formolv1alpha1.TargetStatus, error) {
@ -301,13 +322,13 @@ func (r *RestoreSessionReconciler) Reconcile(req ctrl.Request) (ctrl.Result, err
restoreSession.Status.Targets = append(restoreSession.Status.Targets, targetStatus)
switch target.Kind {
case formolv1alpha1.SidecarKind:
if err := createRestoreInitContainer(target); err != nil {
if err := createRestoreInitContainer(target, backupSession.Status.Targets[nextTarget].SnapshotId); err != nil {
log.V(0).Info("unable to create restore init container", "task", target)
targetStatus.SessionState = formolv1alpha1.Failure
return nil, err
}
case formolv1alpha1.JobKind:
if err := createRestoreJob(target); err != nil {
if err := createRestoreJob(target, backupSession.Status.Targets[nextTarget].SnapshotId); err != nil {
log.V(0).Info("unable to create restore job", "task", target)
targetStatus.SessionState = formolv1alpha1.Failure
return nil, err
@ -336,12 +357,12 @@ func (r *RestoreSessionReconciler) Reconcile(req ctrl.Request) (ctrl.Result, err
restoreSession.Status.SessionState = formolv1alpha1.Running
if targetStatus, err := startNextTask(); err != nil {
log.Error(err, "unable to start next restore task")
return ctrl.Result{}, err
return reconcile.Result{}, err
} else {
log.V(0).Info("New restore. Start the first task", "task", targetStatus.Name)
if err := r.Status().Update(ctx, restoreSession); err != nil {
log.Error(err, "unable to update restoresession")
return ctrl.Result{}, err
return reconcile.Result{}, err
}
}
case formolv1alpha1.Running:
@ -352,11 +373,11 @@ func (r *RestoreSessionReconciler) Reconcile(req ctrl.Request) (ctrl.Result, err
restoreSession.Status.SessionState = formolv1alpha1.Failure
if err := r.Status().Update(ctx, restoreSession); err != nil {
log.Error(err, "unable to update restoresession")
return ctrl.Result{}, err
return reconcile.Result{}, err
}
case formolv1alpha1.Running:
log.V(0).Info("task is still running", "target", currentTargetStatus.Name)
return ctrl.Result{}, nil
return reconcile.Result{}, nil
case formolv1alpha1.Waiting:
target := backupConf.Spec.Targets[len(restoreSession.Status.Targets)-1]
if target.Kind == formolv1alpha1.SidecarKind {
@ -366,7 +387,7 @@ func (r *RestoreSessionReconciler) Reconcile(req ctrl.Request) (ctrl.Result, err
Name: target.Name,
}, deployment); err != nil {
log.Error(err, "unable to get deployment")
return ctrl.Result{}, err
return reconcile.Result{}, err
}
if deployment.Status.ReadyReplicas == *deployment.Spec.Replicas {
@ -374,21 +395,21 @@ func (r *RestoreSessionReconciler) Reconcile(req ctrl.Request) (ctrl.Result, err
currentTargetStatus.SessionState = formolv1alpha1.Finalize
if err := r.Status().Update(ctx, restoreSession); err != nil {
log.Error(err, "unable to update restoresession")
return ctrl.Result{}, err
return reconcile.Result{}, err
}
} else {
log.V(0).Info("Waiting for the sidecar to come back")
return ctrl.Result{RequeueAfter: 10 * time.Second}, nil
return reconcile.Result{RequeueAfter: 10 * time.Second}, nil
}
} else {
log.V(0).Info("not a SidecarKind. Ignoring Waiting")
}
case formolv1alpha1.Success:
_ = endTask()
log.V(0).Info("last task was a success. start a new one", "target", currentTargetStatus)
log.V(0).Info("last task was a success. start a new one", "target", currentTargetStatus, "restoreSession version", restoreSession.ObjectMeta.ResourceVersion)
targetStatus, err := startNextTask()
if err != nil {
return ctrl.Result{}, err
return reconcile.Result{}, err
}
if targetStatus == nil {
// No more task to start. The restore is over
@ -396,7 +417,7 @@ func (r *RestoreSessionReconciler) Reconcile(req ctrl.Request) (ctrl.Result, err
}
if err := r.Status().Update(ctx, restoreSession); err != nil {
log.Error(err, "unable to update restoresession")
return ctrl.Result{}, err
return reconcile.Result{RequeueAfter: 300 * time.Millisecond}, nil
}
}
case "":
@ -405,13 +426,26 @@ func (r *RestoreSessionReconciler) Reconcile(req ctrl.Request) (ctrl.Result, err
restoreSession.Status.StartTime = &metav1.Time{Time: time.Now()}
if err := r.Status().Update(ctx, restoreSession); err != nil {
log.Error(err, "unable to update restoreSession")
return ctrl.Result{}, err
return reconcile.Result{}, err
}
}
return ctrl.Result{}, nil
return reconcile.Result{}, nil
}
func (r *RestoreSessionReconciler) SetupWithManager(mgr ctrl.Manager) error {
if err := mgr.GetFieldIndexer().IndexField(context.Background(), &batchv1.Job{}, jobOwnerKey, func(rawObj client.Object) []string {
job := rawObj.(*batchv1.Job)
owner := metav1.GetControllerOf(job)
if owner == nil {
return nil
}
if owner.APIVersion != formolv1alpha1.GroupVersion.String() || owner.Kind != "RestoreSession" {
return nil
}
return []string{owner.Name}
}); err != nil {
return err
}
return ctrl.NewControllerManagedBy(mgr).
For(&formolv1alpha1.RestoreSession{}).
Owns(&batchv1.Job{}).

17
go.mod
View File

@ -3,13 +3,16 @@ module github.com/desmo999r/formol
go 1.13
require (
github.com/go-logr/logr v0.1.0
github.com/onsi/ginkgo v1.12.1
github.com/onsi/gomega v1.10.1
github.com/go-logr/logr v0.3.0
github.com/gophercloud/gophercloud v0.1.0 // indirect
github.com/onsi/ginkgo v1.14.1
github.com/onsi/gomega v1.10.2
gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e // indirect
k8s.io/api v0.18.6
k8s.io/apimachinery v0.18.6
k8s.io/client-go v0.18.6
sigs.k8s.io/controller-runtime v0.6.4
k8s.io/api v0.20.2
k8s.io/apimachinery v0.20.2
k8s.io/client-go v0.20.2
k8s.io/klog v1.0.0 // indirect
sigs.k8s.io/controller-runtime v0.8.3
sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06 // indirect
sigs.k8s.io/structured-merge-diff/v3 v3.0.0 // indirect
)