diff --git a/pkg/cli/cmds/etcd_snapshot.go b/pkg/cli/cmds/etcd_snapshot.go index 9901a7b07d8d..b0e373e84010 100644 --- a/pkg/cli/cmds/etcd_snapshot.go +++ b/pkg/cli/cmds/etcd_snapshot.go @@ -37,6 +37,12 @@ var EtcdSnapshotFlags = []cli.Flag{ Usage: "(db) Compress etcd snapshot", Destination: &ServerConfig.EtcdSnapshotCompress, }, + &cli.IntFlag{ + Name: "snapshot-retention,etcd-snapshot-retention", + Usage: "(db) Number of snapshots to retain.", + Destination: &ServerConfig.EtcdSnapshotRetention, + Value: defaultSnapshotRentention, + }, &cli.BoolFlag{ Name: "s3,etcd-s3", Usage: "(db) Enable backup to S3", @@ -140,12 +146,7 @@ func NewEtcdSnapshotCommands(delete, list, prune, save func(ctx *cli.Context) er SkipFlagParsing: false, SkipArgReorder: true, Action: prune, - Flags: append(EtcdSnapshotFlags, &cli.IntFlag{ - Name: "snapshot-retention", - Usage: "(db) Number of snapshots to retain.", - Destination: &ServerConfig.EtcdSnapshotRetention, - Value: defaultSnapshotRentention, - }), + Flags: EtcdSnapshotFlags, }, }, Flags: EtcdSnapshotFlags, diff --git a/pkg/etcd/snapshot.go b/pkg/etcd/snapshot.go index d9f5f7689c1e..a481985171dd 100644 --- a/pkg/etcd/snapshot.go +++ b/pkg/etcd/snapshot.go @@ -74,26 +74,38 @@ var ( ) // snapshotDir ensures that the snapshot directory exists, and then returns its path. +// Only the default snapshot directory will be created; user-specified non-default +// snapshot directories must already exist. func snapshotDir(config *config.Control, create bool) (string, error) { - if config.EtcdSnapshotDir == "" { - // we have to create the snapshot dir if we are using - // the default snapshot dir if it doesn't exist - defaultSnapshotDir := filepath.Join(config.DataDir, "db", "snapshots") - s, err := os.Stat(defaultSnapshotDir) - if err != nil { - if create && os.IsNotExist(err) { - if err := os.MkdirAll(defaultSnapshotDir, 0700); err != nil { - return "", err - } - return defaultSnapshotDir, nil + defaultSnapshotDir := filepath.Join(config.DataDir, "db", "snapshots") + snapshotDir := config.EtcdSnapshotDir + + if snapshotDir == "" { + snapshotDir = defaultSnapshotDir + } + + // Disable creation if not using the default snapshot dir. + // Non-default snapshot dirs must be created by the user. + if snapshotDir != defaultSnapshotDir { + create = false + } + + s, err := os.Stat(snapshotDir) + if err != nil { + if os.IsNotExist(err) && create { + if err := os.MkdirAll(snapshotDir, 0700); err != nil { + return "", err } - return "", err - } - if s.IsDir() { - return defaultSnapshotDir, nil + return snapshotDir, nil } + return "", err + } + + if !s.IsDir() { + return "", fmt.Errorf("%s is not a directory", snapshotDir) } - return config.EtcdSnapshotDir, nil + + return snapshotDir, nil } // preSnapshotSetup checks to see if the necessary components are in place @@ -248,12 +260,6 @@ func (e *ETCD) Snapshot(ctx context.Context) error { return errors.Wrap(err, "failed to get etcd-snapshot-dir") } - if info, err := os.Stat(snapshotDir); err != nil { - return errors.Wrapf(err, "failed to stat etcd-snapshot-dir %s", snapshotDir) - } else if !info.IsDir() { - return fmt.Errorf("etcd-snapshot-dir %s is not a directory", snapshotDir) - } - cfg, err := getClientConfig(ctx, e.config) if err != nil { return errors.Wrap(err, "failed to get config for etcd snapshot") @@ -438,7 +444,7 @@ func (e *ETCD) listLocalSnapshots() (map[string]snapshotFile, error) { snapshots := make(map[string]snapshotFile) snapshotDir, err := snapshotDir(e.config, true) if err != nil { - return snapshots, errors.Wrap(err, "failed to get the snapshot dir") + return snapshots, errors.Wrap(err, "failed to get etcd-snapshot-dir") } if err := filepath.Walk(snapshotDir, func(path string, file os.FileInfo, err error) error { @@ -502,8 +508,9 @@ func (e *ETCD) initS3IfNil(ctx context.Context) error { func (e *ETCD) PruneSnapshots(ctx context.Context) error { snapshotDir, err := snapshotDir(e.config, false) if err != nil { - return errors.Wrap(err, "failed to get the snapshot dir") + return errors.Wrap(err, "failed to get etcd-snapshot-dir") } + if err := snapshotRetention(e.config.EtcdSnapshotRetention, e.config.EtcdSnapshotName, snapshotDir); err != nil { logrus.Errorf("Error applying snapshot retention policy: %v", err) } @@ -551,7 +558,7 @@ func (e *ETCD) ListSnapshots(ctx context.Context) (map[string]snapshotFile, erro func (e *ETCD) DeleteSnapshots(ctx context.Context, snapshots []string) error { snapshotDir, err := snapshotDir(e.config, false) if err != nil { - return errors.Wrap(err, "failed to get the snapshot dir") + return errors.Wrap(err, "failed to get etcd-snapshot-dir") } if e.config.EtcdS3 { if err := e.initS3IfNil(ctx); err != nil {