github.com/unigraph-dev/dgraph@v1.1.1-0.20200923154953-8b52b426f765/ee/backup/run.go (about)

     1  // +build !oss
     2  
     3  /*
     4   * Copyright 2018 Dgraph Labs, Inc. and Contributors
     5   *
     6   * Licensed under the Dgraph Community License (the "License"); you
     7   * may not use this file except in compliance with the License. You
     8   * may obtain a copy of the License at
     9   *
    10   *     https://github.com/dgraph-io/dgraph/blob/master/licenses/DCL.txt
    11   */
    12  
    13  package backup
    14  
    15  import (
    16  	"context"
    17  	"fmt"
    18  	"os"
    19  	"time"
    20  
    21  	"github.com/dgraph-io/dgraph/protos/pb"
    22  	"github.com/dgraph-io/dgraph/x"
    23  	"github.com/pkg/errors"
    24  	"github.com/spf13/cobra"
    25  	"google.golang.org/grpc"
    26  )
    27  
    28  // Restore is the sub-command used to restore a backup.
    29  var Restore x.SubCommand
    30  
    31  // LsBackup is the sub-command used to list the backups in a folder.
    32  var LsBackup x.SubCommand
    33  
    34  var opt struct {
    35  	backupId, location, pdir, zero string
    36  }
    37  
    38  func init() {
    39  	initRestore()
    40  	initBackupLs()
    41  }
    42  
    43  func initRestore() {
    44  	Restore.Cmd = &cobra.Command{
    45  		Use:   "restore",
    46  		Short: "Run Dgraph (EE) Restore backup",
    47  		Long: `
    48  Restore loads objects created with the backup feature in Dgraph Enterprise Edition (EE).
    49  
    50  Backups are originated from HTTP at /admin/backup, then can be restored using CLI restore
    51  command. Restore is intended to be used with new Dgraph clusters in offline state.
    52  
    53  The --location flag indicates a source URI with Dgraph backup objects. This URI supports all
    54  the schemes used for backup.
    55  
    56  Source URI formats:
    57    [scheme]://[host]/[path]?[args]
    58    [scheme]:///[path]?[args]
    59    /[path]?[args] (only for local or NFS)
    60  
    61  Source URI parts:
    62    scheme - service handler, one of: "s3", "minio", "file"
    63      host - remote address. ex: "dgraph.s3.amazonaws.com"
    64      path - directory, bucket or container at target. ex: "/dgraph/backups/"
    65      args - specific arguments that are ok to appear in logs.
    66  
    67  The --posting flag sets the posting list parent dir to store the loaded backup files.
    68  
    69  Using the --zero flag will use a Dgraph Zero address to update the start timestamp using
    70  the restored version. Otherwise, the timestamp must be manually updated through Zero's HTTP
    71  'assign' command.
    72  
    73  Dgraph backup creates a unique backup object for each node group, and restore will create
    74  a posting directory 'p' matching the backup group ID. Such that a backup file
    75  named '.../r32-g2.backup' will be loaded to posting dir 'p2'.
    76  
    77  Usage examples:
    78  
    79  # Restore from local dir or NFS mount:
    80  $ dgraph restore -p . -l /var/backups/dgraph
    81  
    82  # Restore from S3:
    83  $ dgraph restore -p /var/db/dgraph -l s3://s3.us-west-2.amazonaws.com/srfrog/dgraph
    84  
    85  # Restore from dir and update Ts:
    86  $ dgraph restore -p . -l /var/backups/dgraph -z localhost:5080
    87  
    88  		`,
    89  		Args: cobra.NoArgs,
    90  		Run: func(cmd *cobra.Command, args []string) {
    91  			defer x.StartProfile(Restore.Conf).Stop()
    92  			if err := runRestoreCmd(); err != nil {
    93  				fmt.Fprintln(os.Stderr, err)
    94  				os.Exit(1)
    95  			}
    96  		},
    97  	}
    98  
    99  	flag := Restore.Cmd.Flags()
   100  	flag.StringVarP(&opt.location, "location", "l", "",
   101  		"Sets the source location URI (required).")
   102  	flag.StringVarP(&opt.pdir, "postings", "p", "",
   103  		"Directory where posting lists are stored (required).")
   104  	flag.StringVarP(&opt.zero, "zero", "z", "", "gRPC address for Dgraph zero. ex: localhost:5080")
   105  	flag.StringVarP(&opt.backupId, "backup_id", "", "", "The ID of the backup series to "+
   106  		"restore. If empty, it will restore the latest series.")
   107  	_ = Restore.Cmd.MarkFlagRequired("postings")
   108  	_ = Restore.Cmd.MarkFlagRequired("location")
   109  }
   110  
   111  func initBackupLs() {
   112  	LsBackup.Cmd = &cobra.Command{
   113  		Use:   "lsbackup",
   114  		Short: "List info on backups in given location",
   115  		Long: `
   116  lsbackup looks at a location where backups are stored and prints information about them.
   117  
   118  Backups are originated from HTTP at /admin/backup, then can be restored using CLI restore
   119  command. Restore is intended to be used with new Dgraph clusters in offline state.
   120  
   121  The --location flag indicates a source URI with Dgraph backup objects. This URI supports all
   122  the schemes used for backup.
   123  
   124  Source URI formats:
   125    [scheme]://[host]/[path]?[args]
   126    [scheme]:///[path]?[args]
   127    /[path]?[args] (only for local or NFS)
   128  
   129  Source URI parts:
   130    scheme - service handler, one of: "s3", "minio", "file"
   131      host - remote address. ex: "dgraph.s3.amazonaws.com"
   132      path - directory, bucket or container at target. ex: "/dgraph/backups/"
   133      args - specific arguments that are ok to appear in logs.
   134  
   135  Dgraph backup creates a unique backup object for each node group, and restore will create
   136  a posting directory 'p' matching the backup group ID. Such that a backup file
   137  named '.../r32-g2.backup' will be loaded to posting dir 'p2'.
   138  
   139  Usage examples:
   140  
   141  # Run using location in S3:
   142  $ dgraph lsbackup -l s3://s3.us-west-2.amazonaws.com/srfrog/dgraph
   143  		`,
   144  		Args: cobra.NoArgs,
   145  		Run: func(cmd *cobra.Command, args []string) {
   146  			defer x.StartProfile(Restore.Conf).Stop()
   147  			if err := runLsbackupCmd(); err != nil {
   148  				fmt.Fprintln(os.Stderr, err)
   149  				os.Exit(1)
   150  			}
   151  		},
   152  	}
   153  
   154  	flag := LsBackup.Cmd.Flags()
   155  	flag.StringVarP(&opt.location, "location", "l", "",
   156  		"Sets the source location URI (required).")
   157  	_ = LsBackup.Cmd.MarkFlagRequired("location")
   158  }
   159  
   160  func runRestoreCmd() error {
   161  	var (
   162  		start time.Time
   163  		zc    pb.ZeroClient
   164  	)
   165  
   166  	fmt.Println("Restoring backups from:", opt.location)
   167  	fmt.Println("Writing postings to:", opt.pdir)
   168  
   169  	// TODO: Remove this dependency on Zero. It complicates restore for the end
   170  	// user.
   171  	if opt.zero != "" {
   172  		fmt.Println("Updating Zero timestamp at:", opt.zero)
   173  
   174  		ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
   175  		defer cancel()
   176  
   177  		zero, err := grpc.DialContext(ctx, opt.zero,
   178  			grpc.WithBlock(),
   179  			grpc.WithInsecure())
   180  		if err != nil {
   181  			return errors.Wrapf(err, "Unable to connect to %s", opt.zero)
   182  		}
   183  		zc = pb.NewZeroClient(zero)
   184  	}
   185  
   186  	start = time.Now()
   187  	version, err := RunRestore(opt.pdir, opt.location, opt.backupId)
   188  	if err != nil {
   189  		return err
   190  	}
   191  	if version == 0 {
   192  		return errors.Errorf("Failed to obtain a restore version")
   193  	}
   194  	fmt.Printf("Restore version: %d\n", version)
   195  
   196  	if zc != nil {
   197  		ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
   198  		defer cancel()
   199  
   200  		_, err = zc.Timestamps(ctx, &pb.Num{Val: version})
   201  		if err != nil {
   202  			fmt.Printf("Failed to assign timestamp %d in Zero: %v", version, err)
   203  		}
   204  	}
   205  
   206  	fmt.Printf("Restore: Time elapsed: %s\n", time.Since(start).Round(time.Second))
   207  	return nil
   208  }
   209  
   210  func runLsbackupCmd() error {
   211  	fmt.Println("Listing backups from:", opt.location)
   212  	manifests, err := ListManifests(opt.location)
   213  	if err != nil {
   214  		return errors.Wrapf(err, "while listing manifests")
   215  	}
   216  
   217  	fmt.Printf("Name\tSince\tGroups\n")
   218  	for path, manifest := range manifests {
   219  		fmt.Printf("%v\t%v\t%v\n", path, manifest.Since, manifest.Groups)
   220  	}
   221  
   222  	return nil
   223  }