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:
parent
477022347d
commit
9c15bcc470
@ -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 {
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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
17
go.mod
@ -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
|
||||
)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user