Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ETCD-636: add automated backup sidecar #1287

Closed
wants to merge 22 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions bindata/etcd/pod.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -335,3 +335,9 @@ ${COMPUTED_ENV_VARS}
- hostPath:
path: /var/log/etcd
name: log-dir
- hostPath:
path: /var/backup/etcd
name: backup-dir
- hostPath:
path: /etc/kubernetes
name: config-dir
Comment on lines +338 to +343
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still have to review to this later and see if all of this aligns with what's outlined in the enhancement, but manifest changes related to this feature like this need to be feature gated and can't be in GA by default.

1 change: 1 addition & 0 deletions cmd/cluster-etcd-operator/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ func NewSSCSCommand(ctx context.Context) *cobra.Command {
cmd.AddCommand(readyz.NewReadyzCommand())
cmd.AddCommand(prune_backups.NewPruneCommand())
cmd.AddCommand(requestbackup.NewRequestBackupCommand(ctx))
cmd.AddCommand(backuprestore.NewBackupNoConfigCommand(os.Stderr))

return cmd
}
11 changes: 6 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ go 1.22.0
toolchain go1.22.1

require (
github.com/adhocore/gronx v1.8.1
github.com/davecgh/go-spew v1.1.1
github.com/ghodss/yaml v1.0.0
github.com/go-bindata/go-bindata v3.1.2+incompatible
Expand All @@ -19,7 +20,7 @@ require (
github.com/prometheus/common v0.44.0
github.com/spf13/cobra v1.7.0
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.8.4
github.com/stretchr/testify v1.9.0
github.com/vishvananda/netlink v1.0.0
go.etcd.io/etcd/api/v3 v3.5.10
go.etcd.io/etcd/client/pkg/v3 v3.5.10
Expand Down Expand Up @@ -70,14 +71,14 @@ require (
github.com/google/cel-go v0.17.8 // indirect
github.com/google/gnostic-models v0.6.8 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect
github.com/imdario/mergo v0.3.7 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jonboulle/clockwork v0.2.2 // indirect
github.com/jonboulle/clockwork v0.4.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
Expand Down Expand Up @@ -111,10 +112,10 @@ require (
go.opentelemetry.io/proto/otlp v1.0.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/crypto v0.21.0 // indirect
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 // indirect
golang.org/x/net v0.23.0 // indirect
golang.org/x/oauth2 v0.10.0 // indirect
golang.org/x/sync v0.6.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/term v0.18.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.3.0 // indirect
Expand Down
25 changes: 14 additions & 11 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym
github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I=
github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/adhocore/gronx v1.8.1 h1:F2mLTG5sB11z7vplwD4iydz3YCEjstSfYmCrdSm3t6A=
github.com/adhocore/gronx v1.8.1/go.mod h1:7oUY1WAU8rEJWmAxXR2DN0JaO4gi9khSgKjiRypqteg=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
Expand Down Expand Up @@ -194,8 +196,8 @@ github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJY
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
Expand Down Expand Up @@ -238,8 +240,9 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ=
github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4=
github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=
Expand Down Expand Up @@ -401,8 +404,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
Expand Down Expand Up @@ -504,8 +507,8 @@ golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA=
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA=
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY=
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
Expand Down Expand Up @@ -565,8 +568,8 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
Expand Down Expand Up @@ -641,8 +644,8 @@ golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapK
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ=
golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg=
golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
Expand Down
14 changes: 14 additions & 0 deletions hack/defaultbackupcr.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
apiVersion: config.openshift.io/v1alpha1
kind: Backup
metadata:
name: default
annotations:
default: "true"
spec:
etcd:
schedule: "20 4 * * *"
timeZone: "UTC"
retentionPolicy:
retentionType: RetentionNumber
retentionNumber:
maxNumberOfBackups: 5
88 changes: 88 additions & 0 deletions pkg/cmd/backuprestore/backupnoconfig.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package backuprestore

import (
"context"
"fmt"
"io"

"k8s.io/klog/v2"

"github.com/adhocore/gronx/pkg/tasker"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)

type backupNoConfig struct {
schedule string
timeZone string
scheduler *tasker.Tasker
backupOptions
}

func NewBackupNoConfigCommand(errOut io.Writer) *cobra.Command {
backupNoConf := &backupNoConfig{
backupOptions: backupOptions{errOut: errOut},
}

cmd := &cobra.Command{
Use: "backup-server",
Short: "Backs up a snapshot of etcd database and static pod resources without config",
Run: func(cmd *cobra.Command, args []string) {
must := func(fn func() error) {
if err := fn(); err != nil {
if cmd.HasParent() {
klog.Fatal(err)
}
fmt.Fprint(backupNoConf.errOut, err.Error())
}
}

must(backupNoConf.Validate)
must(backupNoConf.Run)
},
}
backupNoConf.AddFlags(cmd.Flags())
return cmd
}

func (b *backupNoConfig) AddFlags(fs *pflag.FlagSet) {
fs.StringVar(&b.schedule, "schedule", "", "schedule specifies the cron schedule to run the backup")
fs.StringVar(&b.timeZone, "timezone", "", "timezone specifies the timezone of the cron schedule to run the backup")

b.backupOptions.AddFlags(fs)
}

func (b *backupNoConfig) Validate() error {
return b.backupOptions.Validate()
}

func (b *backupNoConfig) Run() error {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need to use this scheduler here, but rather you want to just write a simple controller, similar in concept to https://github.com/kubernetes/kubernetes/blob/master/pkg/controller/cronjob/cronjob_controllerv2.go.

The main bits are:

  1. Use a DelayingQueue from https://github.com/kubernetes/client-go/blob/master/util/workqueue/delaying_queue.go (TypedNewDelayingQueue, for example, or others if you need more control). Additionally you'll register an informer on that Backup CR of yours, which will be responsible to trigger worker any time a change to a CR will happen.
  2. After that you'll create a Run method very similar to the cronjob controller, there you'll start the queue and your worker.
  3. Inside the worker you'll either schedule the backup to run or you'll queue (using AddAfter method) the next execution. To calculate the actual next run you can use github.com/robfig/cron library which helps parsing the cron spec (cron.ParseStandard) .

b.scheduler = tasker.New(tasker.Option{
Verbose: true,
Tz: b.timeZone,
})

err := b.scheduleBackup()
if err != nil {
return err
}

doneCh := make(chan struct{})
go func() {
b.scheduler.Run()
doneCh <- struct{}{}
}()

<-doneCh
return nil
}

func (b *backupNoConfig) scheduleBackup() error {
var err error
b.scheduler.Task(b.schedule, func(ctx context.Context) (int, error) {
err = backup(&b.backupOptions)
return 0, err
}, false)

return err
}
56 changes: 28 additions & 28 deletions pkg/cmd/prune-backups/prune.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,14 @@ type backupDirStat struct {
modTime time.Time
}

type pruneOpts struct {
retentionType string
maxNumberOfBackups int
maxSizeOfBackupsGb int
type PruneOpts struct {
RetentionType string
MaxNumberOfBackups int
MaxSizeOfBackupsGb int
}

func NewPruneCommand() *cobra.Command {
opts := pruneOpts{retentionType: "None"}
opts := PruneOpts{RetentionType: "None"}
cmd := &cobra.Command{
Use: "prune-backups",
Short: "Prunes existing backups on the filesystem.",
Expand All @@ -56,54 +56,54 @@ func NewPruneCommand() *cobra.Command {
return cmd
}

func (r *pruneOpts) AddFlags(cmd *cobra.Command) {
func (r *PruneOpts) AddFlags(cmd *cobra.Command) {
flagSet := cmd.Flags()
flagSet.StringVar(&r.retentionType, "type", r.retentionType, "Which kind of retention to execute, can either be None, RetentionNumber or RetentionSize.")
flagSet.StringVar(&r.RetentionType, "type", r.RetentionType, "Which kind of retention to execute, can either be None, RetentionNumber or RetentionSize.")
// the defaults are zero for validation, we inject the real defaults from the periodic backup controller
flagSet.IntVar(&r.maxNumberOfBackups, "maxNumberOfBackups", 0, "how many backups to keep when type=RetentionNumber")
flagSet.IntVar(&r.maxSizeOfBackupsGb, "maxSizeOfBackupsGb", 0, "how many gigabytes of backups to keep when type=RetentionSize")
flagSet.IntVar(&r.MaxNumberOfBackups, "MaxNumberOfBackups", 0, "how many backups to keep when type=RetentionNumber")
flagSet.IntVar(&r.MaxSizeOfBackupsGb, "MaxSizeOfBackupsGb", 0, "how many gigabytes of backups to keep when type=RetentionSize")

// adding klog flags to tune verbosity better
gfs := goflag.NewFlagSet("", goflag.ExitOnError)
klog.InitFlags(gfs)
cmd.Flags().AddGoFlagSet(gfs)
}

func (r *pruneOpts) Validate() error {
if r.retentionType != RetentionTypeNone && r.retentionType != RetentionTypeNumber && r.retentionType != RetentionTypeSize {
return fmt.Errorf("unknown retention type: [%s]", r.retentionType)
func (r *PruneOpts) Validate() error {
if r.RetentionType != RetentionTypeNone && r.RetentionType != RetentionTypeNumber && r.RetentionType != RetentionTypeSize {
return fmt.Errorf("unknown retention type: [%s]", r.RetentionType)
}

if r.retentionType == RetentionTypeNumber {
if r.maxNumberOfBackups < 1 {
return fmt.Errorf("unexpected amount of backups [%d] found, expected at least 1", r.maxNumberOfBackups)
if r.RetentionType == RetentionTypeNumber {
if r.MaxNumberOfBackups < 1 {
return fmt.Errorf("unexpected amount of backups [%d] found, expected at least 1", r.MaxNumberOfBackups)
}

if r.maxSizeOfBackupsGb != 0 {
return fmt.Errorf("unexpected argument [maxSizeOfBackupsGb] found while using %s", RetentionTypeNumber)
if r.MaxSizeOfBackupsGb != 0 {
return fmt.Errorf("unexpected argument [MaxSizeOfBackupsGb] found while using %s", RetentionTypeNumber)
}

} else if r.retentionType == RetentionTypeSize {
if r.maxSizeOfBackupsGb < 1 {
return fmt.Errorf("unexpected size of backups [%d]gb found, expected at least 1", r.maxSizeOfBackupsGb)
} else if r.RetentionType == RetentionTypeSize {
if r.MaxSizeOfBackupsGb < 1 {
return fmt.Errorf("unexpected size of backups [%d]gb found, expected at least 1", r.MaxSizeOfBackupsGb)
}

if r.maxNumberOfBackups != 0 {
return fmt.Errorf("unexpected argument [maxNumberOfBackups] found while using %s", RetentionTypeSize)
if r.MaxNumberOfBackups != 0 {
return fmt.Errorf("unexpected argument [MaxNumberOfBackups] found while using %s", RetentionTypeSize)
}
}

return nil
}

func (r *pruneOpts) Run() error {
if r.retentionType == RetentionTypeNone {
func (r *PruneOpts) Run() error {
if r.RetentionType == RetentionTypeNone {
klog.Infof("nothing to do, retention type is none")
return nil
} else if r.retentionType == RetentionTypeSize {
return retainBySizeGb(r.maxSizeOfBackupsGb)
} else if r.retentionType == RetentionTypeNumber {
return retainByNumber(r.maxNumberOfBackups)
} else if r.RetentionType == RetentionTypeSize {
return retainBySizeGb(r.MaxSizeOfBackupsGb)
} else if r.RetentionType == RetentionTypeNumber {
return retainByNumber(r.MaxNumberOfBackups)
}

return nil
Expand Down
20 changes: 10 additions & 10 deletions pkg/cmd/prune-backups/prune_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,21 @@ import (

func TestCommandValidation(t *testing.T) {
testCases := map[string]struct {
opts pruneOpts
opts PruneOpts
expectedErr error
}{
"none happy": {opts: pruneOpts{retentionType: RetentionTypeNone}},
"number happy": {opts: pruneOpts{retentionType: RetentionTypeNumber, maxNumberOfBackups: 1}},
"number zero": {opts: pruneOpts{retentionType: RetentionTypeNumber, maxNumberOfBackups: 0},
"none happy": {opts: PruneOpts{RetentionType: RetentionTypeNone}},
"number happy": {opts: PruneOpts{RetentionType: RetentionTypeNumber, MaxNumberOfBackups: 1}},
"number zero": {opts: PruneOpts{RetentionType: RetentionTypeNumber, MaxNumberOfBackups: 0},
expectedErr: fmt.Errorf("unexpected amount of backups [0] found, expected at least 1")},
"number flipped": {opts: pruneOpts{retentionType: RetentionTypeNumber, maxNumberOfBackups: 2, maxSizeOfBackupsGb: 25},
expectedErr: fmt.Errorf("unexpected argument [maxSizeOfBackupsGb] found while using RetentionNumber")},
"number flipped": {opts: PruneOpts{RetentionType: RetentionTypeNumber, MaxNumberOfBackups: 2, MaxSizeOfBackupsGb: 25},
expectedErr: fmt.Errorf("unexpected argument [MaxSizeOfBackupsGb] found while using RetentionNumber")},

"size happy": {opts: pruneOpts{retentionType: RetentionTypeSize, maxSizeOfBackupsGb: 1}},
"size zero": {opts: pruneOpts{retentionType: RetentionTypeSize, maxSizeOfBackupsGb: 0},
"size happy": {opts: PruneOpts{RetentionType: RetentionTypeSize, MaxSizeOfBackupsGb: 1}},
"size zero": {opts: PruneOpts{RetentionType: RetentionTypeSize, MaxSizeOfBackupsGb: 0},
expectedErr: fmt.Errorf("unexpected size of backups [0]gb found, expected at least 1")},
"size flipped": {opts: pruneOpts{retentionType: RetentionTypeSize, maxSizeOfBackupsGb: 2, maxNumberOfBackups: 25},
expectedErr: fmt.Errorf("unexpected argument [maxNumberOfBackups] found while using RetentionSize")},
"size flipped": {opts: PruneOpts{RetentionType: RetentionTypeSize, MaxSizeOfBackupsGb: 2, MaxNumberOfBackups: 25},
expectedErr: fmt.Errorf("unexpected argument [MaxNumberOfBackups] found while using RetentionSize")},
}

for k, v := range testCases {
Expand Down
6 changes: 6 additions & 0 deletions pkg/operator/etcd_assets/bindata.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading