github.com/percona/percona-xtradb-cluster-operator@v1.14.0/pkg/controller/pxcrestore/restore.go (about)

     1  package pxcrestore
     2  
     3  import (
     4  	"context"
     5  	"time"
     6  
     7  	"github.com/pkg/errors"
     8  	batchv1 "k8s.io/api/batch/v1"
     9  	corev1 "k8s.io/api/core/v1"
    10  	k8serrors "k8s.io/apimachinery/pkg/api/errors"
    11  	"k8s.io/apimachinery/pkg/types"
    12  	logf "sigs.k8s.io/controller-runtime/pkg/log"
    13  
    14  	api "github.com/percona/percona-xtradb-cluster-operator/pkg/apis/pxc/v1"
    15  	"github.com/percona/percona-xtradb-cluster-operator/pkg/k8s"
    16  )
    17  
    18  func (r *ReconcilePerconaXtraDBClusterRestore) restore(ctx context.Context, cr *api.PerconaXtraDBClusterRestore, bcp *api.PerconaXtraDBClusterBackup, cluster *api.PerconaXtraDBCluster) error {
    19  	log := logf.FromContext(ctx)
    20  
    21  	if cluster.Spec.Backup == nil {
    22  		return errors.New("undefined backup section in a cluster spec")
    23  	}
    24  
    25  	restorer, err := r.getRestorer(cr, bcp, cluster)
    26  	if err != nil {
    27  		return errors.Wrap(err, "failed to get restorer")
    28  	}
    29  	job, err := restorer.Job()
    30  	if err != nil {
    31  		return errors.Wrap(err, "failed to get restore job")
    32  	}
    33  	if err = k8s.SetControllerReference(cr, job, r.scheme); err != nil {
    34  		return err
    35  	}
    36  
    37  	if err = restorer.Init(ctx); err != nil {
    38  		return errors.Wrap(err, "failed to init restore")
    39  	}
    40  	defer func() {
    41  		if derr := restorer.Finalize(ctx); derr != nil {
    42  			log.Error(derr, "failed to finalize restore")
    43  		}
    44  	}()
    45  
    46  	return r.createJob(ctx, job)
    47  }
    48  
    49  func (r *ReconcilePerconaXtraDBClusterRestore) pitr(ctx context.Context, cr *api.PerconaXtraDBClusterRestore, bcp *api.PerconaXtraDBClusterBackup, cluster *api.PerconaXtraDBCluster) error {
    50  	log := logf.FromContext(ctx)
    51  
    52  	restorer, err := r.getRestorer(cr, bcp, cluster)
    53  	if err != nil {
    54  		return errors.Wrap(err, "failed to get restorer")
    55  	}
    56  	job, err := restorer.PITRJob()
    57  	if err != nil {
    58  		return errors.Wrap(err, "failed to create pitr restore job")
    59  	}
    60  	if err := k8s.SetControllerReference(cr, job, r.scheme); err != nil {
    61  		return err
    62  	}
    63  	if err = restorer.Init(ctx); err != nil {
    64  		return errors.Wrap(err, "failed to init restore")
    65  	}
    66  	defer func() {
    67  		if derr := restorer.Finalize(ctx); derr != nil {
    68  			log.Error(derr, "failed to finalize restore")
    69  		}
    70  	}()
    71  
    72  	return r.createJob(ctx, job)
    73  }
    74  
    75  func (r *ReconcilePerconaXtraDBClusterRestore) validate(ctx context.Context, cr *api.PerconaXtraDBClusterRestore, bcp *api.PerconaXtraDBClusterBackup, cluster *api.PerconaXtraDBCluster) error {
    76  	restorer, err := r.getRestorer(cr, bcp, cluster)
    77  	if err != nil {
    78  		return errors.Wrap(err, "failed to get restorer")
    79  	}
    80  	job, err := restorer.Job()
    81  	if err != nil {
    82  		return errors.Wrap(err, "failed to create restore job")
    83  	}
    84  	if err := restorer.ValidateJob(ctx, job); err != nil {
    85  		return errors.Wrap(err, "failed to validate job")
    86  	}
    87  
    88  	if cr.Spec.PITR != nil {
    89  		job, err := restorer.PITRJob()
    90  		if err != nil {
    91  			return errors.Wrap(err, "failed to create pitr restore job")
    92  		}
    93  		if err := restorer.ValidateJob(ctx, job); err != nil {
    94  			return errors.Wrap(err, "failed to validate job")
    95  		}
    96  	}
    97  	if err := restorer.Validate(ctx); err != nil {
    98  		return errors.Wrap(err, "failed to validate backup existence")
    99  	}
   100  	return nil
   101  }
   102  
   103  func (r *ReconcilePerconaXtraDBClusterRestore) createJob(ctx context.Context, job *batchv1.Job) error {
   104  	err := r.client.Create(ctx, job)
   105  	if err != nil {
   106  		return errors.Wrap(err, "create job")
   107  	}
   108  
   109  	for {
   110  		time.Sleep(time.Second * 1)
   111  
   112  		checkJob := batchv1.Job{}
   113  		err := r.client.Get(ctx, types.NamespacedName{Name: job.Name, Namespace: job.Namespace}, &checkJob)
   114  		if err != nil {
   115  			if k8serrors.IsNotFound(err) {
   116  				return nil
   117  			}
   118  			return errors.Wrap(err, "get job status")
   119  		}
   120  		for _, cond := range checkJob.Status.Conditions {
   121  			if cond.Status != corev1.ConditionTrue {
   122  				continue
   123  			}
   124  			switch cond.Type {
   125  			case batchv1.JobComplete:
   126  				return nil
   127  			case batchv1.JobFailed:
   128  				return errors.New(cond.Message)
   129  			}
   130  		}
   131  	}
   132  }