github.com/jenkins-x/jx/v2@v2.1.155/pkg/cmd/step/restore/step_restore_from_backup.go (about)

     1  package restore
     2  
     3  import (
     4  	"fmt"
     5  
     6  	apiextensionsclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
     7  
     8  	"github.com/jenkins-x/jx-logging/pkg/log"
     9  	"github.com/jenkins-x/jx/v2/pkg/cmd/helper"
    10  	"github.com/jenkins-x/jx/v2/pkg/cmd/opts"
    11  	"github.com/jenkins-x/jx/v2/pkg/cmd/opts/step"
    12  	"github.com/jenkins-x/jx/v2/pkg/cmd/templates"
    13  	"github.com/jenkins-x/jx/v2/pkg/kube/velero"
    14  	"github.com/jenkins-x/jx/v2/pkg/util"
    15  	"github.com/pkg/errors"
    16  	"github.com/spf13/cobra"
    17  
    18  	"k8s.io/client-go/kubernetes"
    19  )
    20  
    21  // FromBackupOptions contains the command line options
    22  type FromBackupOptions struct {
    23  	*StepRestoreOptions
    24  
    25  	Namespace       string
    26  	UseLatestBackup bool
    27  }
    28  
    29  var (
    30  	restoreFromBackupLong = templates.LongDesc(`
    31  		Restores the cluster custom data from the a backup.
    32  
    33  `)
    34  
    35  	restoreFromBackupExample = templates.Examples(`
    36  		# executes the step which restores data from a backup 
    37  		jx step restore from-backup
    38  	`)
    39  )
    40  
    41  // NewCmdStepRestoreFromBackup creates the command
    42  func NewCmdStepRestoreFromBackup(commonOpts *opts.CommonOptions) *cobra.Command {
    43  	options := &FromBackupOptions{
    44  		StepRestoreOptions: &StepRestoreOptions{
    45  			StepOptions: step.StepOptions{
    46  				CommonOptions: commonOpts,
    47  			},
    48  		},
    49  	}
    50  
    51  	cmd := &cobra.Command{
    52  		Use:     "from-backup [flags]",
    53  		Short:   "This step attempts a velero restore from a selected velero backup",
    54  		Long:    restoreFromBackupLong,
    55  		Example: restoreFromBackupExample,
    56  		Aliases: []string{"from-backups"},
    57  		Run: func(cmd *cobra.Command, args []string) {
    58  			options.Cmd = cmd
    59  			options.Args = args
    60  			err := options.Run()
    61  			helper.CheckErr(err)
    62  		},
    63  	}
    64  	cmd.Flags().StringVarP(&options.Namespace, "namespace", "", "velero", "The namespace where velero has been installed")
    65  	cmd.Flags().BoolVarP(&options.UseLatestBackup, "latest", "", false, "This indicates whether to use the latest velero backup as the restore point")
    66  	return cmd
    67  }
    68  
    69  func performVeleroRestore(apiClient apiextensionsclientset.Interface, kubeClient kubernetes.Interface, backupName string, namespace string) error {
    70  	log.Logger().Infof("Using backup '%s' as the backup to restore", util.ColorInfo(backupName))
    71  	err := velero.RestoreFromBackup(apiClient, kubeClient, namespace, backupName)
    72  	if err != nil {
    73  		return errors.Wrap(err, fmt.Sprintf("when attempting to restore from '%s' backup", backupName))
    74  	}
    75  	return nil
    76  }
    77  
    78  // Run implements this command
    79  func (o *FromBackupOptions) Run() error {
    80  
    81  	// create the api extensions client
    82  	apiClient, err := o.ApiExtensionsClient()
    83  	if err != nil {
    84  		return errors.Wrap(err, "while creating api extensions client")
    85  	}
    86  
    87  	// create the kubernetes client
    88  	kubeClient, err := o.KubeClient()
    89  	if err != nil {
    90  		return errors.Wrap(err, "while creating kube client")
    91  	}
    92  
    93  	// check if a velero schedule exists
    94  	scheduleExists, err := velero.DoesVeleroBackupScheduleExist(apiClient, o.Namespace)
    95  	if err != nil {
    96  		return errors.Wrap(err, "when trying to check for velero schedules")
    97  	}
    98  
    99  	// However, if a Velero Schedule exists then we should be confident that this is an existing operational cluster
   100  	// and therefore abort the restore.
   101  	if scheduleExists {
   102  		fmt.Println("A velero schedule exists for this cluster")
   103  		fmt.Println("Aborting restore as it would be dangerous to apply the a backup")
   104  		fmt.Println("If you expected this command to execute automatically - perhaps the backup schedule apply step comes before this step?")
   105  
   106  		return nil
   107  	}
   108  	latestBackupName, err := velero.GetLatestBackupFromBackupResource(apiClient, o.Namespace)
   109  	if err != nil {
   110  		return errors.Wrap(err, "when trying to get the latest backup")
   111  	}
   112  	if o.UseLatestBackup {
   113  		if latestBackupName == "" {
   114  			fmt.Println("unable to locate latest backup - it's possible there may not be any yet")
   115  			return nil
   116  		}
   117  		err = performVeleroRestore(apiClient, kubeClient, latestBackupName, o.Namespace)
   118  		if err != nil {
   119  			return errors.Wrap(err, fmt.Sprintf("when attempting to automatically restore from '%s' backup", latestBackupName))
   120  		}
   121  	} else {
   122  		backupNames, err := velero.GetBackupsFromBackupResource(apiClient, o.Namespace)
   123  		if err != nil {
   124  			return errors.Wrap(err, "when attempting to retrieve the backups")
   125  		}
   126  		if len(backupNames) == 0 {
   127  			return errors.Errorf("unable to locate backups")
   128  		}
   129  
   130  		selectedBackup, err := util.PickNameWithDefault(backupNames, "Which backup do you want to restore from?: ", latestBackupName, "", o.GetIOFileHandles())
   131  		if err != nil {
   132  			return err
   133  		}
   134  		args := []string{selectedBackup}
   135  		if len(args) == 0 {
   136  			return fmt.Errorf("No backup chosen")
   137  		}
   138  		selectedBackupName := args[0]
   139  		err = performVeleroRestore(apiClient, kubeClient, selectedBackupName, o.Namespace)
   140  		if err != nil {
   141  			return errors.Wrap(err, fmt.Sprintf("when attempting to automatically restore from '%s' backup", selectedBackupName))
   142  		}
   143  	}
   144  	return nil
   145  }