diff --git a/client/v3/snapshot/v3_snapshot.go b/client/v3/snapshot/v3_snapshot.go index b2db5f0c137..ac4aba5a738 100644 --- a/client/v3/snapshot/v3_snapshot.go +++ b/client/v3/snapshot/v3_snapshot.go @@ -20,6 +20,7 @@ import ( "fmt" "io" "os" + "strings" "time" "github.com/dustin/go-humanize" @@ -37,15 +38,14 @@ func hasChecksum(n int64) bool { return (n % 512) == sha256.Size } -// SaveWithVersion fetches snapshot from remote etcd server, saves data +// GetSnapshotWithVersion fetches snapshot from remote etcd server, saves data // to target path and returns server version. If the context "ctx" is canceled or timed out, // snapshot save stream will error out (e.g. context.Canceled, // context.DeadlineExceeded). Make sure to specify only one endpoint // in client configuration. Snapshot API must be requested to a // selected node, and saved snapshot is the point-in-time state of -// the selected node. -// Etcd SNAPSHOT SAVE writes a point-in-time snapshot of the etcd backend database to a file. diff --git a/etcdctl/ctlv3/command/snapshot_command.go b/etcdctl/ctlv3/command/snapshot_command.go index df317e23cc7..94daf2ff415 100644 --- a/etcdctl/ctlv3/command/snapshot_command.go +++ b/etcdctl/ctlv3/command/snapshot_command.go @@ -33,6 +33,7 @@ func NewSnapshotCommand() *cobra.Command { Short: "Manages etcd node snapshots", } cmd.AddCommand(NewSnapshotSaveCommand()) + cmd.AddCommand(NewSnapshotPipeCommand()) return cmd } @@ -44,6 +45,14 @@ func NewSnapshotSaveCommand() *cobra.Command { } } +func NewSnapshotPipeCommand() *cobra.Command { + return &cobra.Command{ + Use: "pipe", + Short: "Streams an etcd node backend snapshot to STDOUT", + Run: snapshotPipeCommandFunc, + } +} + func snapshotSaveCommandFunc(cmd *cobra.Command, args []string) { if len(args) != 1 { err := fmt.Errorf("snapshot save expects one argument") @@ -73,3 +82,24 @@ func snapshotSaveCommandFunc(cmd *cobra.Command, args []string) { fmt.Printf("Server version %s\n", version) } } + +func snapshotPipeCommandFunc(cmd *cobra.Command, args []string) { + + lg, err := logutil.CreateDefaultZapLogger(zap.InfoLevel) + if err != nil { + cobrautl.ExitWithError(cobrautl.ExitError, err) + } + cfg := mustClientCfgFromCmd(cmd) + + // if user does not specify "--command-timeout" flag, there will be no timeout for snapshot pipe command + ctx, cancel := context.WithCancel(context.Background()) + if isCommandTimeoutFlagSet(cmd) { + ctx, cancel = commandCtx(cmd) + } + defer cancel() + + _, err = snapshot.PipeWithVersion(ctx, lg, *cfg) + if err != nil { + cobrautl.ExitWithError(cobrautl.ExitInterrupted, err) + } +}