From 425a8b5fd5f2cb69e5e3c6e918ea6f91f36177ef Mon Sep 17 00:00:00 2001 From: Stefan Benz <46600784+stebenz@users.noreply.github.com> Date: Wed, 13 Oct 2021 14:34:03 +0200 Subject: [PATCH] feat(crdb): use crdb native backup and s3 backup added (#1915) * fix(zitadelctl): implement takedown command * fix(zitadelctl): correct destroy flow * fix(zitadelctl): correct backup commands to read crds beforehand * fix: add of destroyfile * fix: clean for userlist * fix: change backup and restore to crdb native * fix: timeout for delete pvc for cockroachdb * fix: corrected unit tests * fix: add ignored file for scale * fix: correct handling of gitops in backup command * feat: add s3 backup kind * fix: backuplist for s3 and timeout for pv deletion * fix(database): fix nil pointer with binary version * fix(database): cleanup of errors which cam with merging of the s3 logic * fix: correct unit tests * fix: cleanup monitor output Co-authored-by: Elio Bischof * fix: backup imagepullpolixy to ifnotpresent Co-authored-by: Elio Bischof --- cmd/zitadelctl/cmds/backuplist.go | 6 +- cmd/zitadelctl/cmds/restore.go | 16 +- cmd/zitadelctl/cmds/scale.go | 85 +++ go.mod | 5 + go.sum | 379 ++++++++++++- internal/command/setup_step4.go | 1 + operator/crtlcrd/backup.go | 29 +- operator/crtlcrd/zitadel/scale.go | 32 ++ operator/crtlcrd/zitadel/zitadel.go | 48 +- operator/crtlgitops/backup.go | 29 + operator/crtlgitops/scale.go | 41 ++ operator/database/kinds/backups/backups.go | 31 +- .../database/kinds/backups/bucket/adapt.go | 112 ++-- .../kinds/backups/bucket/adapt_test.go | 24 +- .../kinds/backups/bucket/backup/adapt.go | 9 +- .../kinds/backups/bucket/backup/adapt_test.go | 44 +- .../kinds/backups/bucket/backup/cleanup.go | 2 +- .../kinds/backups/bucket/backup/command.go | 38 +- .../backups/bucket/backup/command_test.go | 55 +- .../kinds/backups/bucket/backup/job.go | 2 +- .../kinds/backups/bucket/backup/job_test.go | 4 +- .../kinds/backups/bucket/clean/command.go | 33 -- .../backups/bucket/clean/command_test.go | 38 -- .../database/kinds/backups/bucket/list.go | 3 + .../database/kinds/backups/bucket/mock.go | 24 - .../kinds/backups/bucket/restore/adapt.go | 12 +- .../backups/bucket/restore/adapt_test.go | 22 +- .../kinds/backups/bucket/restore/command.go | 38 +- .../backups/bucket/restore/command_test.go | 57 +- .../kinds/backups/bucket/restore/job.go | 2 +- .../kinds/backups/bucket/restore/job_test.go | 4 +- operator/database/kinds/backups/s3/adapt.go | 296 +++++++++++ .../database/kinds/backups/s3/adapt_test.go | 500 ++++++++++++++++++ .../database/kinds/backups/s3/backup/adapt.go | 154 ++++++ .../kinds/backups/s3/backup/adapt_test.go | 404 ++++++++++++++ .../{bucket/clean => s3/backup}/cleanup.go | 14 +- .../kinds/backups/s3/backup/cleanup_test.go | 41 ++ .../kinds/backups/s3/backup/command.go | 53 ++ .../kinds/backups/s3/backup/command_test.go | 58 ++ .../database/kinds/backups/s3/backup/job.go | 127 +++++ .../kinds/backups/s3/backup/job_test.go | 199 +++++++ operator/database/kinds/backups/s3/desired.go | 65 +++ .../database/kinds/backups/s3/desired_test.go | 155 ++++++ operator/database/kinds/backups/s3/list.go | 105 ++++ operator/database/kinds/backups/s3/mock.go | 149 ++++++ .../{bucket/clean => s3/restore}/adapt.go | 70 ++- .../clean => s3/restore}/adapt_test.go | 123 +++-- .../kinds/backups/s3/restore/cleanup.go | 27 + .../clean => s3/restore}/cleanup_test.go | 10 +- .../kinds/backups/s3/restore/command.go | 48 ++ .../kinds/backups/s3/restore/command_test.go | 59 +++ .../{bucket/clean => s3/restore}/job.go | 49 +- .../{bucket/clean => s3/restore}/job_test.go | 123 ++++- operator/database/kinds/backups/s3/secrets.go | 54 ++ .../database/kinds/backups/s3/secrets_test.go | 38 ++ .../database/kinds/databases/databases.go | 12 +- .../database/kinds/databases/managed/adapt.go | 54 +- .../databases/managed/adapt_backup_test.go | 11 +- .../kinds/databases/managed/adapt_test.go | 26 +- .../database/kinds/databases/managed/mock.go | 35 ++ .../databases/managed/statefulset/adapt.go | 1 + .../databases/managed/statefulset/clean.go | 60 +++ operator/database/kinds/orb/adapt.go | 10 +- pkg/databases/clear.go | 19 +- pkg/databases/restore.go | 10 +- pkg/kubernetes/artifacts.go | 4 +- pkg/zitadel/clearmigraterestore.go | 105 ---- 67 files changed, 3867 insertions(+), 626 deletions(-) create mode 100644 cmd/zitadelctl/cmds/scale.go create mode 100644 operator/crtlcrd/zitadel/scale.go create mode 100644 operator/crtlgitops/backup.go create mode 100644 operator/crtlgitops/scale.go delete mode 100644 operator/database/kinds/backups/bucket/clean/command.go delete mode 100644 operator/database/kinds/backups/bucket/clean/command_test.go create mode 100644 operator/database/kinds/backups/s3/adapt.go create mode 100644 operator/database/kinds/backups/s3/adapt_test.go create mode 100644 operator/database/kinds/backups/s3/backup/adapt.go create mode 100644 operator/database/kinds/backups/s3/backup/adapt_test.go rename operator/database/kinds/backups/{bucket/clean => s3/backup}/cleanup.go (61%) create mode 100644 operator/database/kinds/backups/s3/backup/cleanup_test.go create mode 100644 operator/database/kinds/backups/s3/backup/command.go create mode 100644 operator/database/kinds/backups/s3/backup/command_test.go create mode 100644 operator/database/kinds/backups/s3/backup/job.go create mode 100644 operator/database/kinds/backups/s3/backup/job_test.go create mode 100644 operator/database/kinds/backups/s3/desired.go create mode 100644 operator/database/kinds/backups/s3/desired_test.go create mode 100644 operator/database/kinds/backups/s3/list.go create mode 100644 operator/database/kinds/backups/s3/mock.go rename operator/database/kinds/backups/{bucket/clean => s3/restore}/adapt.go (53%) rename operator/database/kinds/backups/{bucket/clean => s3/restore}/adapt_test.go (59%) create mode 100644 operator/database/kinds/backups/s3/restore/cleanup.go rename operator/database/kinds/backups/{bucket/clean => s3/restore}/cleanup_test.go (98%) create mode 100644 operator/database/kinds/backups/s3/restore/command.go create mode 100644 operator/database/kinds/backups/s3/restore/command_test.go rename operator/database/kinds/backups/{bucket/clean => s3/restore}/job.go (59%) rename operator/database/kinds/backups/{bucket/clean => s3/restore}/job_test.go (60%) create mode 100644 operator/database/kinds/backups/s3/secrets.go create mode 100644 operator/database/kinds/backups/s3/secrets_test.go create mode 100644 operator/database/kinds/databases/managed/mock.go create mode 100644 operator/database/kinds/databases/managed/statefulset/clean.go delete mode 100644 pkg/zitadel/clearmigraterestore.go diff --git a/cmd/zitadelctl/cmds/backuplist.go b/cmd/zitadelctl/cmds/backuplist.go index 388d0e7da..8c0f36806 100644 --- a/cmd/zitadelctl/cmds/backuplist.go +++ b/cmd/zitadelctl/cmds/backuplist.go @@ -2,13 +2,11 @@ package cmds import ( "fmt" + "github.com/caos/orbos/pkg/kubernetes/cli" "sort" - "github.com/spf13/cobra" - - "github.com/caos/orbos/pkg/kubernetes/cli" - "github.com/caos/zitadel/pkg/databases" + "github.com/spf13/cobra" ) func BackupListCommand(getRv GetRootValues) *cobra.Command { diff --git a/cmd/zitadelctl/cmds/restore.go b/cmd/zitadelctl/cmds/restore.go index f9b4f5f45..c89dfd0ca 100644 --- a/cmd/zitadelctl/cmds/restore.go +++ b/cmd/zitadelctl/cmds/restore.go @@ -3,11 +3,11 @@ package cmds import ( "errors" - "github.com/caos/zitadel/pkg/zitadel" - "github.com/caos/orbos/mntr" "github.com/caos/orbos/pkg/kubernetes/cli" + "github.com/caos/zitadel/operator/crtlcrd" + "github.com/caos/zitadel/operator/crtlgitops" "github.com/caos/zitadel/pkg/databases" "github.com/manifoldco/promptui" @@ -82,17 +82,17 @@ func RestoreCommand(getRv GetRootValues) *cobra.Command { return mntr.ToUserError(errors.New("chosen backup is not existing")) } + ensure := func() error { return nil } if rv.Gitops { - if err := zitadel.GitOpsClearMigrateRestore(monitor, gitClient, orbConfig, k8sClient, backup, &version); err != nil { - return err + ensure = func() error { + return crtlgitops.Restore(monitor, gitClient, k8sClient, backup) } } else { - if err := zitadel.CrdClearMigrateRestore(monitor, k8sClient, backup, &version); err != nil { - return err + ensure = func() error { + return crtlcrd.Restore(monitor, k8sClient, backup) } - } - return nil + return scaleForFunction(monitor, gitClient, orbConfig, k8sClient, &version, rv.Gitops, ensure) } return cmd } diff --git a/cmd/zitadelctl/cmds/scale.go b/cmd/zitadelctl/cmds/scale.go new file mode 100644 index 000000000..ff7c8664c --- /dev/null +++ b/cmd/zitadelctl/cmds/scale.go @@ -0,0 +1,85 @@ +package cmds + +import ( + "github.com/caos/orbos/mntr" + "github.com/caos/orbos/pkg/git" + "github.com/caos/orbos/pkg/kubernetes" + orbconfig "github.com/caos/orbos/pkg/orb" + "github.com/caos/zitadel/operator/crtlcrd/zitadel" + "github.com/caos/zitadel/operator/crtlgitops" + kubernetes2 "github.com/caos/zitadel/pkg/kubernetes" + macherrs "k8s.io/apimachinery/pkg/api/errors" +) + +func scaleForFunction( + monitor mntr.Monitor, + gitClient *git.Client, + orbCfg *orbconfig.Orb, + k8sClient *kubernetes.Client, + version *string, + gitops bool, + ensureFunc func() error, +) error { + noOperator := false + if err := kubernetes2.ScaleZitadelOperator(monitor, k8sClient, 0); err != nil { + if macherrs.IsNotFound(err) { + noOperator = true + } else { + return err + } + } + + noZitadel := false + if gitops { + noZitadelT, err := crtlgitops.ScaleDown(monitor, gitClient, k8sClient, orbCfg, version, gitops) + if err != nil { + return err + } + noZitadel = noZitadelT + } else { + noZitadelT, err := zitadel.ScaleDown(monitor, k8sClient, version) + if err != nil { + return err + } + noZitadel = noZitadelT + } + + noDatabase := false + if err := kubernetes2.ScaleDatabaseOperator(monitor, k8sClient, 0); err != nil { + if macherrs.IsNotFound(err) { + noDatabase = true + } else { + return err + } + } + + if err := ensureFunc(); err != nil { + return err + } + + if !noDatabase { + if err := kubernetes2.ScaleDatabaseOperator(monitor, k8sClient, 1); err != nil { + return err + } + } + + if !noZitadel { + if gitops { + if err := crtlgitops.ScaleUp(monitor, gitClient, k8sClient, orbCfg, version, gitops); err != nil { + return err + } + } else { + if err := zitadel.ScaleUp(monitor, k8sClient, version); err != nil { + return err + } + } + } + + if !noOperator { + if err := kubernetes2.ScaleZitadelOperator(monitor, k8sClient, 1); err != nil { + return err + } + } + + return nil +} diff --git a/go.mod b/go.mod index e11154d19..ad2df932b 100644 --- a/go.mod +++ b/go.mod @@ -15,6 +15,11 @@ require ( github.com/VictoriaMetrics/fastcache v1.7.0 github.com/ajstarks/svgo v0.0.0-20210406150507-75cfd577ce75 github.com/allegro/bigcache v1.2.1 + github.com/aws/aws-sdk-go-v2 v1.6.0 // indirect + github.com/aws/aws-sdk-go-v2/config v1.3.0 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.2.1 // indirect + github.com/aws/aws-sdk-go-v2/service/dynamodb v1.3.1 // indirect + github.com/aws/aws-sdk-go-v2/service/s3 v1.10.0 // indirect github.com/boombuler/barcode v1.0.1 github.com/caos/logging v0.0.2 github.com/caos/oidc v0.15.10 diff --git a/go.sum b/go.sum index 8bfcb8580..d729058be 100644 --- a/go.sum +++ b/go.sum @@ -32,19 +32,26 @@ cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNF cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0 h1:PQcPefKFdaIzjQFbiyOgAqyx8q5djaE7x9Sqe712DPA= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0 h1:/May9ojXjRkPBNVrq+oWLqmWCkr4OU5uRY29bu0mRyQ= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/firestore v1.1.0 h1:9x7Bx0A9R5/M9jibeJeZWqjeVEIxYW9fZYqB9a70/bY= cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1 h1:ukjixP1wl0LpnZ6LWtZJ0mX5tBmjp1f8Sqer8Z2OMUU= cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.16.0 h1:1UwAux2OZP4310YXg5ohqBEpV16Y93uZG4+qOX7K2Kg= +cloud.google.com/go/storage v1.16.0/go.mod h1:ieKBmUyzcftN5tbxwnXClMKH00CfcQ+xL6NN0r5QfmE= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9 h1:VpgP7xuJadIUuKccphEpTJnWhS2jkQyMt6Y7pJCD7fY= cloud.google.com/go/storage v1.16.1 h1:sMEIc4wxvoY3NXG7Rn9iP7jb/2buJgWR1vNXCR/UPfs= cloud.google.com/go/storage v1.16.1/go.mod h1:LaNorbty3ehnU3rEjXSNV/NRgQA0O8Y+uh6bPe5UOk4= cloud.google.com/go/trace v0.1.0 h1:nUGUK79FOkN0UGUXhBmVBkbu1PYsHe0YyFSPLOD9Npg= @@ -54,41 +61,55 @@ cloud.google.com/go/trace v1.0.0/go.mod h1:4iErSByzxkyHWzzlAj63/Gmjz0NH1ASqhJguH dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/AlecAivazis/survey/v2 v2.2.15 h1:6UNMnk+YGegYFiPfdTOyZDIN+m08x2nGnqOn15BWcEQ= github.com/AlecAivazis/survey/v2 v2.2.15/go.mod h1:TH2kPCDU3Kqq7pLbnCWwZXDBjnhZtmsCle5EiYDJ2fg= +github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9 h1:HD8gA2tkByhMAwYaFAX9w2l7vxvBQ5NMoxDrkhqhtn4= github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/AppsFlyer/go-sundheit v0.2.0 h1:FArqX+HbqZ6U32RC3giEAWRUpkggqxHj91KIvxNgwjU= github.com/AppsFlyer/go-sundheit v0.2.0/go.mod h1:rCRkVTMQo7/krF7xQ9X0XEF1an68viFR6/Gy02q+4ds= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/Azure/go-ansiterm v0.0.0-20210608223527-2377c96fe795/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= github.com/Azure/go-autorest/autorest v0.11.12/go.mod h1:eipySxLmqSyC5s5k1CLupqet0PSENBEDP93LQ9a8QYw= +github.com/Azure/go-autorest/autorest v0.11.18 h1:90Y4srNYrwOtAgVo3ndrQkTYn6kf1Eg/AjTFJ8Is2aM= github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= +github.com/Azure/go-autorest/autorest/adal v0.9.13 h1:Mp5hbtOePIzM8pJVRa3YLrWWmZtoxRXqUEzCfJt3+/Q= github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= +github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw= github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.4.1 h1:K0laFcLE6VLTOwNgSxaGbUcLPuGXlNkbVvq4cW4nIHk= github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg= github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= +github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.4.1 h1:GaI7EiDXDRfa8VshkTj7Fym7ha+y8/XxIgD2okUIjLw= github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802 h1:1BDTz0u9nC3//pOCMdNH+CiXJVYJh5UQNCOBG7jbELc= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53 h1:sR+/8Yb4slttB4vD+b9btVEnWgL3Q00OBTzVT8B9C0c= github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno= +github.com/CloudyKit/jet/v3 v3.0.0 h1:1PwO5w5VCtlUUl+KTOBsTGZlhjWkcybsGaAau52tOy8= github.com/CloudyKit/jet/v3 v3.0.0/go.mod h1:HKQPgSJmdK8hdoAbKUUWajkHyHo4RaU5rMdUywE7VMo= github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/trace v1.0.0-RC2 h1:zQoLPDL4o59qnguhsQ655DD/B0MBnPILQLVU1oirN9E= github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/trace v1.0.0-RC2/go.mod h1:wUQuqLc5wdTVnX/mgszL0WJagBhN+cbqZf1Ax/SNGSk= +github.com/Joker/hpp v1.0.0 h1:65+iuJYdRXv/XyN62C1uEmmOx3432rNG/rKlX6V7Kkc= github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= +github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd h1:sjQovDkwrZp8u+gxLtPgKGjk5hCxuy2hrRejBTA9xFU= github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= @@ -99,47 +120,100 @@ github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuN github.com/Masterminds/squirrel v1.5.0 h1:JukIZisrUXadA9pl3rMkjhiamxiB0cXiu+HGp/Y8cY8= github.com/Masterminds/squirrel v1.5.0/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8 h1:xzYJEypr/85nBpB11F9br+3HUrpgb+fcm5iADzXXYEw= github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc= +github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/PuerkitoBio/goquery v1.5.1 h1:PSPBGne8NIUWw+/7vFBV+kG2J/5MOjbzc7154OaKCSE= github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc= github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398 h1:WDC6ySpJzbxGWFh4aMxFFC28wwGp5pEuoTtvA4q/qQ4= github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= +github.com/VictoriaMetrics/fastcache v1.6.0 h1:C/3Oi3EiBCqufydp1neRZkqcwmEiuRT9c3fqvvgKm5o= +github.com/VictoriaMetrics/fastcache v1.6.0/go.mod h1:0qHz5QP0GMX4pfmMA/zt5RgfNuXJrTP0zS7DqpHGGTw= +github.com/agnivade/levenshtein v1.0.1 h1:3oJU7J3FGFmyhn8KHjmVaZCN5hxTr7GxgRue+sxIXdQ= github.com/VictoriaMetrics/fastcache v1.7.0 h1:E6GibaGI685TafrI7E/QqZPkMsOzRw+3gpICQx08ISg= github.com/VictoriaMetrics/fastcache v1.7.0/go.mod h1:n7Sl+ioh/HlWeYHLSIBIE8TcZFHg/+xgvomWSS5xuEE= github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= +github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/ajstarks/svgo v0.0.0-20210406150507-75cfd577ce75 h1:tuK1xIp+jrEEF0l3xXab78w89ilYr0Am170KdSml2xc= github.com/ajstarks/svgo v0.0.0-20210406150507-75cfd577ce75/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= 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= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/allegro/bigcache v1.2.1 h1:hg1sY1raCwic3Vnsvje6TT7/pnZba83LeFck5NrFKSc= github.com/allegro/bigcache v1.2.1/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= +github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= +github.com/andybalholm/cascadia v1.1.0 h1:BuuO6sSfQNFRu1LppgbD25Hr2vLYW25JvxHs5zzsLTo= github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= +github.com/antihax/optional v1.0.0 h1:xK2lYat7ZLaVVcIuj82J8kIro4V6kDe0AUDFboUCwcg= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e h1:QEF07wC0T1rKkctt1RINW/+RMTVmiwxETico2l3gxJA= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6 h1:G1bPvciwNyF7IUmKXNt9Ak3m6u9DE1rF+RmtIkBpVdA= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da h1:8GUt8eRujhVEGZFFEjBj46YV4rDjvGrNxb0KMWYkL2I= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310 h1:BUAU3CGlLvorLI26FmByPp2eC2qla6E1Tw+scpcg/to= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= +github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.31.12/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= +github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= +github.com/aws/aws-sdk-go-v2 v1.6.0 h1:r20hdhm8wZmKkClREfacXrKfX0Y7/s0aOoeraFbf/sY= +github.com/aws/aws-sdk-go-v2 v1.6.0/go.mod h1:tI4KhsR5VkzlUa2DZAdwx7wCAYGwkZZ1H31PYrBFx1w= +github.com/aws/aws-sdk-go-v2/config v1.3.0 h1:0JAnp0WcsgKilFLiZEScUTKIvTKa2LkicadZADza+u0= +github.com/aws/aws-sdk-go-v2/config v1.3.0/go.mod h1:lOxzHWDt/k7MMidA/K8DgXL4+ynnZYsDq65Qhs/l3dg= +github.com/aws/aws-sdk-go-v2/credentials v1.2.1 h1:AqQ8PzWll1wegNUOfIKcbp/JspTbJl54gNonrO6VUsY= +github.com/aws/aws-sdk-go-v2/credentials v1.2.1/go.mod h1:Rfvim1eZTC9W5s8YJyYYtl1KMk6e8fHv+wMRQGO4Ru0= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.1.1 h1:w1ocBIhQkLgupEB3d0uOuBddqVYl0xpubz7HSTzWG8A= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.1.1/go.mod h1:GTXAhrxHQOj9N+J5tYVjwt+rpRyy/42qLjlgw9pz1a0= +github.com/aws/aws-sdk-go-v2/internal/ini v1.0.0 h1:k7I9E6tyVWBo7H9ffpnxDWudtjau6Qt9rnOYgV+ciEQ= +github.com/aws/aws-sdk-go-v2/internal/ini v1.0.0/go.mod h1:g3XMXuxvqSMUjnsXXp/960152w0wFS4CXVYgQaSVOHE= +github.com/aws/aws-sdk-go-v2/service/dynamodb v1.3.1 h1:uAn7miAtNHewvTnGbXOA0dW1yE/3spgq9lB2D3sfpeQ= +github.com/aws/aws-sdk-go-v2/service/dynamodb v1.3.1/go.mod h1:zL1ZppTfOSWcDLRURlZn9w4Wl0jceSBF5PoUXa1amYc= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.1.0 h1:XwqxIO9LtNXznBbEMNGumtLN60k4nVqDpVwVWx3XU/o= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.1.0/go.mod h1:zdjOOy0ojUn3iNELo6ycIHSMCp4xUbycSHfb8PnbbyM= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.1.1 h1:l7pDLsmOGrnR8LT+3gIv8NlHpUhs7220E457KEC2UM0= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.1.1/go.mod h1:2+ehJPkdIdl46VCj67Emz/EH2hpebHZtaLdzqg+sWOI= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.4.0 h1:VacTNowcxS2WG9cmHbBi7nYq34xFSud7OYSkezf2VyQ= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.4.0/go.mod h1:IpjxfORBAFfkMM0VEx5gPPnEy6WV4Hk0F/+zb/SUWyw= +github.com/aws/aws-sdk-go-v2/service/s3 v1.10.0 h1:BPUiwgs2sTnu1pzBa2oblYzo0qXLfVPblb6QVqcZWkg= +github.com/aws/aws-sdk-go-v2/service/s3 v1.10.0/go.mod h1:azwgEajHWHcobFQRqwHcwLv+m/aip/uZnuqpFm1MSZ4= +github.com/aws/aws-sdk-go-v2/service/sso v1.2.1 h1:alpXc5UG7al7QnttHe/9hfvUfitV8r3w0onPpPkGzi0= +github.com/aws/aws-sdk-go-v2/service/sso v1.2.1/go.mod h1:VimPFPltQ/920i1X0Sb0VJBROLIHkDg2MNP10D46OGs= +github.com/aws/aws-sdk-go-v2/service/sts v1.4.1 h1:9Z00tExoaLutWVDmY6LyvIAcKjHetkbdmpRt4JN/FN0= +github.com/aws/aws-sdk-go-v2/service/sts v1.4.1/go.mod h1:G9osDWA52WQ38BDcj65VY1cNmcAQXAXTsE8IWH8j81w= +github.com/aws/smithy-go v1.4.0 h1:3rsQpgRe+OoQgJhEwGNpIkosl0fJLdmQqF4gSFRjg+4= +github.com/aws/smithy-go v1.4.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= +github.com/benbjohnson/clock v1.0.3 h1:vkLuvpK4fmtSCuo60+yC63p7y0BmQ8gm5ZXGuBCJyXg= +github.com/aws/aws-sdk-go v1.40.7 h1:dD5+UZxedqHeE4WakJHEhTsEARYlq8kHkYEf89R1tEo= github.com/aws/aws-sdk-go v1.40.7/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q= +github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible h1:Ppm0npCCsmuR9oQaBtRuZcmILVE74aXE+AmrJj8L2ns= github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= @@ -148,33 +222,48 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= +github.com/bketelsen/crypt v0.0.4 h1:w/jqZtC9YD4DS/Vp9GhWfWcCpuAL58oTnLoI8vE9YHU= github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/boombuler/barcode v1.0.1 h1:NDBbPmhS+EqABEs5Kg3n/5ZNjy73Pz7SIV+KCeqyXcs= github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/caos/logging v0.0.2 h1:ebg5C/HN0ludYR+WkvnFjwSExF4wvyiWPyWGcKMYsoo= github.com/caos/logging v0.0.2/go.mod h1:9LKiDE2ChuGv6CHYif/kiugrfEXu9AwDiFWSreX7Wp0= +github.com/caos/oidc v0.14.4/go.mod h1:H5Y2zw3YIrWqQOoy0wcmZva2a66bumDyU2iOhXiM9uA= +github.com/caos/oidc v0.15.3 h1:DNzzvSgUbhUewrZKOVF9nDop0AfMy0wjnMy/rD9f8xA= +github.com/caos/oidc v0.15.3/go.mod h1:doQ1B/mGnQWbgS+UOANIQCPJe1+KACyxQ8wjV2d11h0= +github.com/caos/oidc v0.15.7 h1:jC7ugbQG1WJbGZgCXy1fE0B1VwWKvtKXLXY/pGDybhA= github.com/caos/oidc v0.15.7/go.mod h1:doQ1B/mGnQWbgS+UOANIQCPJe1+KACyxQ8wjV2d11h0= +github.com/caos/orbos v1.5.14-0.20210428081839-983ffc569980 h1:Fz0aYUwGMA2tsu5w7SryqFGjqGClJVHbyhBMT5SXtPU= +github.com/caos/orbos v1.5.14-0.20210428081839-983ffc569980/go.mod h1:2I8oiZb5SMRm/qTLvwpSmdV0M6ex8J/UKyxUGfKaqJo= +github.com/caos/orbos v1.5.14-0.20210621082229-b29e64ff75e6 h1:0gmrJDKVCiFvKNtOfoccV+ux6LmAHGRg11+pL8qyCCs= +github.com/caos/orbos v1.5.14-0.20210621082229-b29e64ff75e6/go.mod h1:2I8oiZb5SMRm/qTLvwpSmdV0M6ex8J/UKyxUGfKaqJo= github.com/caos/oidc v0.15.10 h1:dSzkIvsZR2PSZgvBFFkLJt8A/MujsyLac1yNvBShXuw= github.com/caos/oidc v0.15.10/go.mod h1:4l0PPwdc6BbrdCFhNrRTUddsG292uHGa7gE2DSEIqoU= github.com/caos/orbos v1.5.14-0.20210803090517-905668247c09 h1:9NHrHp09Sz4FQbwnlfRa16lxWa7MUJtiHgZGKJxF+58= github.com/caos/orbos v1.5.14-0.20210803090517-905668247c09/go.mod h1:4raGz+E7Vxzg5TE+TwbnN+APn7ffs4FTVhsEyuHoPQE= +github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cenkalti/backoff v2.1.1+incompatible h1:tKJnvO2kl0zmb/jA5UKAt4VoEVw1qxKWjE/Bpp46npY= github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff/v4 v4.1.1 h1:G2HAfAmvm/GcKan2oOQpBXOd2tT2G57ZnZGWa1PxPBQ= github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= +github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= +github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054 h1:uH66TXeswKn5PW5zdZ39xEwfS9an067BirqA+P4QaLI= github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 h1:7aWHqerlJ41y6FOsEUvknqgXnGmJyJSbjhAWq5pO4F8= github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw= github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= @@ -182,6 +271,7 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5O github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/cfssl v0.0.0-20190726000631-633726f6bcb7 h1:Puu1hUwfps3+1CUzYdAZXijuvLuRMirgiXdf3zsM2Ig= github.com/cloudflare/cfssl v0.0.0-20190726000631-633726f6bcb7/go.mod h1:yMWuSON2oQp+43nFtAV/uvKQIFpSPerB57DCt9t8sSA= @@ -191,33 +281,50 @@ github.com/cloudscale-ch/cloudscale-go-sdk v1.6.0 h1:qKHn4YlgYKS0oHnOoDvPnL5jDUP github.com/cloudscale-ch/cloudscale-go-sdk v1.6.0/go.mod h1:FhOTOCgKAVvRRMQc1mC0D7xK/3zYnmcZBWFXNkacvMc= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403 h1:cqQfy1jclcSy/FwLjemeg3SR1yaINm74aQyupQ0Bl8M= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed h1:OZmjad4L3H8ncOIR8rnb5MREYqG8ixi5+WbeUsquF0c= github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/cockroachdb/cockroach-go/v2 v2.1.1 h1:3XzfSMuUT0wBe1a3o5C0eOTcArhmmFAg2Jzh/7hhKqo= github.com/cockroachdb/cockroach-go/v2 v2.1.1/go.mod h1:7NtUnP6eK+l6k483WSYNrq3Kb23bWV10IRV1TyeSpwM= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5 h1:xD/lrqdvwsc+O2bjSSi3YqY73Ke3LAiSCx49aCesA0E= github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo= +github.com/cockroachdb/errors v1.2.4 h1:Lap807SXTH5tri2TivECb/4abUkMZC9zRoLarvcKDqs= github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA= +github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f h1:o/kfcElHqOiXqcou5a3rIlMc7oJbMQkeLk0VQJ7zgqY= github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI= +github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 h1:sDMmm+q/3+BukdIpxwO365v/Rbspp2Nt5XntgQRXq8Q= github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM= +github.com/coreos/bbolt v1.3.2 h1:wZwiHHUieZCquLkDL0B8UhzreNWsPHooDAG3q34zk0s= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/etcd v3.3.13+incompatible h1:8F3hqu9fGYLBifCmRCJsicFqDx/D68Rt3q1JMazcgBQ= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible h1:bXhRBIXoTm9BYHS3gE0TtQuyNZyeEMux2sDi4oo5YOo= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-oidc v2.1.0+incompatible h1:sdJrfw8akMnCuUlaZU3tE/uYXFgfqom8DBE9so9EBsM= github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f h1:JOrtw2xFKzlg+cbHpyrpLDmnN1HqhBfnX7WDiW7eG2c= github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f h1:lBNOc5arjvs8E5mO2tbpBpLoyyu8B6e44T7hJy6potg= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -226,23 +333,32 @@ github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd h1:uVsMphB1eRx7xB1njzL3fuMdWRN8HtVzoUOItHMwv5c= github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE= github.com/deckarep/golang-set v1.7.1 h1:SCQV0S6gTtp6itiFrTqI+pfmJ4LN85S1YzhDf9rTHJQ= github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6ROGeiHFAP8WJdI2RoxALQYgdllERc3N5N2DM= github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= +github.com/dgraph-io/badger v1.6.0 h1:DshxFxZWXUcO0xX476VJC07Xsr6ZCBVRHKZ93Oh7Evo= github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4= github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954 h1:RMLoZVzv4GliuWafOuPuQDKSm1SJph7uCRnnS61JAn4= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug= github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91 h1:Izz0+t1Z5nI16/II7vuEo/nHjodOg0p7+OiDpjX5t1E= github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0 h1:w3NnFcKR5241cfmQU5ZZAsf0xcpId6mWOupTvJlUX2U= github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96 h1:cenwrSVm+Z7QLSV/BsnenAOcDXdX4cMv4wP0B/5QbPg= github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815 h1:bWDMxwH3px2JBh6AyO7hdCn/PkvCZXii8TGj7sbtEbQ= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dop251/goja v0.0.0-20210817151038-07a7fd9355b4 h1:c6+6EmiSboC79bkEtZGQhpeEWP1lzHuHpr1tPdISdYo= github.com/dop251/goja v0.0.0-20210817151038-07a7fd9355b4/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= @@ -253,10 +369,12 @@ github.com/duo-labs/webauthn v0.0.0-20210727191636-9f1b88ef44cc/go.mod h1:/X2OJi github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385 h1:clC1lXBpe2kTj2VHdaIu9ajZQe4kcEY9j0NsnDDBZ3o= github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/emicklei/go-restful v2.9.5+incompatible h1:spTtZBk5DYEvbxMVutUuTyh1Ao2r4iyvLdACqsl/Ljk= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= @@ -266,6 +384,7 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0 h1:dulLQAYQFYtG5MTplgNGHWuV2D+OBD+Z8lmDBmbLg+s= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= @@ -273,6 +392,7 @@ github.com/envoyproxy/protoc-gen-validate v0.6.1 h1:4CF52PCseTFt4bE+Yk3dIpdVi7XW github.com/envoyproxy/protoc-gen-validate v0.6.1/go.mod h1:txg5va2Qkip90uYoSKH+nkAAmXrb2j3iq4FLwdrCbXQ= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= +github.com/etcd-io/bbolt v1.3.3 h1:gSJmxrs37LgTqR/oyJBWok6k6SvXEUerFTbltIhXkBM= github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= @@ -280,25 +400,36 @@ github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLi github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.11.0+incompatible h1:glyUF9yIYtMHzn8xaKw5rMhdWcwsYV8dZHIq5567/xs= github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM= github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= +github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072 h1:DddqAaWDpywytcG8w/qoQ5sAN8X12d3Z3koB0C3Rxsc= github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8= +github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8= github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= +github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/felixge/httpsnoop v1.0.2 h1:+nS9g82KMXccJ/wp0zyRW9ZBHFETmMGtkk+2CTTrW4o= github.com/felixge/httpsnoop v1.0.2/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/form3tech-oss/jwt-go v3.2.3+incompatible h1:7ZaBxOI7TMoYBfyA3cQHErNNyAWIKUMIwqxEtgHOs5c= github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fvbommel/sortorder v1.0.1 h1:dSnXLt4mJYH25uDDGa3biZNQsozaUWDSWeKJ0qqFfzE= github.com/fvbommel/sortorder v1.0.1/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0= github.com/fxamacker/cbor/v2 v2.2.0 h1:6eXqdDDe588rSYAi1HfZKbx6YYQO4mxQ9eC6xYpU/JQ= github.com/fxamacker/cbor/v2 v2.2.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= +github.com/gavv/httpexpect v2.0.0+incompatible h1:1X9kcRshkSKEjNJJxX9Y9mQ5BRfbxU5kORdjhlA1yX8= github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc= +github.com/getsentry/raven-go v0.2.0 h1:no+xWJRb5ZI7eE8TWgIq1jLulQiIoLG0IfYxv5JYMGs= github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= github.com/getsentry/sentry-go v0.11.0 h1:qro8uttJGvNAMr5CLcFI9CHR0aDzXl0Vs3Pmw/oTPg8= github.com/getsentry/sentry-go v0.11.0/go.mod h1:KBQIxiZAetw62Cj8Ri964vAEWVdgfaUCn30Q3bCvANo= @@ -306,13 +437,17 @@ github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2H github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= +github.com/gin-gonic/gin v1.5.0 h1:fi+bqFAx/oLK54somfCtEZs9HeH1LHVoEPUgARpTqyc= github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do= github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0= github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= +github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8 h1:DujepqpGd1hyOd7aW59XpK7Qymp8iy83xq74fLr21is= github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= +github.com/go-check/check v0.0.0-20180628173108-788fd7840127 h1:0gkP6mzaMqkmpcJYCFOLkIBwI7xFExG03bbkOkCvUPI= github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= @@ -324,14 +459,19 @@ github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12 h1:PbK github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw= github.com/go-git/go-git/v5 v5.2.0 h1:YPBLG/3UK1we1ohRkncLjaXWLW+HKp5QNM/jTli2JgI= github.com/go-git/go-git/v5 v5.2.0/go.mod h1:kh02eMX+wdqqxgNMEyq8YgwlIOsDOa9homkUq1PoTMs= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1 h1:QbL/5oDUmRBzO9/Z7Seo6zf912W/a6Sr4Eu0G/3Jho0= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4 h1:WtGNWLvXpe6ZudgnXrq0barxBImvnnJoMEhXAzcbM0I= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0 h1:wDJmvq38kDhkVxi50ni9ykkdUr1PKgqKOoi01fa0Mdk= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/log v0.1.0 h1:DGJh0Sm43HbOeYDNnVZFl8BvcYVvjD5bqYJvp0REbwQ= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= @@ -339,70 +479,90 @@ github.com/go-logr/logr v0.4.0 h1:K7/B1jt6fIBQVd4Owv2MqGQClcgf0R266+7C/QjRcLc= github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/zapr v0.4.0 h1:uc1uML3hRYL9/ZZPdgHS/n8Nzo+eaYL/Efxkkamf7OM= github.com/go-logr/zapr v0.4.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk= +github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab h1:xveKWz2iaueeTaUgdetzel+U7exyigDYBryyVfV/rZk= github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8= github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk= +github.com/go-openapi/analysis v0.19.5 h1:8b2ZgKfKIUTVQpTb77MoRDIMEIwvDVw40o3aOXdfYzI= github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU= github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= +github.com/go-openapi/errors v0.19.2 h1:a2kIyV3w+OS3S97zxUndRVD46+FhGOUBDFY7nmu4CsY= github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= +github.com/go-openapi/jsonreference v0.19.5 h1:1WJP/wi4OjB4iV8KVbH73rQaoialJrqv8gitZLxGLtM= github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs= +github.com/go-openapi/loads v0.19.4 h1:5I4CCSqoWzT+82bBkNIvmLc0UOsoKKQ4Fz+3VxOB7SY= github.com/go-openapi/loads v0.19.4/go.mod h1:zZVHonKd8DXyxyw4yfnVjPzBjIQcLt0CCsn0N0ZrQsk= github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA= github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64= +github.com/go-openapi/runtime v0.19.4 h1:csnOgcgAiuGoM/Po7PEpKDoNulCcF3FGbSnbHfxgjMI= github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4= github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY= github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/spec v0.19.5 h1:Xm0Ao53uqnk9QE/LlYV5DEU09UAgpliA85QoT9LzqPw= github.com/go-openapi/spec v0.19.5/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk= github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY= github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU= +github.com/go-openapi/strfmt v0.19.5 h1:0utjKrw+BAh8s57XE9Xz8DUBsVvPmRUB6styvl9wWIM= github.com/go-openapi/strfmt v0.19.5/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk= github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng= github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= +github.com/go-openapi/validate v0.19.8 h1:YFzsdWIDfVuLvIOF+ZmKjVg1MbPJ1QgY9PihMwei1ys= github.com/go-openapi/validate v0.19.8/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= +github.com/go-playground/locales v0.12.1 h1:2FITxuFt/xuCNP1Acdhv62OzaCiviiE4kotfhkmOqEc= github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM= +github.com/go-playground/universal-translator v0.16.0 h1:X++omBR/4cE2MNg91AoC3rmGrCjJ8eAeUP/K/EKx4DM= github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY= github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU= github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/gobuffalo/flect v0.2.0 h1:EWCvMGGxOjsgwlWaP+f4+Hh6yrrte7JeFL2S6b+0hdM= github.com/gobuffalo/flect v0.2.0/go.mod h1:W3K3X9ksuZfir8f/LrfVtWmCDQFfayuylOJ7sz/Fj80= +github.com/gobuffalo/here v0.6.0 h1:hYrd0a6gDmWxBM4TnrGw8mQg24iSVoIkHEk7FodQcBI= github.com/gobuffalo/here v0.6.0/go.mod h1:wAG085dHOYqUpf+Ap+WOdrPTp5IYcDAs/x7PLa8Y5fM= +github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0= github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= +github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo= github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= +github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= @@ -455,12 +615,15 @@ github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e h1:KhcknUwkWHKZPbFy2P7jH5LKJ3La+0ZeknkkmrSgqb0= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk= +github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38 h1:y0Wmhvml7cGnzPa9nocn/fMraMH/lMDdeG+rkx4VgYY= github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= github.com/google/certificate-transparency-go v1.0.21 h1:Yf1aXowfZ2nuboBsg7iYGLmwsOARdV86pfH3g95wXmE= github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= @@ -503,9 +666,12 @@ github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210715191844-86eeefc3e471 h1:WqmlwDwojb0rrPPtueSYqNrONX90T3SjwZeVUr4QCtI= github.com/google/pprof v0.0.0-20210715191844-86eeefc3e471/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA= 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/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -525,6 +691,7 @@ github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9 github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= github.com/googleinterns/cloud-operations-api-mock v0.0.0-20200709193332-a1e58c29bdd3 h1:eHv/jVY/JNop1xg2J9cBb4EzyMpWZoNCP1BslSAIkOI= github.com/googleinterns/cloud-operations-api-mock v0.0.0-20200709193332-a1e58c29bdd3/go.mod h1:h/KNeRx7oYU4SpA4SoY7W2/NxDKEEVuwA6j9A27L4OI= +github.com/gophercloud/gophercloud v0.1.0 h1:P/nh25+rzXouhytV2pUHBb65fnds26Ghl8/391+sT5o= github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= @@ -541,64 +708,99 @@ github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+ github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.5.0 h1:ajue7SzQMywqRjg2fK7dcpc0QhFGpTR2plWfV4EZWR4= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.5.0/go.mod h1:r1hZAcvfFXuYmcKyCJI9wlyOPIZUJl6FCB8Cpca/NLE= +github.com/hashicorp/consul/api v1.1.0 h1:BNQPM9ytxj6jbjjdRPioQ94T6YXriSopn0i8COv6SRA= github.com/grpc-ecosystem/grpc-gateway/v2 v2.6.0 h1:rgxjzoDmDXw5q8HONgyHhBas4to0/XWRo/gPpJhsUNQ= github.com/grpc-ecosystem/grpc-gateway/v2 v2.6.0/go.mod h1:qrJPVzv9YlhsrxJc3P/Q85nr0w1lIRikTl4JlhdDH5w= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/sdk v0.1.1 h1:LnuDWGNsoajlhGyHJvuWW6FVqRl8JOTPqS6CPTsYjhY= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-immutable-radix v1.0.0 h1:AKDB1HM5PWEA7i4nhcpwOrO2byshxBjXVn/J/3+z5/0= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3 h1:zKjpN5BK/P5lMYrLmBHdBULWbJ0XpYR+7NGzqkZzoD4= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/go-sockaddr v1.0.0 h1:GeH6tui99pF4NJgfnhp+L6+FfobzVW3Ah46sLo0ICXs= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0 h1:KaodqZuhUoZereWVIYmpUgZysurB1kBLX2j0MwMrUAE= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.2.0 h1:3vNe/fWF5CBgRIguda1meWhsZHy3m8gCJ5wx+dIzX/E= github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go.net v0.0.1 h1:sNCoNyDEvN1xa+X0baata4RdcpKwcMS6DH+xwfqPgjw= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0 h1:WhIgCr5a7AaVH6jPUwjtRuuE7/RDufnUvzIr48smyxs= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3 h1:EmmoJme1matNzb+hMpDuR/0sbJSUisxyqBGG676r31M= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2 h1:YZ7UKsJv+hKjqGVUUbtE3HNj79Eln2oQ75tniF6iPt0= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174 h1:WlZsjVhE8Af9IcZDGgJGQpNflI3+MJSBhsgT5PCtzBQ= github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw= github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/iancoleman/strcase v0.0.0-20180726023541-3605ed457bf7 h1:ux/56T2xqZO/3cP1I2F86qpeoYPCOzk+KF/UH/Ar+lk= github.com/iancoleman/strcase v0.0.0-20180726023541-3605ed457bf7/go.mod h1:SK73tn/9oHe+/Y0h39VT4UCxmurVJkR5NA7kMEAOgSE= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639 h1:mV02weKRL81bEnm8A0HT1/CAelMQDBuQIfLw8n+d6xI= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imkira/go-interpol v1.1.0 h1:KIiKr0VSG2CUW1hl1jpiyuzuJeKUUpC8iM1AIE7N1Vk= github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/iris-contrib/blackfriday v2.0.0+incompatible h1:o5sHQHHm0ToHUlAJSTjW9UWicjJSDDauOOQ2AHuIVp4= github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI= +github.com/iris-contrib/go.uuid v2.0.0+incompatible h1:XZubAYg61/JwnJNbZilGjf3b3pB80+OQg2qf6c8BfWE= github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0= +github.com/iris-contrib/jade v1.1.3 h1:p7J/50I0cjo0wq/VWVCDFd8taPJbuFC+bq23SniRFX0= github.com/iris-contrib/jade v1.1.3/go.mod h1:H/geBymxJhShH5kecoiOCSssPX7QWYH7UaeZTSWddIk= +github.com/iris-contrib/pongo2 v0.0.1 h1:zGP7pW51oi5eQZMIlGA3I+FHY9/HOQWDB+572yin0to= github.com/iris-contrib/pongo2 v0.0.1/go.mod h1:Ssh+00+3GAZqSQb30AvBRNxBx7rf0GqwkjqxNd0u65g= +github.com/iris-contrib/schema v0.0.1 h1:10g/WnoRR+U+XXHWKBHeNy/+tZmM2kcAVGLOsz+yaDA= github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw= +github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0= github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= +github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= @@ -606,18 +808,25 @@ github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsU github.com/jackc/pgconn v1.4.0/go.mod h1:Y2O3ZDF0q4mMacyWV3AstPJpeHXWGEetiFttmq5lahk= github.com/jackc/pgconn v1.5.0/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI= github.com/jackc/pgconn v1.5.1-0.20200601181101-fa742c524853/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI= +github.com/jackc/pgconn v1.8.0 h1:FmjZ0rOyXTr1wfWs45i4a9vjnjWUAGpMuQLD9OSs+lw= github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= +github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= +github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2 h1:JVX6jT/XfzNqIjye4717ITLaNwV9mWbJx0dLCpcRzdA= github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= +github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= +github.com/jackc/pgproto3 v1.1.0 h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A= github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= github.com/jackc/pgproto3/v2 v2.0.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.0.6 h1:b1105ZGEMFe7aCvrT1Cca3VoVb4ZFMaFJLJcg/3zD+8= github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgservicefile v0.0.0-20200307190119-3430c5407db8/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= +github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= @@ -625,6 +834,7 @@ github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrU github.com/jackc/pgtype v1.2.0/go.mod h1:5m2OfMh1wTK7x+Fk952IDmI4nw3nPrvtQdM0ZT4WpC0= github.com/jackc/pgtype v1.3.1-0.20200510190516-8cd94a14c75a/go.mod h1:vaogEUkALtxZMCH411K+tKzNpwzCKU+AnPzBKZ+I+Po= github.com/jackc/pgtype v1.3.1-0.20200606141011-f6355165a91c/go.mod h1:cvk9Bgu/VzJ9/lxTO5R5sf80p0DiucVtN7ZxvaC4GmQ= +github.com/jackc/pgtype v1.6.2 h1:b3pDeuhbbzBYcg5kwNmNDun4pFUD/0AAr1kLXZLeNt8= github.com/jackc/pgtype v1.6.2/go.mod h1:JCULISAZBFGrHaOXIIFiyfzW5VY0GRitRr8NeJsrdig= github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= @@ -632,14 +842,17 @@ github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQ github.com/jackc/pgx/v4 v4.5.0/go.mod h1:EpAKPLdnTorwmPUUsqrPxy5fphV18j9q3wrfRXgo+kA= github.com/jackc/pgx/v4 v4.6.1-0.20200510190926-94ba730bb1e9/go.mod h1:t3/cdRQl6fOLDxqtlyhe9UWgfIi9R8+8v8GKV5TRA/o= github.com/jackc/pgx/v4 v4.6.1-0.20200606145419-4e5062306904/go.mod h1:ZDaNWkt9sW1JMiNn0kdYBaLelIhw7Pg4qd+Vk6tw7Hg= +github.com/jackc/pgx/v4 v4.10.1 h1:/6Q3ye4myIj6AaplUm+eRcz4OhK9HAvFf4ePsG40LJY= github.com/jackc/pgx/v4 v4.10.1/go.mod h1:QlrWebbs3kqEZPHCTGyxecvzG6tvIsYu+A5b1raylkA= github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/puddle v1.1.3 h1:JnPg/5Q9xVJGfjsO5CPUOjnJps1JaRUm8I9FXVCFK94= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= +github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jinzhu/gorm v1.9.16 h1:+IyIjPEABKRpsu/F8OvDPy9fyQlgsg2luMV2ZIH5i5o= github.com/jinzhu/gorm v1.9.16/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs= @@ -648,12 +861,24 @@ github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkr github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jinzhu/now v1.1.1 h1:g39TucaRWyV3dwDO++eEc6qf8TVIQ/Da48WmqjZ3i7E= github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= +github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= +github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= +github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= +github.com/jmoiron/sqlx v1.3.1 h1:aLN7YINNZ7cYOPK3QC83dbM6KT0NMqVMw961TqrejlE= +github.com/jmoiron/sqlx v1.3.1/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXLBMCQ= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik= +github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= -github.com/jmoiron/sqlx v1.3.1/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXLBMCQ= +github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= 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/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= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -669,13 +894,21 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a h1:FaWFmfWdAUKbSCtOU2QjDaorUexogfaMgbipgYATUMU= github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a/go.mod h1:UJSiEoRfvx3hP73CvoARgeLjaIOjybY9vj8PUPPFGeU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 h1:uC1QfSlInpQF+M0ao65imhwqKnz3Q2z/d8PWZRMQvDM= github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= +github.com/kataras/golog v0.0.10 h1:vRDRUmwacco/pmBAm8geLn8rHEdc+9Z4NAr5Sh7TG/4= github.com/kataras/golog v0.0.10/go.mod h1:yJ8YKCmyL+nWjERB90Qwn+bdyBZsaQwU3bTVFgkFIp8= +github.com/kataras/iris/v12 v12.1.8 h1:O3gJasjm7ZxpxwTH8tApZsvf274scSGQAUpNe47c37U= github.com/kataras/iris/v12 v12.1.8/go.mod h1:LMYy4VlP67TQ3Zgriz8RE2h2kMZV2SgMYbq3UhfoFmE= +github.com/kataras/neffos v0.0.14 h1:pdJaTvUG3NQfeMbbVCI8JT2T5goPldyyfUB2PJfh1Bs= github.com/kataras/neffos v0.0.14/go.mod h1:8lqADm8PnbeFfL7CLXh1WHw53dG27MC3pgi2R1rmoTE= +github.com/kataras/pio v0.0.2 h1:6NAi+uPJ/Zuid6mrAKlgpbI11/zK/lV4B2rxWaJN98Y= github.com/kataras/pio v0.0.2/go.mod h1:hAoW0t9UmXi4R5Oyq5Z4irTbaTsOemSrDGUtaTl7Dro= +github.com/kataras/sitemap v0.0.5 h1:4HCONX5RLgVy6G4RkYOV3vKNcma9p236LdGOipJsaFE= github.com/kataras/sitemap v0.0.5/go.mod h1:KY2eugMKiPwsJgx7+U103YZehfvNGOXURubcGyk0Bz8= +github.com/kataras/tablewriter v0.0.0-20180708051242-e063d29b7c23 h1:M8exrBzuhWcU6aoHJlHWPe4qFjVKzkMGRal78f5jRRU= github.com/kataras/tablewriter v0.0.0-20180708051242-e063d29b7c23/go.mod h1:kBSna6b0/RzsOcOZf515vAXwSsXYusl2U7SA0XP09yI= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= @@ -689,9 +922,12 @@ github.com/kevinburke/twilio-go v0.0.0-20210327194925-1623146bcf73 h1:PSsFm2SRpq github.com/kevinburke/twilio-go v0.0.0-20210327194925-1623146bcf73/go.mod h1:Fm9alkN1/LPVY1eqD/psyMwPWE4VWl4P01/nTYZKzBk= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/errcheck v1.5.0 h1:e8esj/e4R+SAOwFwN+n3zr0nYeCyeweozKfO23MvHzY= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.9.7 h1:hYW1gP94JUmAhBtJ+LNz5My+gBobDxPR1iVuKug26aA= github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= @@ -699,10 +935,14 @@ github.com/klauspost/cpuid v1.3.1 h1:5JNjFYYQrZeKRJ0734q51WCEEn2huer72Dc7K+R/b6s github.com/klauspost/cpuid v1.3.1/go.mod h1:bYW4mA6ZgKPob1/Dlai2LviZJO7KGI3uoWLd42rAQw4= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= @@ -714,9 +954,13 @@ github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/labstack/echo/v4 v4.1.11 h1:z0BZoArY4FqdpUEl+wlHp4hnr/oSR6MTmQmv8OHSoww= github.com/labstack/echo/v4 v4.1.11/go.mod h1:i541M3Fj6f76NZtHSj7TXnyM8n2gaodfvfxNnFqi74g= +github.com/labstack/gommon v0.3.0 h1:JEeO0bvc78PKdyHxloTKiF8BD5iGrH8T6MSeGvSgob0= github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k= +github.com/landoop/tableprinter v0.0.0-20200805134727-ea32388e35c1 h1:xUwSaTDYl+Ib5OoFxWJnqYFG9N31++qfeNXzTZ1cc8o= github.com/landoop/tableprinter v0.0.0-20200805134727-ea32388e35c1/go.mod h1:f0X1c0za3TbET/rl5ThtCSel0+G3/yZ8iuU9BxnyVK0= +github.com/leodido/go-urn v1.1.0 h1:Sm1gr51B1kKyfD2BlRcLSiEkffoG96g6TPv6eRoEiB8= github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw= github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o= github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk= @@ -728,9 +972,13 @@ github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8= +github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= github.com/lib/pq v1.10.3 h1:v9QZf2Sn6AmjXtQeFpdoq/eaNtYP6IN+7lcrygsIAtg= github.com/lib/pq v1.10.3/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= +github.com/lithammer/dedent v1.1.0 h1:VNzHMVCBNG1j0fh3OrsFRkVUwStdDArbgBWoPAffktY= github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc= github.com/lucasb-eyer/go-colorful v1.0.2/go.mod h1:0MS4r+7BZKSJ5mw4/S5MPN+qHFF1fYclkSPilDOKW0s= github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= @@ -738,9 +986,11 @@ github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69 github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/lunixbochs/vtclean v0.0.0-20180621232353-2d01aacdc34a h1:weJVJJRzAJBFRlAiJQROKQs8oC9vOxvm4rZmBBk0ONw= github.com/lunixbochs/vtclean v0.0.0-20180621232353-2d01aacdc34a/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= +github.com/lyft/protoc-gen-star v0.5.1 h1:sImehRT+p7lW9n6R7MQc5hVgzWGEkDVZU4AsBQ4Isu8= github.com/lyft/protoc-gen-star v0.5.1/go.mod h1:9toiA3cC7z5uVbODF7kEQ91Xn7XNFkVUl+SrEe+ZORU= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -748,9 +998,11 @@ github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/manifoldco/promptui v0.8.0 h1:R95mMF+McvXZQ7j1g8ucVZE1gLP3Sv6j9vlF9kyRqQo= github.com/manifoldco/promptui v0.8.0/go.mod h1:n4zTdgP0vr0S3w7/O/g98U+e0gwLScEXGwov2nIKuGQ= +github.com/markbates/pkger v0.17.1 h1:/MKEtWqtc0mZvu9OinB9UzVN9iYCwLWuyUv4Bw+PCno= github.com/markbates/pkger v0.17.1/go.mod h1:0JoVlrol20BSywW79rN3kdFFsE5xYM+rSCQDXbLhiuI= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= @@ -770,19 +1022,24 @@ github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHX github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U= github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mattn/goveralls v0.0.2 h1:7eJB6EqsPhRVxvwEXGnqdO2sJI0PTsrWoTMXEk9/OQc= github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/mediocregopher/radix/v3 v3.4.2 h1:galbPBjIwmyREgwGCfQEN4X8lxbJnKBYurgz+VfcStA= github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= +github.com/microcosm-cc/bluemonday v1.0.2 h1:5lPfLTTAvAbtS0VqT+94yOtFnGfUWYyx0+iToC3Os3s= github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= +github.com/miekg/dns v1.0.14 h1:9jZdLNd/P4+SfEJ0TNyxYpsK8N4GtfylBLqtbYN1sbA= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/minio/md5-simd v1.1.0 h1:QPfiOqlZH+Cj9teu0t9b1nTBfPbyTl16Of5MeuShdK4= github.com/minio/md5-simd v1.1.0/go.mod h1:XpBqgZULrMYD3R+M28PcmP0CkI7PEMzB3U77ZrKZ0Gw= @@ -790,15 +1047,20 @@ github.com/minio/minio-go/v7 v7.0.14 h1:T7cw8P586gVwEEd0y21kTYtloD576XZgP62N8pE1 github.com/minio/minio-go/v7 v7.0.14/go.mod h1:S23iSP5/gbMwtxeY5FM71R+TkAYyzEdoNEDDwpt8yWs= github.com/minio/sha256-simd v0.1.1 h1:5QHSlgo3nt5yKOJrC7W8w7X+NFl8cMPZm96iu8kKUJU= github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/mitchellh/cli v1.0.0 h1:iGBIsUe3+HZ/AD/Vd7DErOt5sU9fa8Uj7A2s1aggv1Y= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/gox v0.4.0 h1:lfGJxY7ToLJQjHHwi0EX6uYBdK78egf954SQl13PQJc= github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0 h1:C+X3KsSTLFVBr/tK1eYN/vs4rJcvsiLU338UhYPJWeY= github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= @@ -809,6 +1071,7 @@ github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc= +github.com/moby/term v0.0.0-20210610120745-9d4ed1856297 h1:yH0SvLzcbZxcJXho2yh7CqdENGMQe73Cw3woZBpPli0= github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7IDy8SXRufE172gr8+K/JE/7hHFxHW3A= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= @@ -816,7 +1079,9 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0= github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= +github.com/moul/http2curl v1.0.0 h1:dRMWoAtb+ePxMlLkrCbAqh4TlPHXvoGUSQ323/9Zahs= github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= github.com/muesli/clusters v0.0.0-20180605185049-a07a36e67d36/go.mod h1:mw5KDqUj0eLj/6DUNINLVJNoPTFkEuGMHtJsXLviLkY= github.com/muesli/clusters v0.0.0-20200529215643-2700303c1762 h1:p4A2Jx7Lm3NV98VRMKlyWd3nqf8obft8NfXlAUmqd3I= @@ -826,13 +1091,20 @@ github.com/muesli/gamut v0.2.0/go.mod h1:kz1+UJqI1thNtocJlowyqG2o0FNsN0W534VoMVs github.com/muesli/kmeans v0.2.1 h1:ja5AnwfyDCVBCANrAfXr2pOh292FQnSeu1lySACDJU0= github.com/muesli/kmeans v0.2.1/go.mod h1:eNyybq0tX9/iBEP6EMU4Y7dpmGK0uEhODdZpnG1a/iQ= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/nats-io/jwt v0.3.0 h1:xdnzwFETV++jNc4W1mw//qFyJGb2ABOombmZJQS4+Qo= github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= +github.com/nats-io/nats.go v1.9.1 h1:ik3HbLhZ0YABLto7iX80pZLPw/6dx3T+++MZJwLnMrQ= github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= +github.com/nats-io/nkeys v0.1.0 h1:qMd4+pRHgdr1nAClu+2h/2a5F2TmKcCzjCDazVgRoX4= github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/nicksnyder/go-i18n/v2 v2.1.2 h1:QHYxcUJnGHBaq7XbvgunmZ2Pn0focXFqTD61CkH146c= github.com/nicksnyder/go-i18n/v2 v2.1.2/go.mod h1:d++QJC9ZVf7pa48qrsRWhMJ5pSHIPmS3OLqK1niyLxs= @@ -840,8 +1112,10 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLA github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8= github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= @@ -857,14 +1131,20 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.14.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/onsi/gomega v1.15.0 h1:WjP/FQ/sk43MRmnEcT+MlDw2TFvkrXlprrPST/IudjU= github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsqf19k25Ur8rU= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c h1:Lgl0gzECD8GnQ5QCWA8o6BtfL6mDH5rQgM4/fX3avOs= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ= github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= @@ -874,10 +1154,13 @@ github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.10.1 h1:VasscCm72135zRysgrJDKsntdmPN+OuU3+nnHYA9wyc= github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1 h1:ccV59UEOTzVDnDUEFdT95ZzHVZ+5+158q8+SJb2QV5w= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021 h1:0XM1XL/OFFJjXsYXlG30spTkV/E9+gmd5GD1w2HE8xM= github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= github.com/pquerna/otp v1.3.0 h1:oJV/SkzR33anKXwQU3Of42rL4wbrffP4uvUf1SvS5Xs= github.com/pquerna/otp v1.3.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= @@ -905,32 +1188,43 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/tsdb v0.7.1 h1:YZcsG11NqnK4czYLrWd9mpEuAJIHVQLwdrleYfszMAA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rakyll/statik v0.1.7 h1:OF3QCZUuyPxuGEP7B4ypUa7sB/iHtqOTDYZXGM8KOdQ= github.com/rakyll/statik v0.1.7/go.mod h1:AlZONWzMtEnMs7W4e/1LURLiI49pIMmp6V9Unghqrcc= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/fastuuid v1.2.0 h1:Ppwyp6VYCF1nvBTXL3trRso7mXMlRrw9ooo375wvi2s= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.3.0 h1:RR9dF3JtopPvtkroDZuVD7qquD0bnHlKSqaQhgwt8yk= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rs/cors v1.8.0 h1:P2KMzcFwrPoSjkF1WLRPsp3UMLyql8L4v9hQpVeK5so= github.com/rs/cors v1.8.0/go.mod h1:EBwu+T5AvHOcXwvZIkQFjUN6s8Czyqw12GL/Y0tUyRM= github.com/rs/xid v1.2.1 h1:mhH9Nq+C1fY2l1XIpgxIiUOfNpRBYH1kKcr+qfKgjRc= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= +github.com/rs/zerolog v1.15.0 h1:uPRuwkWF4J6fGsJ2R0Gn2jB1EQiav9k3S6CSdygQJXY= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= +github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryanuber/columnize v2.1.0+incompatible h1:j1Wcmh8OrK4Q7GXY+V7SVSY8nUWQxHW5TkBe7YUl+2s= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/schollz/closestmatch v2.1.0+incompatible h1:Uel2GXEpJqOWBrlyI+oY9LTiyyjYS17cCYRqP13/SHk= github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= @@ -944,16 +1238,20 @@ github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1 github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= github.com/sony/sonyflake v1.0.0 h1:MpU6Ro7tfXwgn2l5eluf9xQvQJDROTBImNCfRXn/YeM= github.com/sony/sonyflake v1.0.0/go.mod h1:Jv3cfhf/UFtolOTTRd3q4Nl6ENqM+KfyZ5PseKfZGF4= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= github.com/spf13/afero v1.3.4/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= +github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= @@ -963,6 +1261,7 @@ github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSW github.com/spf13/cobra v1.2.1 h1:+KmjbUw1hriSNMF55oPrkZcb27aECyrj8V2ytv7kWDw= github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= @@ -972,10 +1271,13 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/spf13/viper v1.8.1 h1:Kq1fyeebqsBfbjZj4EL7gj2IO0mMaiyjYUWcUsl2O44= github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= +github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= @@ -985,27 +1287,40 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= 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 h1:uruHq4dN7GR16kFc5fp3d1RIYzJW5onx8Ybykw2YQFA= github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ttacon/builder v0.0.0-20170518171403-c099f663e1c2 h1:5u+EJUQiosu3JFX0XS0qTf5FznsMOzTjGqavBGuCbo0= github.com/ttacon/builder v0.0.0-20170518171403-c099f663e1c2/go.mod h1:4kyMkleCiLkgY6z8gK5BkI01ChBtxR0ro3I1ZDcGM3w= github.com/ttacon/libphonenumber v1.2.1 h1:fzOfY5zUADkCkbIafAed11gL1sW+bJ26p6zWLBMElR4= github.com/ttacon/libphonenumber v1.2.1/go.mod h1:E0TpmdVMq5dyVlQ7oenAkhsLu86OkUl+yR4OAxyEg/M= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.4 h1:u7tSpNPPswAFymm8IehJhy4uJMlUuU/GmqSkvJ1InXA= github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli/v2 v2.1.1 h1:Qt8FeAtxE/vfdrLmR3rxR6JRE0RoVmbXu8+6kZtYU4k= github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= +github.com/urfave/negroni v1.0.0 h1:kIimOitoypq34K7TG7DUaJ9kq/N4Ofuwi1sjz0KipXc= github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.6.0 h1:uWF8lgKmeaIewWVPwi4GRq2P6+R46IgYZdxWtM+GtEY= github.com/valyala/fasthttp v1.6.0/go.mod h1:FstJa9V+Pj9vQ7OJie2qMHdwemEDaDiSdBnvPM1Su9w= +github.com/valyala/fasttemplate v1.0.1 h1:tY9CJiPnMXf1ERmG2EyK7gNUd+c6RKGD0IfU8WdUSz8= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= +github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a h1:0R4NLDRDZX6JcmhJgXi5E4b8Wg84ihbmUKp/GvSPEzc= github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= +github.com/vektah/gqlparser v1.1.2 h1:ZsyLGn7/7jDNI+y4SEhI4yAxRChlv15pUHMjijT+e68= github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= github.com/wcharczuk/go-chart/v2 v2.1.0 h1:tY2slqVQ6bN+yHSnDYwZebLQFkphK4WNrVwnt7CJZ2I= github.com/wcharczuk/go-chart/v2 v2.1.0/go.mod h1:yx7MvAVNcP/kN9lKXM/NTce4au4DFN99j6i1OwDclNA= @@ -1013,40 +1328,62 @@ github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70= github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca h1:1CFlNzQhALwjS9mBAUkycX616GzgsuYUOCHA5+HSlXI= github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77 h1:ESFSdwYZvkeru3RtdrYueztKhOBCSAAzS4Gf+k0tEow= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/xrash/smetrics v0.0.0-20200730060457-89a2a8a1fb0b h1:tnWgqoOBmInkt5pbLjagwNVjjT4RdJhFHzL1ebCSRh8= github.com/xrash/smetrics v0.0.0-20200730060457-89a2a8a1fb0b/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= +github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 h1:6fRhSjgLCkTD3JnJxvaJ4Sj+TYblw757bqYgZaOq5ZY= github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= +github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA= github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= +github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M= github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= +github.com/yudai/pp v2.0.1+incompatible h1:Q4//iY4pNF6yPLZIigmvcl7k/bPgrcTPIFIcmawg5bI= github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5 h1:dPmz1Snjq0kmkz159iL7S6WzdahUTHnHB5M56WFVifs= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/zenazn/goji v0.9.0 h1:RSQQAbXGArQ0dIDEq+PI6WqN6if+5KHu6x2Cx/GXLTQ= github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= +go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489 h1:1JFLBqwIgdyHN1ZtgjTBwO+blA6gVOmZurpiMEsETKo= go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg= +go.etcd.io/etcd/api/v3 v3.5.0 h1:GsV3S+OfZEOCNXdtNkBSR7kgLobAa/SO6tCxRa0GAYw= go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/client/pkg/v3 v3.5.0 h1:2aQv6F436YnN7I4VbI8PPYrBhu+SmrTaADcf8Mi/6PU= go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/v2 v2.305.0 h1:ftQ0nOOHMcbMS3KIaDQ0g5Qcd6bhaBrQT6b89DfwLTs= go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= +go.etcd.io/etcd/client/v3 v3.5.0 h1:62Eh0XOro+rDwkrypAGDfgmNh5Joq+z+W9HZdlXMzek= go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0= +go.etcd.io/etcd/pkg/v3 v3.5.0 h1:ntrg6vvKRW26JRmHTE0iNlDgYK6JX3hg/4cD62X0ixk= go.etcd.io/etcd/pkg/v3 v3.5.0/go.mod h1:UzJGatBQ1lXChBkQF0AuAtkRQMYnHubxAEYIrC3MSsE= +go.etcd.io/etcd/raft/v3 v3.5.0 h1:kw2TmO3yFTgE+F0mdKkG7xMxkit2duBDa2Hu6D/HMlw= go.etcd.io/etcd/raft/v3 v3.5.0/go.mod h1:UFOHSIvO/nKwd4lhkwabrTD3cqW5yVyYYf/KlD00Szc= +go.etcd.io/etcd/server/v3 v3.5.0 h1:jk8D/lwGEDlQU9kZXUFMSANkE22Sg5+mW27ip8xcF9E= go.etcd.io/etcd/server/v3 v3.5.0/go.mod h1:3Ah5ruV+M+7RZr0+Y/5mNLwC+eQlni+mQmOVdCRJoS4= go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= +go.mongodb.org/mongo-driver v1.1.2 h1:jxcFYjlkl8xaERsgLo+RNquI0epW6zuy/ZRQs6jnrFA= go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= @@ -1112,6 +1449,7 @@ go.opentelemetry.io/otel/trace v1.0.0/go.mod h1:PXTWqayeFUlJV1YDNhsJYB184+IvAH81 go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v0.9.0 h1:C0g6TWmQYvjKRnljRULLWUVJGy8Uvu0NEL/5frY2/t4= go.opentelemetry.io/proto/otlp v0.9.0/go.mod h1:1vKfU9rv61e9EVGthD1zNvUbiwPcimSsOPU9brfSHJg= +go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 h1:+FNtrFTmVw0YZGpBGX56XDee331t6JAXeK2bcyhLOOc= go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= @@ -1124,6 +1462,7 @@ go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/ go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= @@ -1170,6 +1509,7 @@ golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6 h1:QE6XYQK6naiK1EPAe1g/ILLxN5RBoH5xkJk3CqlMI/Y= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= 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= @@ -1189,6 +1529,7 @@ golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPI golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028 h1:4+4C/Iv2U4fMZBiMCc98MG1In4gJY5YRhtpDNeDeHWs= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= @@ -1618,6 +1959,7 @@ google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQ google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0 h1:M1YKkFIboKNieVO5DLUEVzQfGwJD30Nv2jfUgzb5UcE= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.41.0 h1:f+PlOh7QV4iIJkPrx5NQ7qaNGFQ3OTse67yaDHfju4E= google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k= @@ -1636,6 +1978,7 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -1644,12 +1987,19 @@ gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/cheggaaa/pb.v1 v1.0.25 h1:Ev7yu1/f6+d+b3pi5vPdRPc6nNtP1umSfcWiEfRqv6I= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/errgo.v2 v2.1.0 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= +gopkg.in/go-playground/validator.v8 v8.18.2 h1:lFB4DoMU6B626w8ny76MV7VX6W2VHct2GVOI3xgiMrQ= gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= +gopkg.in/go-playground/validator.v9 v9.29.1 h1:SvGtYmN60a5CVKTOzMSyfzWDeZRxRuGvRQyEAKbw1xc= gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= +gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec h1:RlWgLqCMMIYYEVcAR5MDsuHlVkaIPDAF+5Dehzg8L5A= gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= @@ -1658,8 +2008,11 @@ gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU= gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce h1:xcEWjVhvbDy+nHP67nPDDpbYrY+ILlfndk4bRioVHaU= gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= +gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/resty.v1 v1.12.0 h1:CuXP0Pjfw9rOuY6EP+UvtNvt5DSqHpIxILZKT/quCZI= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= @@ -1685,12 +2038,15 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/driver/postgres v1.0.8 h1:PAgM+PaHOSAeroTjHkCHCBIHHoBIf9RgPWGo8dF2DA8= gorm.io/driver/postgres v1.0.8/go.mod h1:4eOzrI1MUfm6ObJU/UcmbXyiHSs8jSwH95G5P5dxcAg= gorm.io/gorm v1.20.12/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= +gorm.io/gorm v1.21.4 h1:J0xfPJMRfHgpVcYLrEAIqY/apdvTIkrltPQNHQLq9Qc= gorm.io/gorm v1.21.4/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= +gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -1698,6 +2054,7 @@ honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4 h1:UoveltGrhghAA7ePc+e+QYDHXrBps2PqFZiHkGR/xK8= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= k8s.io/api v0.18.2/go.mod h1:SJCWI7OLzhZSvbY7U8zwNl9UA4o1fizoug34OV/2r78= k8s.io/api v0.21.3/go.mod h1:hUgeYHUbBp23Ue4qdX9tR8/ANi/g3ehylAqDn9NWVOg= @@ -1713,6 +2070,9 @@ k8s.io/apimachinery v0.22.2 h1:ejz6y/zNma8clPVfNDLnPbleBo6MpoFy/HBiBqCouVk= k8s.io/apimachinery v0.22.2/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0= k8s.io/apiserver v0.18.2/go.mod h1:Xbh066NqrZO8cbsoenCwyDJ1OSi8Ag8I2lezeHxzwzw= k8s.io/apiserver v0.21.3/go.mod h1:eDPWlZG6/cCCMj/JBcEpDoK+I+6i3r9GsChYBHSbAzU= +k8s.io/apiserver v0.22.0 h1:KZh2asnRBjawLLfPOi6qiD+A2jaNt31HCnZG6AX3Qcs= +k8s.io/apiserver v0.22.0/go.mod h1:04kaIEzIQrTGJ5syLppQWvpkLJXQtJECHmae+ZGc/nc= +k8s.io/cli-runtime v0.21.3 h1:eXevRomULAAGjQ7m6qo+AWHvtVRqaLG8WQICEBwjtmo= k8s.io/apiserver v0.22.2/go.mod h1:vrpMmbyjWrgdyOvZTSpsusQq5iigKNWv9o9KlDAbBHI= k8s.io/cli-runtime v0.21.3/go.mod h1:h65y0uXIXDnNjd5J+F3CvQU3ZNplH4+rjqbII7JkD4A= k8s.io/client-go v0.18.2/go.mod h1:Xcm5wVGXX9HAA2JJ2sSBUn3tCJ+4SVlCbl2MNNv+CIU= @@ -1721,15 +2081,21 @@ k8s.io/client-go v0.22.2 h1:DaSQgs02aCC1QcwUdkKZWOeaVsQjYvWv8ZazcZ6JcHc= k8s.io/client-go v0.22.2/go.mod h1:sAlhrkVDf50ZHx6z4K0S40wISNTarf1r800F+RlCF6U= k8s.io/code-generator v0.18.2/go.mod h1:+UHX5rSbxmR8kzS+FAv7um6dtYrZokQvjHpDSYRVkTc= k8s.io/code-generator v0.21.3/go.mod h1:K3y0Bv9Cz2cOW2vXUrNZlFbflhuPvuadW6JdnN6gGKo= +k8s.io/code-generator v0.22.0 h1:wIo+6NuAEf+aP6dblF+fPJOkY/VnM6wqNHusiW/eQ3o= +k8s.io/code-generator v0.22.0/go.mod h1:eV77Y09IopzeXOJzndrDyCI88UBok2h6WxAlBwpxa+o= k8s.io/code-generator v0.22.2/go.mod h1:eV77Y09IopzeXOJzndrDyCI88UBok2h6WxAlBwpxa+o= k8s.io/component-base v0.18.2/go.mod h1:kqLlMuhJNHQ9lz8Z7V5bxUUtjFZnrypArGl58gmDfUM= k8s.io/component-base v0.21.3/go.mod h1:kkuhtfEHeZM6LkX0saqSK8PbdO7A0HigUngmhhrwfGQ= +k8s.io/component-base v0.22.0 h1:ZTmX8hUqH9T9gc0mM42O+KDgtwTYbVTt2MwmLP0eK8A= +k8s.io/component-base v0.22.0/go.mod h1:SXj6Z+V6P6GsBhHZVbWCw9hFjUdUYnJerlhhPnYCBCg= +k8s.io/component-helpers v0.21.3 h1:aOqcg7p/MLOAVBKKokFTOEn9Iy2BjTaZLRY0JdenN/I= k8s.io/component-base v0.22.2 h1:vNIvE0AIrLhjX8drH0BgCNJcR4QZxMXcJzBsDplDx9M= k8s.io/component-base v0.22.2/go.mod h1:5Br2QhI9OTe79p+TzPe9JKNQYvEKbq9rTJDWllunGug= k8s.io/component-helpers v0.21.3/go.mod h1:FJCpEhM9fkKvNN0QAl33ozmMj+Bx8R64wcOBqhng0oQ= k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20200114144118-36b2048a9120/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20201214224949-b6c5ce23f027 h1:Uusb3oh8XcdzDF/ndlI4ToKTYVlkCSJP39SRY2mfRAw= k8s.io/gengo v0.0.0-20201214224949-b6c5ce23f027/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= @@ -1744,29 +2110,40 @@ k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c/go.mod h1:GRQhZsXIAJ1xR0C k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7/go.mod h1:wXW5VT87nVfh/iLV8FpR2uDvrFyomxbtb1KivDbvPTE= k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e h1:KLHHjkdQFomZy8+06csTWZ0m1343QqxZhR2LJ1OxCYM= k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= +k8s.io/kubectl v0.21.3 h1:RmHvvz7tLnFmVqUzJuR44D8oE5zv1iyDojxSQllY+II= k8s.io/kubectl v0.21.3/go.mod h1:/x/kzrhfL1h1W07z6a1UTbd8SWZUYAWXskigkG4OBCg= +k8s.io/metrics v0.21.3 h1:BXLcDFR/2XUNOcFDyNI6//9pK+WIDCbQ0+uEkIjcHEc= k8s.io/metrics v0.21.3/go.mod h1:mN3Klf203Lw1hOsfg1MG7DR/kKUhwiyu8GSFCXZdz+o= k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20210722164352-7f3ee0f31471/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +rsc.io/binaryregexp v0.2.0 h1:HfqmD5MEmC0zvwBuF187nq9mdnXjXsSivRiXN7SmRkE= k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a h1:8dYfu/Fc9Gz2rNJKB9IQRGgQOh2clmRzNIPPY1xLY5g= k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0 h1:9JKUTTIUgS6kzR9mK1YuGKv6Nl+DijDNIc0ghT58FaY= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0 h1:7uVkIFmeBqHfdjD+gZwtXXI+RODJ2Wc4O7MPEh/QiW4= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.7/go.mod h1:PHgbrJT7lCHcxMU+mDHEm+nx46H4zuuHZkDP6icnhu0= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.19/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.22 h1:fmRfl9WJ4ApJn7LxNuED4m0t18qivVQOxP6aAYG9J6c= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.22/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= sigs.k8s.io/controller-runtime v0.9.5/go.mod h1:q6PpkM5vqQubEKUKOM6qr06oXGzOBcCby1DA9FbyZeA= sigs.k8s.io/controller-runtime v0.10.1 h1:+eLHgY/VrJWnfg6iXUqhCUqNXgPH1NZeP9drNAAgWlg= sigs.k8s.io/controller-runtime v0.10.1/go.mod h1:CQp8eyUQZ/Q7PJvnIrB6/hgfTC1kBkGylwsLgOQi1WY= sigs.k8s.io/controller-tools v0.4.1 h1:VkuV0MxlRPmRu5iTgBZU4UxUX2LiR99n3sdQGRxZF4w= sigs.k8s.io/controller-tools v0.4.1/go.mod h1:G9rHdZMVlBDocIxGkK3jHLWqcTMNvveypYJwrvYKjWU= +sigs.k8s.io/kustomize/api v0.8.8 h1:G2z6JPSSjtWWgMeWSoHdXqyftJNmMmyxXpwENGoOtGE= sigs.k8s.io/kustomize/api v0.8.8/go.mod h1:He1zoK0nk43Pc6NlV085xDXDXTNprtcyKZVm3swsdNY= +sigs.k8s.io/kustomize/cmd/config v0.9.10 h1:oA6APIzAg5CnpqOyf6Cnghu7byicnbmWIBgd19VZSZQ= sigs.k8s.io/kustomize/cmd/config v0.9.10/go.mod h1:Mrby0WnRH7hA6OwOYnYpfpiY0WJIMgYrEDfwOeFdMK0= +sigs.k8s.io/kustomize/kustomize/v4 v4.1.2 h1:iP3ckqMIftwsIKnMqtztReSkkPJvhqNc5QiOpMoFpbY= sigs.k8s.io/kustomize/kustomize/v4 v4.1.2/go.mod h1:PxBvo4WGYlCLeRPL+ziT64wBXqbgfcalOS/SXa/tcyo= +sigs.k8s.io/kustomize/kyaml v0.10.17 h1:4zrV0ym5AYa0e512q7K3Wp1u7mzoWW0xR3UHJcGWGIg= sigs.k8s.io/kustomize/kyaml v0.10.17/go.mod h1:mlQFagmkm1P+W4lZJbJ/yaxMd8PqMRSC4cPcfUVt5Hg= sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= +sigs.k8s.io/structured-merge-diff/v3 v3.0.0 h1:dOmIZBMfhcHS09XZkMyUgkq5trg3/jRyJYFZUiaOp8E= sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.1.2 h1:Hr/htKFmJEbtMgS/UD0N+gtgctAqz81t3nu+sPzynno= diff --git a/internal/command/setup_step4.go b/internal/command/setup_step4.go index 143420446..31a2a5700 100644 --- a/internal/command/setup_step4.go +++ b/internal/command/setup_step4.go @@ -19,6 +19,7 @@ func (s *Step4) Step() domain.Step { func (s *Step4) execute(ctx context.Context, commandSide *Commands) error { return commandSide.SetupStep4(ctx, s) } + //This step should not be executed when a new instance is setup, because its not used anymore //SetupStep4 is no op in favour of step 18. //Password lockout policy is replaced by lockout policy diff --git a/operator/crtlcrd/backup.go b/operator/crtlcrd/backup.go index b8d2854d5..6976f8838 100644 --- a/operator/crtlcrd/backup.go +++ b/operator/crtlcrd/backup.go @@ -3,28 +3,23 @@ package crtlcrd import ( "github.com/caos/orbos/mntr" "github.com/caos/orbos/pkg/kubernetes" - "github.com/caos/orbos/pkg/tree" - "github.com/caos/zitadel/operator/api/database" - orbdb "github.com/caos/zitadel/operator/database/kinds/orb" + "github.com/caos/zitadel/pkg/databases" ) -func Restore(monitor mntr.Monitor, k8sClient *kubernetes.Client, backup string, binaryVersion *string) error { - desired, err := database.ReadCrd(k8sClient) - if err != nil { +func Restore( + monitor mntr.Monitor, + k8sClient *kubernetes.Client, + backup string, +) error { + if err := databases.CrdClear(monitor, k8sClient); err != nil { return err } - query, _, _, _, _, _, err := orbdb.AdaptFunc(backup, binaryVersion, false, "restore")(monitor, desired, &tree.Tree{}) - if err != nil { - return err - } - - ensure, err := query(k8sClient, map[string]interface{}{}) - if err != nil { - return err - } - - if err := ensure(k8sClient); err != nil { + if err := databases.CrdRestore( + monitor, + k8sClient, + backup, + ); err != nil { return err } diff --git a/operator/crtlcrd/zitadel/scale.go b/operator/crtlcrd/zitadel/scale.go new file mode 100644 index 000000000..8487cb72c --- /dev/null +++ b/operator/crtlcrd/zitadel/scale.go @@ -0,0 +1,32 @@ +package zitadel + +import ( + "github.com/caos/orbos/mntr" + "github.com/caos/orbos/pkg/kubernetes" + "github.com/caos/zitadel/operator/zitadel/kinds/orb" + macherrs "k8s.io/apimachinery/pkg/api/errors" +) + +func ScaleDown( + monitor mntr.Monitor, + k8sClient *kubernetes.Client, + version *string, +) (bool, error) { + noZitadel := false + if err := Takeoff(monitor, k8sClient, orb.AdaptFunc(nil, "scaledown", version, false, []string{"scaledown"})); err != nil { + if macherrs.IsNotFound(err) { + noZitadel = true + } else { + return noZitadel, err + } + } + return noZitadel, nil +} + +func ScaleUp( + monitor mntr.Monitor, + k8sClient *kubernetes.Client, + version *string, +) error { + return Takeoff(monitor, k8sClient, orb.AdaptFunc(nil, "scaleup", version, false, []string{"scaleup"})) +} diff --git a/operator/crtlcrd/zitadel/zitadel.go b/operator/crtlcrd/zitadel/zitadel.go index ef8e6d662..4bb196d07 100644 --- a/operator/crtlcrd/zitadel/zitadel.go +++ b/operator/crtlcrd/zitadel/zitadel.go @@ -3,6 +3,7 @@ package zitadel import ( "context" "fmt" + "github.com/caos/zitadel/operator" "github.com/caos/orbos/mntr" "github.com/caos/orbos/pkg/kubernetes" @@ -35,31 +36,40 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (res ctrl. return res, fmt.Errorf("resource must be named %s and namespaced in %s", zitadel.Name, zitadel.Namespace) } - desired, err := zitadel.ReadCrd(r.ClientInt) - if err != nil { - return res, err - } - - query, _, _, _, _, _, err := orbz.AdaptFunc(nil, "ensure", &r.Version, false, []string{"operator", "iam"})(internalMonitor, desired, &tree.Tree{}) - if err != nil { - internalMonitor.Error(err) - return res, err - } - - ensure, err := query(r.ClientInt, map[string]interface{}{}) - if err != nil { - internalMonitor.Error(err) - return res, err - } - - if err := ensure(r.ClientInt); err != nil { - internalMonitor.Error(err) + if err := Takeoff(internalMonitor, r.ClientInt, orbz.AdaptFunc(nil, "ensure", &r.Version, false, []string{"operator", "iam"})); err != nil { return res, err } return res, nil } +func Takeoff( + monitor mntr.Monitor, + k8sClient kubernetes.ClientInt, + adaptFunc operator.AdaptFunc, +) error { + desired, err := zitadel.ReadCrd(k8sClient) + if err != nil { + return err + } + + query, _, _, _, _, _, err := adaptFunc(monitor, desired, &tree.Tree{}) + if err != nil { + return err + } + + ensure, err := query(k8sClient, map[string]interface{}{}) + if err != nil { + return err + } + + if err := ensure(k8sClient); err != nil { + return err + } + + return nil +} + func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). For(&v1.Zitadel{}). diff --git a/operator/crtlgitops/backup.go b/operator/crtlgitops/backup.go new file mode 100644 index 000000000..34755b795 --- /dev/null +++ b/operator/crtlgitops/backup.go @@ -0,0 +1,29 @@ +package crtlgitops + +import ( + "github.com/caos/orbos/mntr" + "github.com/caos/orbos/pkg/git" + "github.com/caos/orbos/pkg/kubernetes" + "github.com/caos/zitadel/pkg/databases" +) + +func Restore( + monitor mntr.Monitor, + gitClient *git.Client, + k8sClient *kubernetes.Client, + backup string, +) error { + if err := databases.GitOpsClear(monitor, k8sClient, gitClient); err != nil { + return err + } + + if err := databases.GitOpsRestore( + monitor, + k8sClient, + gitClient, + backup, + ); err != nil { + return err + } + return nil +} diff --git a/operator/crtlgitops/scale.go b/operator/crtlgitops/scale.go new file mode 100644 index 000000000..980edf823 --- /dev/null +++ b/operator/crtlgitops/scale.go @@ -0,0 +1,41 @@ +package crtlgitops + +import ( + "github.com/caos/orbos/mntr" + "github.com/caos/orbos/pkg/git" + "github.com/caos/orbos/pkg/kubernetes" + orbconfig "github.com/caos/orbos/pkg/orb" + "github.com/caos/zitadel/operator/zitadel" + "github.com/caos/zitadel/operator/zitadel/kinds/orb" + macherrs "k8s.io/apimachinery/pkg/api/errors" +) + +func ScaleDown( + monitor mntr.Monitor, + gitClient *git.Client, + k8sClient *kubernetes.Client, + orbCfg *orbconfig.Orb, + version *string, + gitops bool, +) (bool, error) { + noZitadel := false + if err := zitadel.Takeoff(monitor, gitClient, orb.AdaptFunc(orbCfg, "scaledown", version, gitops, []string{"scaledown"}), k8sClient)(); err != nil { + if macherrs.IsNotFound(err) { + noZitadel = true + } else { + return noZitadel, err + } + } + return noZitadel, nil +} + +func ScaleUp( + monitor mntr.Monitor, + gitClient *git.Client, + k8sClient *kubernetes.Client, + orbCfg *orbconfig.Orb, + version *string, + gitops bool, +) error { + return zitadel.Takeoff(monitor, gitClient, orb.AdaptFunc(orbCfg, "scaleup", version, gitops, []string{"scaleup"}), k8sClient)() +} diff --git a/operator/database/kinds/backups/backups.go b/operator/database/kinds/backups/backups.go index 7c3376928..65b39d059 100644 --- a/operator/database/kinds/backups/backups.go +++ b/operator/database/kinds/backups/backups.go @@ -3,8 +3,6 @@ package backups import ( "fmt" - corev1 "k8s.io/api/core/v1" - "github.com/caos/orbos/mntr" "github.com/caos/orbos/pkg/kubernetes" "github.com/caos/orbos/pkg/labels" @@ -12,6 +10,8 @@ import ( "github.com/caos/orbos/pkg/tree" "github.com/caos/zitadel/operator" "github.com/caos/zitadel/operator/database/kinds/backups/bucket" + "github.com/caos/zitadel/operator/database/kinds/backups/s3" + corev1 "k8s.io/api/core/v1" ) func Adapt( @@ -26,6 +26,8 @@ func Adapt( nodeselector map[string]string, tolerations []corev1.Toleration, version string, + dbURL string, + dbPort int32, features []string, customImageRegistry string, ) ( @@ -54,6 +56,29 @@ func Adapt( nodeselector, tolerations, version, + dbURL, + dbPort, + features, + customImageRegistry, + )(monitor, desiredTree, currentTree) + case "databases.caos.ch/S3Backup": + return s3.AdaptFunc( + name, + namespace, + labels.MustForComponent( + labels.MustReplaceAPI( + labels.GetAPIFromComponent(componentLabels), + "S3Backup", + desiredTree.Common.Version(), + ), + "backup"), + checkDBReady, + timestamp, + nodeselector, + tolerations, + version, + dbURL, + dbPort, features, customImageRegistry, )(monitor, desiredTree, currentTree) @@ -74,6 +99,8 @@ func GetBackupList( switch desiredTree.Common.Kind { case "databases.caos.ch/BucketBackup": return bucket.BackupList()(monitor, k8sClient, name, desiredTree) + case "databases.caos.ch/S3Backup": + return s3.BackupList()(monitor, k8sClient, name, desiredTree) default: return nil, mntr.ToUserError(fmt.Errorf("unknown database kind %s", desiredTree.Common.Kind)) } diff --git a/operator/database/kinds/backups/bucket/adapt.go b/operator/database/kinds/backups/bucket/adapt.go index 75a9534e4..184a8c086 100644 --- a/operator/database/kinds/backups/bucket/adapt.go +++ b/operator/database/kinds/backups/bucket/adapt.go @@ -12,12 +12,9 @@ import ( secretpkg "github.com/caos/orbos/pkg/secret" "github.com/caos/orbos/pkg/secret/read" "github.com/caos/orbos/pkg/tree" - coreDB "github.com/caos/zitadel/operator/database/kinds/databases/core" - "github.com/caos/zitadel/operator" "github.com/caos/zitadel/operator/common" "github.com/caos/zitadel/operator/database/kinds/backups/bucket/backup" - "github.com/caos/zitadel/operator/database/kinds/backups/bucket/clean" "github.com/caos/zitadel/operator/database/kinds/backups/bucket/restore" ) @@ -35,6 +32,8 @@ func AdaptFunc( nodeselector map[string]string, tolerations []corev1.Toleration, version string, + dbURL string, + dbPort int32, features []string, customImageRegistry string, ) operator.AdaptFunc { @@ -78,7 +77,6 @@ func AdaptFunc( name, namespace, componentLabels, - []string{}, checkDBReady, desiredKind.Spec.Bucket, desiredKind.Spec.Cron, @@ -87,6 +85,8 @@ func AdaptFunc( timestamp, nodeselector, tolerations, + dbURL, + dbPort, features, image, ) @@ -99,7 +99,6 @@ func AdaptFunc( name, namespace, componentLabels, - []string{}, desiredKind.Spec.Bucket, timestamp, nodeselector, @@ -107,13 +106,15 @@ func AdaptFunc( checkDBReady, secretName, secretKey, + dbURL, + dbPort, image, ) if err != nil { return nil, nil, nil, nil, nil, false, err } - _, destroyC, err := clean.AdaptFunc( + /*_, destroyC, err := clean.AdaptFunc( monitor, name, namespace, @@ -129,7 +130,7 @@ func AdaptFunc( ) if err != nil { return nil, nil, nil, nil, nil, false, err - } + }*/ destroyers := make([]operator.DestroyFunc, 0) for _, feature := range features { @@ -139,10 +140,10 @@ func AdaptFunc( operator.ResourceDestroyToZitadelDestroy(destroyS), destroyB, ) - case clean.Instant: - destroyers = append(destroyers, - destroyC, - ) + /*case clean.Instant: + destroyers = append(destroyers, + destroyC, + )*/ case restore.Instant: destroyers = append(destroyers, destroyR, @@ -156,21 +157,6 @@ func AdaptFunc( return nil, err } - currentDB, err := coreDB.ParseQueriedForDatabase(queried) - if err != nil { - return nil, err - } - - databases, err := currentDB.GetListDatabasesFunc()(k8sClient) - if err != nil { - databases = []string{} - } - - users, err := currentDB.GetListUsersFunc()(k8sClient) - if err != nil { - users = []string{} - } - value, err := read.GetSecretValue(k8sClient, desiredKind.Spec.ServiceAccountJSON, desiredKind.Spec.ExistingServiceAccountJSON) if err != nil { return nil, err @@ -186,7 +172,6 @@ func AdaptFunc( name, namespace, componentLabels, - databases, checkDBReady, desiredKind.Spec.Bucket, desiredKind.Spec.Cron, @@ -195,6 +180,8 @@ func AdaptFunc( timestamp, nodeselector, tolerations, + dbURL, + dbPort, features, image, ) @@ -207,7 +194,6 @@ func AdaptFunc( name, namespace, componentLabels, - databases, desiredKind.Spec.Bucket, timestamp, nodeselector, @@ -215,13 +201,15 @@ func AdaptFunc( checkDBReady, secretName, secretKey, + dbURL, + dbPort, image, ) if err != nil { return nil, err } - queryC, _, err := clean.AdaptFunc( + /*queryC, _, err := clean.AdaptFunc( monitor, name, namespace, @@ -237,43 +225,41 @@ func AdaptFunc( ) if err != nil { return nil, err - } + }*/ queriers := make([]operator.QueryFunc, 0) cleanupQueries := make([]operator.QueryFunc, 0) - if databases != nil && len(databases) != 0 { - for _, feature := range features { - switch feature { - case backup.Normal: - queriers = append(queriers, - operator.ResourceQueryToZitadelQuery(queryS), - queryB, - ) - case backup.Instant: - queriers = append(queriers, - operator.ResourceQueryToZitadelQuery(queryS), - queryB, - ) - cleanupQueries = append(cleanupQueries, - operator.EnsureFuncToQueryFunc(backup.GetCleanupFunc(monitor, namespace, name)), - ) - case clean.Instant: - queriers = append(queriers, - operator.ResourceQueryToZitadelQuery(queryS), - queryC, - ) - cleanupQueries = append(cleanupQueries, - operator.EnsureFuncToQueryFunc(clean.GetCleanupFunc(monitor, namespace, name)), - ) - case restore.Instant: - queriers = append(queriers, - operator.ResourceQueryToZitadelQuery(queryS), - queryR, - ) - cleanupQueries = append(cleanupQueries, - operator.EnsureFuncToQueryFunc(restore.GetCleanupFunc(monitor, namespace, name)), - ) - } + for _, feature := range features { + switch feature { + case backup.Normal: + queriers = append(queriers, + operator.ResourceQueryToZitadelQuery(queryS), + queryB, + ) + case backup.Instant: + queriers = append(queriers, + operator.ResourceQueryToZitadelQuery(queryS), + queryB, + ) + cleanupQueries = append(cleanupQueries, + operator.EnsureFuncToQueryFunc(backup.GetCleanupFunc(monitor, namespace, name)), + ) + /*case clean.Instant: + queriers = append(queriers, + operator.ResourceQueryToZitadelQuery(queryS), + queryC, + ) + cleanupQueries = append(cleanupQueries, + operator.EnsureFuncToQueryFunc(clean.GetCleanupFunc(monitor, namespace, name)), + )*/ + case restore.Instant: + queriers = append(queriers, + operator.ResourceQueryToZitadelQuery(queryS), + queryR, + ) + cleanupQueries = append(cleanupQueries, + operator.EnsureFuncToQueryFunc(restore.GetCleanupFunc(monitor, namespace, name)), + ) } } diff --git a/operator/database/kinds/backups/bucket/adapt_test.go b/operator/database/kinds/backups/bucket/adapt_test.go index f9c2fead4..c4bba30c7 100644 --- a/operator/database/kinds/backups/bucket/adapt_test.go +++ b/operator/database/kinds/backups/bucket/adapt_test.go @@ -10,7 +10,6 @@ import ( "github.com/caos/orbos/pkg/secret" "github.com/caos/orbos/pkg/tree" "github.com/caos/zitadel/operator/database/kinds/backups/bucket/backup" - "github.com/caos/zitadel/operator/database/kinds/backups/bucket/clean" "github.com/caos/zitadel/operator/database/kinds/backups/bucket/restore" "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" @@ -27,6 +26,8 @@ func TestBucket_Secrets(t *testing.T) { monitor := mntr.Monitor{} namespace := "testNs2" + dbURL := "testDB" + dbPort := int32(80) kindVersion := "v0" kind := "BucketBackup" componentLabels := labels.MustForComponent(labels.MustForAPI(labels.MustForOperator("testProd", "testOp", "testVersion"), "BucketBackup", kindVersion), "testComponent") @@ -67,6 +68,8 @@ func TestBucket_Secrets(t *testing.T) { nodeselector, tolerations, version, + dbURL, + dbPort, features, "", )( @@ -88,6 +91,8 @@ func TestBucket_AdaptBackup(t *testing.T) { features := []string{backup.Normal} saJson := "testSA" + dbURL := "testDB" + dbPort := int32(80) bucketName := "testBucket2" cron := "testCron2" monitor := mntr.Monitor{} @@ -137,6 +142,8 @@ func TestBucket_AdaptBackup(t *testing.T) { nodeselector, tolerations, version, + dbURL, + dbPort, features, "", )( @@ -163,6 +170,8 @@ func TestBucket_AdaptInstantBackup(t *testing.T) { cron := "testCron" monitor := mntr.Monitor{} namespace := "testNs" + dbURL := "testDB" + dbPort := int32(80) componentLabels := labels.MustForComponent(labels.MustForAPI(labels.MustForOperator("testProd", "testOp", "testVersion"), "BucketBackup", "v0"), "testComponent") k8sLabels := map[string]string{ @@ -209,6 +218,8 @@ func TestBucket_AdaptInstantBackup(t *testing.T) { nodeselector, tolerations, version, + dbURL, + dbPort, features, "", )( @@ -254,6 +265,8 @@ func TestBucket_AdaptRestore(t *testing.T) { backupName := "testName" version := "testVersion" saJson := "testSA" + dbURL := "testDB" + dbPort := int32(80) desired := getDesiredTree(t, masterkey, &DesiredV0{ Common: tree.NewCommon("databases.caos.ch/BucketBackup", "v0", false), @@ -282,6 +295,8 @@ func TestBucket_AdaptRestore(t *testing.T) { nodeselector, tolerations, version, + dbURL, + dbPort, features, "", )( @@ -299,6 +314,7 @@ func TestBucket_AdaptRestore(t *testing.T) { assert.NoError(t, ensure(client)) } +/* func TestBucket_AdaptClean(t *testing.T) { masterkey := "testMk" client := kubernetesmock.NewMockClientInt(gomock.NewController(t)) @@ -327,6 +343,8 @@ func TestBucket_AdaptClean(t *testing.T) { backupName := "testName" version := "testVersion" saJson := "testSA" + dbURL := "testDB" + dbPort := int32(80) desired := getDesiredTree(t, masterkey, &DesiredV0{ Common: tree.NewCommon("databases.caos.ch/BucketBackup", "v0", false), @@ -355,6 +373,8 @@ func TestBucket_AdaptClean(t *testing.T) { nodeselector, tolerations, version, + dbURL, + dbPort, features, "", )( @@ -371,4 +391,4 @@ func TestBucket_AdaptClean(t *testing.T) { assert.NotNil(t, ensure) assert.NoError(t, err) assert.NoError(t, ensure(client)) -} +}*/ diff --git a/operator/database/kinds/backups/bucket/backup/adapt.go b/operator/database/kinds/backups/bucket/backup/adapt.go index 27642aae3..e91d34e0f 100644 --- a/operator/database/kinds/backups/bucket/backup/adapt.go +++ b/operator/database/kinds/backups/bucket/backup/adapt.go @@ -19,6 +19,7 @@ const ( secretPath = "/secrets/sa.json" backupPath = "/cockroach" backupNameEnv = "BACKUP_NAME" + saJsonBase64Env = "SAJSON" cronJobNamePrefix = "backup-" internalSecretName = "client-certs" rootSecretName = "cockroachdb.client.root" @@ -32,7 +33,6 @@ func AdaptFunc( backupName string, namespace string, componentLabels *labels.Component, - databases []string, checkDBReady operator.EnsureFunc, bucketName string, cron string, @@ -41,6 +41,8 @@ func AdaptFunc( timestamp string, nodeselector map[string]string, tolerations []corev1.Toleration, + dbURL string, + dbPort int32, features []string, image string, ) ( @@ -51,9 +53,12 @@ func AdaptFunc( command := getBackupCommand( timestamp, - databases, bucketName, backupName, + certPath, + secretPath, + dbURL, + dbPort, ) jobSpecDef := getJobSpecDef( diff --git a/operator/database/kinds/backups/bucket/backup/adapt_test.go b/operator/database/kinds/backups/bucket/backup/adapt_test.go index a8834b88b..f4c7334b5 100644 --- a/operator/database/kinds/backups/bucket/backup/adapt_test.go +++ b/operator/database/kinds/backups/bucket/backup/adapt_test.go @@ -21,7 +21,6 @@ func TestBackup_AdaptInstantBackup1(t *testing.T) { monitor := mntr.Monitor{} namespace := "testNs" - databases := []string{"testDb"} bucketName := "testBucket" cron := "testCron" timestamp := "test" @@ -32,6 +31,8 @@ func TestBackup_AdaptInstantBackup1(t *testing.T) { image := "testImage" secretKey := "testKey" secretName := "testSecretName" + dbURL := "testDB" + dbPort := int32(80) jobName := GetJobName(backupName) componentLabels := labels.MustForComponent(labels.MustForAPI(labels.MustForOperator("testProd2", "testOp2", "testVersion2"), "testKind2", "testVersion2"), "testComponent") nameLabels := labels.MustForName(componentLabels, jobName) @@ -51,9 +52,12 @@ func TestBackup_AdaptInstantBackup1(t *testing.T) { backupName, getBackupCommand( timestamp, - databases, bucketName, backupName, + certPath, + secretPath, + dbURL, + dbPort, ), image, ), @@ -67,7 +71,6 @@ func TestBackup_AdaptInstantBackup1(t *testing.T) { backupName, namespace, componentLabels, - databases, checkDBReady, bucketName, cron, @@ -76,6 +79,8 @@ func TestBackup_AdaptInstantBackup1(t *testing.T) { timestamp, nodeselector, tolerations, + dbURL, + dbPort, features, image, ) @@ -93,7 +98,8 @@ func TestBackup_AdaptInstantBackup2(t *testing.T) { features := []string{Instant} monitor := mntr.Monitor{} namespace := "testNs2" - databases := []string{"testDb2"} + dbURL := "testDB" + dbPort := int32(80) bucketName := "testBucket2" cron := "testCron2" timestamp := "test2" @@ -123,9 +129,12 @@ func TestBackup_AdaptInstantBackup2(t *testing.T) { backupName, getBackupCommand( timestamp, - databases, bucketName, backupName, + certPath, + secretPath, + dbURL, + dbPort, ), image, ), @@ -139,7 +148,6 @@ func TestBackup_AdaptInstantBackup2(t *testing.T) { backupName, namespace, componentLabels, - databases, checkDBReady, bucketName, cron, @@ -148,6 +156,8 @@ func TestBackup_AdaptInstantBackup2(t *testing.T) { timestamp, nodeselector, tolerations, + dbURL, + dbPort, features, image, ) @@ -165,10 +175,11 @@ func TestBackup_AdaptBackup1(t *testing.T) { features := []string{Normal} monitor := mntr.Monitor{} namespace := "testNs" - databases := []string{"testDb"} bucketName := "testBucket" cron := "testCron" timestamp := "test" + dbURL := "testDB" + dbPort := int32(80) nodeselector := map[string]string{"test": "test"} tolerations := []corev1.Toleration{ {Key: "testKey", Operator: "testOp"}} @@ -196,9 +207,12 @@ func TestBackup_AdaptBackup1(t *testing.T) { backupName, getBackupCommand( timestamp, - databases, bucketName, backupName, + certPath, + secretPath, + dbURL, + dbPort, ), image, ), @@ -211,7 +225,6 @@ func TestBackup_AdaptBackup1(t *testing.T) { backupName, namespace, componentLabels, - databases, checkDBReady, bucketName, cron, @@ -220,6 +233,8 @@ func TestBackup_AdaptBackup1(t *testing.T) { timestamp, nodeselector, tolerations, + dbURL, + dbPort, features, image, ) @@ -237,7 +252,8 @@ func TestBackup_AdaptBackup2(t *testing.T) { features := []string{Normal} monitor := mntr.Monitor{} namespace := "testNs2" - databases := []string{"testDb2"} + dbURL := "testDB" + dbPort := int32(80) bucketName := "testBucket2" cron := "testCron2" timestamp := "test2" @@ -268,9 +284,12 @@ func TestBackup_AdaptBackup2(t *testing.T) { backupName, getBackupCommand( timestamp, - databases, bucketName, backupName, + certPath, + secretPath, + dbURL, + dbPort, ), image, ), @@ -283,7 +302,6 @@ func TestBackup_AdaptBackup2(t *testing.T) { backupName, namespace, componentLabels, - databases, checkDBReady, bucketName, cron, @@ -292,6 +310,8 @@ func TestBackup_AdaptBackup2(t *testing.T) { timestamp, nodeselector, tolerations, + dbURL, + dbPort, features, image, ) diff --git a/operator/database/kinds/backups/bucket/backup/cleanup.go b/operator/database/kinds/backups/bucket/backup/cleanup.go index 7a1310879..33fc5122b 100644 --- a/operator/database/kinds/backups/bucket/backup/cleanup.go +++ b/operator/database/kinds/backups/bucket/backup/cleanup.go @@ -23,7 +23,7 @@ func GetCleanupFunc( if err := k8sClient.DeleteJob(namespace, GetJobName(backupName)); err != nil { return fmt.Errorf("error while trying to cleanup backup: %w", err) } - monitor.Info("restore backup is completed") + monitor.Info("cleanup backup is completed") return nil } } diff --git a/operator/database/kinds/backups/bucket/backup/command.go b/operator/database/kinds/backups/bucket/backup/command.go index 4558df62c..3db5039bc 100644 --- a/operator/database/kinds/backups/bucket/backup/command.go +++ b/operator/database/kinds/backups/bucket/backup/command.go @@ -1,12 +1,18 @@ package backup -import "strings" +import ( + "strconv" + "strings" +) func getBackupCommand( timestamp string, - databases []string, bucketName string, backupName string, + certsFolder string, + serviceAccountPath string, + dbURL string, + dbPort int32, ) string { backupCommands := make([]string, 0) @@ -16,18 +22,20 @@ func getBackupCommand( backupCommands = append(backupCommands, "export "+backupNameEnv+"=$(date +%Y-%m-%dT%H:%M:%SZ)") } - for _, database := range databases { - backupCommands = append(backupCommands, - strings.Join([]string{ - "/scripts/backup.sh", - backupName, - bucketName, - database, - backupPath, - secretPath, - certPath, - "${" + backupNameEnv + "}", - }, " ")) - } + backupCommands = append(backupCommands, "export "+saJsonBase64Env+"=$(cat "+serviceAccountPath+" | base64 | tr -d '\n' )") + + backupCommands = append(backupCommands, + strings.Join([]string{ + "cockroach", + "sql", + "--certs-dir=" + certsFolder, + "--host=" + dbURL, + "--port=" + strconv.Itoa(int(dbPort)), + "-e", + "\"BACKUP TO \\\"gs://" + bucketName + "/" + backupName + "/${" + backupNameEnv + "}?AUTH=specified&CREDENTIALS=${" + saJsonBase64Env + "}\\\";\"", + }, " ", + ), + ) + return strings.Join(backupCommands, " && ") } diff --git a/operator/database/kinds/backups/bucket/backup/command_test.go b/operator/database/kinds/backups/bucket/backup/command_test.go index 59ef89cbe..7b476b4fd 100644 --- a/operator/database/kinds/backups/bucket/backup/command_test.go +++ b/operator/database/kinds/backups/bucket/backup/command_test.go @@ -7,47 +7,40 @@ import ( func TestBackup_Command1(t *testing.T) { timestamp := "" - databases := []string{} bucketName := "test" backupName := "test" + dbURL := "testDB" + dbPort := int32(80) - cmd := getBackupCommand(timestamp, databases, bucketName, backupName) - equals := "export " + backupNameEnv + "=$(date +%Y-%m-%dT%H:%M:%SZ)" + cmd := getBackupCommand( + timestamp, + bucketName, + backupName, + certPath, + secretPath, + dbURL, + dbPort, + ) + equals := "export " + backupNameEnv + "=$(date +%Y-%m-%dT%H:%M:%SZ) && export SAJSON=$(cat /secrets/sa.json | base64 | tr -d '\n' ) && cockroach sql --certs-dir=/cockroach/cockroach-certs --host=testDB --port=80 -e \"BACKUP TO \\\"gs://test/test/${BACKUP_NAME}?AUTH=specified&CREDENTIALS=${SAJSON}\\\";\"" assert.Equal(t, equals, cmd) } func TestBackup_Command2(t *testing.T) { timestamp := "test" - databases := []string{} bucketName := "test" backupName := "test" + dbURL := "testDB" + dbPort := int32(80) - cmd := getBackupCommand(timestamp, databases, bucketName, backupName) - equals := "export " + backupNameEnv + "=test" - assert.Equal(t, equals, cmd) -} - -func TestBackup_Command3(t *testing.T) { - timestamp := "" - databases := []string{"testDb"} - bucketName := "testBucket" - backupName := "testBackup" - - cmd := getBackupCommand(timestamp, databases, bucketName, backupName) - equals := "export " + backupNameEnv + "=$(date +%Y-%m-%dT%H:%M:%SZ) && /scripts/backup.sh testBackup testBucket testDb " + backupPath + " " + secretPath + " " + certPath + " ${" + backupNameEnv + "}" - assert.Equal(t, equals, cmd) -} - -func TestBackup_Command4(t *testing.T) { - timestamp := "test" - databases := []string{"test1", "test2", "test3"} - bucketName := "testBucket" - backupName := "testBackup" - - cmd := getBackupCommand(timestamp, databases, bucketName, backupName) - equals := "export " + backupNameEnv + "=test && " + - "/scripts/backup.sh testBackup testBucket test1 " + backupPath + " " + secretPath + " " + certPath + " ${" + backupNameEnv + "} && " + - "/scripts/backup.sh testBackup testBucket test2 " + backupPath + " " + secretPath + " " + certPath + " ${" + backupNameEnv + "} && " + - "/scripts/backup.sh testBackup testBucket test3 " + backupPath + " " + secretPath + " " + certPath + " ${" + backupNameEnv + "}" + cmd := getBackupCommand( + timestamp, + bucketName, + backupName, + certPath, + secretPath, + dbURL, + dbPort, + ) + equals := "export " + backupNameEnv + "=test && export SAJSON=$(cat /secrets/sa.json | base64 | tr -d '\n' ) && cockroach sql --certs-dir=/cockroach/cockroach-certs --host=testDB --port=80 -e \"BACKUP TO \\\"gs://test/test/${BACKUP_NAME}?AUTH=specified&CREDENTIALS=${SAJSON}\\\";\"" assert.Equal(t, equals, cmd) } diff --git a/operator/database/kinds/backups/bucket/backup/job.go b/operator/database/kinds/backups/bucket/backup/job.go index b7a53a22f..8a064a30a 100644 --- a/operator/database/kinds/backups/bucket/backup/job.go +++ b/operator/database/kinds/backups/bucket/backup/job.go @@ -77,7 +77,7 @@ func getJobSpecDef( SubPath: secretKey, MountPath: secretPath, }}, - ImagePullPolicy: corev1.PullAlways, + ImagePullPolicy: corev1.PullIfNotPresent, }}, Volumes: []corev1.Volume{{ Name: internalSecretName, diff --git a/operator/database/kinds/backups/bucket/backup/job_test.go b/operator/database/kinds/backups/bucket/backup/job_test.go index f41a6efcc..e54aeb5bb 100644 --- a/operator/database/kinds/backups/bucket/backup/job_test.go +++ b/operator/database/kinds/backups/bucket/backup/job_test.go @@ -41,7 +41,7 @@ func TestBackup_JobSpec1(t *testing.T) { SubPath: secretKey, MountPath: secretPath, }}, - ImagePullPolicy: corev1.PullAlways, + ImagePullPolicy: corev1.PullIfNotPresent, }}, Volumes: []corev1.Volume{{ Name: internalSecretName, @@ -98,7 +98,7 @@ func TestBackup_JobSpec2(t *testing.T) { SubPath: secretKey, MountPath: secretPath, }}, - ImagePullPolicy: corev1.PullAlways, + ImagePullPolicy: corev1.PullIfNotPresent, }}, Volumes: []corev1.Volume{{ Name: internalSecretName, diff --git a/operator/database/kinds/backups/bucket/clean/command.go b/operator/database/kinds/backups/bucket/clean/command.go deleted file mode 100644 index bef9cf5a9..000000000 --- a/operator/database/kinds/backups/bucket/clean/command.go +++ /dev/null @@ -1,33 +0,0 @@ -package clean - -import "strings" - -func getCommand( - databases []string, - users []string, -) string { - backupCommands := make([]string, 0) - for _, database := range databases { - backupCommands = append(backupCommands, - strings.Join([]string{ - "/scripts/clean-db.sh", - certPath, - database, - }, " ")) - } - for _, user := range users { - backupCommands = append(backupCommands, - strings.Join([]string{ - "/scripts/clean-user.sh", - certPath, - user, - }, " ")) - } - backupCommands = append(backupCommands, - strings.Join([]string{ - "/scripts/clean-migration.sh", - certPath, - }, " ")) - - return strings.Join(backupCommands, " && ") -} diff --git a/operator/database/kinds/backups/bucket/clean/command_test.go b/operator/database/kinds/backups/bucket/clean/command_test.go deleted file mode 100644 index e79a3713f..000000000 --- a/operator/database/kinds/backups/bucket/clean/command_test.go +++ /dev/null @@ -1,38 +0,0 @@ -package clean - -import ( - "github.com/stretchr/testify/assert" - "testing" -) - -func TestClean_Command1(t *testing.T) { - databases := []string{} - users := []string{} - - cmd := getCommand(databases, users) - equals := "/scripts/clean-migration.sh " + certPath - - assert.Equal(t, equals, cmd) -} - -func TestClean_Command2(t *testing.T) { - databases := []string{"test"} - users := []string{"test"} - - cmd := getCommand(databases, users) - equals := "/scripts/clean-db.sh " + certPath + " test && /scripts/clean-user.sh " + certPath + " test && /scripts/clean-migration.sh " + certPath - - assert.Equal(t, equals, cmd) -} - -func TestClean_Command3(t *testing.T) { - databases := []string{"test1", "test2", "test3"} - users := []string{"test1", "test2", "test3"} - - cmd := getCommand(databases, users) - equals := "/scripts/clean-db.sh " + certPath + " test1 && /scripts/clean-db.sh " + certPath + " test2 && /scripts/clean-db.sh " + certPath + " test3 && " + - "/scripts/clean-user.sh " + certPath + " test1 && /scripts/clean-user.sh " + certPath + " test2 && /scripts/clean-user.sh " + certPath + " test3 && " + - "/scripts/clean-migration.sh " + certPath - - assert.Equal(t, equals, cmd) -} diff --git a/operator/database/kinds/backups/bucket/list.go b/operator/database/kinds/backups/bucket/list.go index ce1cc45b2..32dbb1143 100644 --- a/operator/database/kinds/backups/bucket/list.go +++ b/operator/database/kinds/backups/bucket/list.go @@ -60,6 +60,9 @@ func listFilesWithFilter(serviceAccountJSON string, bucketName, name string) ([] parts := strings.Split(attrs.Name, "/") found := false for _, name := range names { + if len(parts) < 2 { + continue + } if name == parts[1] { found = true } diff --git a/operator/database/kinds/backups/bucket/mock.go b/operator/database/kinds/backups/bucket/mock.go index 04fccc42c..4009d9895 100644 --- a/operator/database/kinds/backups/bucket/mock.go +++ b/operator/database/kinds/backups/bucket/mock.go @@ -3,7 +3,6 @@ package bucket import ( kubernetesmock "github.com/caos/orbos/pkg/kubernetes/mock" "github.com/caos/zitadel/operator/database/kinds/backups/bucket/backup" - "github.com/caos/zitadel/operator/database/kinds/backups/bucket/clean" "github.com/caos/zitadel/operator/database/kinds/backups/bucket/restore" "github.com/caos/zitadel/operator/database/kinds/databases/core" "github.com/golang/mock/gomock" @@ -61,29 +60,6 @@ func SetBackup( k8sClient.EXPECT().ApplyCronJob(gomock.Any()).Times(1).Return(nil) } -func SetClean( - k8sClient *kubernetesmock.MockClientInt, - namespace string, - backupName string, - labels map[string]string, - saJson string, -) { - k8sClient.EXPECT().ApplySecret(&corev1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: secretName, - Namespace: namespace, - Labels: labels, - }, - StringData: map[string]string{secretKey: saJson}, - Type: "Opaque", - }).Times(1).Return(nil) - - k8sClient.EXPECT().ApplyJob(gomock.Any()).Times(1).Return(nil) - k8sClient.EXPECT().GetJob(namespace, clean.GetJobName(backupName)).Times(1).Return(nil, macherrs.NewNotFound(schema.GroupResource{"batch", "jobs"}, clean.GetJobName(backupName))) - k8sClient.EXPECT().WaitUntilJobCompleted(namespace, clean.GetJobName(backupName), gomock.Any()).Times(1).Return(nil) - k8sClient.EXPECT().DeleteJob(namespace, clean.GetJobName(backupName)).Times(1).Return(nil) -} - func SetRestore( k8sClient *kubernetesmock.MockClientInt, namespace string, diff --git a/operator/database/kinds/backups/bucket/restore/adapt.go b/operator/database/kinds/backups/bucket/restore/adapt.go index 6f6b19a7e..0675c6d13 100644 --- a/operator/database/kinds/backups/bucket/restore/adapt.go +++ b/operator/database/kinds/backups/bucket/restore/adapt.go @@ -22,6 +22,7 @@ const ( internalSecretName = "client-certs" rootSecretName = "cockroachdb.client.root" timeout = 45 * time.Minute + saJsonBase64Env = "SAJSON" ) func AdaptFunc( @@ -29,7 +30,6 @@ func AdaptFunc( backupName string, namespace string, componentLabels *labels.Component, - databases []string, bucketName string, timestamp string, nodeselector map[string]string, @@ -37,6 +37,8 @@ func AdaptFunc( checkDBReady operator.EnsureFunc, secretName string, secretKey string, + dbURL string, + dbPort int32, image string, ) ( queryFunc operator.QueryFunc, @@ -47,9 +49,12 @@ func AdaptFunc( jobName := jobPrefix + backupName + jobSuffix command := getCommand( timestamp, - databases, bucketName, backupName, + certPath, + secretPath, + dbURL, + dbPort, ) jobdef := getJob( @@ -60,7 +65,8 @@ func AdaptFunc( secretName, secretKey, command, - image) + image, + ) destroyJ, err := job.AdaptFuncToDestroy(jobName, namespace) if err != nil { diff --git a/operator/database/kinds/backups/bucket/restore/adapt_test.go b/operator/database/kinds/backups/bucket/restore/adapt_test.go index 5eaf96cf6..2e5c90465 100644 --- a/operator/database/kinds/backups/bucket/restore/adapt_test.go +++ b/operator/database/kinds/backups/bucket/restore/adapt_test.go @@ -19,7 +19,6 @@ func TestBackup_Adapt1(t *testing.T) { monitor := mntr.Monitor{} namespace := "testNs" - databases := []string{"testDb"} nodeselector := map[string]string{"test": "test"} tolerations := []corev1.Toleration{ {Key: "testKey", Operator: "testOp"}} @@ -29,6 +28,8 @@ func TestBackup_Adapt1(t *testing.T) { image := "testImage2" secretKey := "testKey" secretName := "testSecretName" + dbURL := "testDB" + dbPort := int32(80) jobName := GetJobName(backupName) componentLabels := labels.MustForComponent(labels.MustForAPI(labels.MustForOperator("testProd", "testOp", "testVersion"), "testKind", "testVersion"), "testComponent") nameLabels := labels.MustForName(componentLabels, jobName) @@ -46,9 +47,12 @@ func TestBackup_Adapt1(t *testing.T) { secretKey, getCommand( timestamp, - databases, bucketName, backupName, + certPath, + secretPath, + dbURL, + dbPort, ), image, ) @@ -61,7 +65,6 @@ func TestBackup_Adapt1(t *testing.T) { backupName, namespace, componentLabels, - databases, bucketName, timestamp, nodeselector, @@ -69,6 +72,8 @@ func TestBackup_Adapt1(t *testing.T) { checkDBReady, secretName, secretKey, + dbURL, + dbPort, image, ) @@ -84,7 +89,6 @@ func TestBackup_Adapt2(t *testing.T) { monitor := mntr.Monitor{} namespace := "testNs2" - databases := []string{"testDb1", "testDb2"} nodeselector := map[string]string{"test2": "test2"} tolerations := []corev1.Toleration{ {Key: "testKey2", Operator: "testOp2"}} @@ -94,6 +98,8 @@ func TestBackup_Adapt2(t *testing.T) { image := "testImage2" secretKey := "testKey2" secretName := "testSecretName2" + dbURL := "testDB" + dbPort := int32(80) jobName := GetJobName(backupName) componentLabels := labels.MustForComponent(labels.MustForAPI(labels.MustForOperator("testProd2", "testOp2", "testVersion2"), "testKind2", "testVersion2"), "testComponent2") nameLabels := labels.MustForName(componentLabels, jobName) @@ -111,9 +117,12 @@ func TestBackup_Adapt2(t *testing.T) { secretKey, getCommand( timestamp, - databases, bucketName, backupName, + certPath, + secretPath, + dbURL, + dbPort, ), image, ) @@ -126,7 +135,6 @@ func TestBackup_Adapt2(t *testing.T) { backupName, namespace, componentLabels, - databases, bucketName, timestamp, nodeselector, @@ -134,6 +142,8 @@ func TestBackup_Adapt2(t *testing.T) { checkDBReady, secretName, secretKey, + dbURL, + dbPort, image, ) diff --git a/operator/database/kinds/backups/bucket/restore/command.go b/operator/database/kinds/backups/bucket/restore/command.go index 30a34e2df..eb0890790 100644 --- a/operator/database/kinds/backups/bucket/restore/command.go +++ b/operator/database/kinds/backups/bucket/restore/command.go @@ -1,28 +1,36 @@ package restore -import "strings" +import ( + "strconv" + "strings" +) func getCommand( timestamp string, - databases []string, bucketName string, backupName string, - + certsFolder string, + serviceAccountPath string, + dbURL string, + dbPort int32, ) string { backupCommands := make([]string, 0) - for _, database := range databases { - backupCommands = append(backupCommands, - strings.Join([]string{ - "/scripts/restore.sh", - bucketName, - backupName, - timestamp, - database, - secretPath, - certPath, - }, " ")) - } + + backupCommands = append(backupCommands, "export "+saJsonBase64Env+"=$(cat "+serviceAccountPath+" | base64 | tr -d '\n' )") + + backupCommands = append(backupCommands, + strings.Join([]string{ + "cockroach", + "sql", + "--certs-dir=" + certsFolder, + "--host=" + dbURL, + "--port=" + strconv.Itoa(int(dbPort)), + "-e", + "\"RESTORE FROM \\\"gs://" + bucketName + "/" + backupName + "/" + timestamp + "?AUTH=specified&CREDENTIALS=${" + saJsonBase64Env + "}\\\";\"", + }, " ", + ), + ) return strings.Join(backupCommands, " && ") } diff --git a/operator/database/kinds/backups/bucket/restore/command_test.go b/operator/database/kinds/backups/bucket/restore/command_test.go index 2a2d0c812..3f8464664 100644 --- a/operator/database/kinds/backups/bucket/restore/command_test.go +++ b/operator/database/kinds/backups/bucket/restore/command_test.go @@ -6,45 +6,42 @@ import ( ) func TestBackup_Command1(t *testing.T) { - timestamp := "" - databases := []string{} + timestamp := "test1" bucketName := "testBucket" backupName := "testBackup" + dbURL := "testDB" + dbPort := int32(80) - cmd := getCommand(timestamp, databases, bucketName, backupName) - equals := "" + cmd := getCommand( + timestamp, + bucketName, + backupName, + certPath, + secretPath, + dbURL, + dbPort, + ) + + equals := "export SAJSON=$(cat /secrets/sa.json | base64 | tr -d '\n' ) && cockroach sql --certs-dir=/cockroach/cockroach-certs --host=testDB --port=80 -e \"RESTORE FROM \\\"gs://testBucket/testBackup/test1?AUTH=specified&CREDENTIALS=${SAJSON}\\\";\"" assert.Equal(t, equals, cmd) } func TestBackup_Command2(t *testing.T) { - timestamp := "" - databases := []string{"testDb"} + timestamp := "test2" bucketName := "testBucket" backupName := "testBackup" + dbURL := "testDB2" + dbPort := int32(81) - cmd := getCommand(timestamp, databases, bucketName, backupName) - equals := "/scripts/restore.sh testBucket testBackup testDb /secrets/sa.json /cockroach/cockroach-certs" - assert.Equal(t, equals, cmd) -} - -func TestBackup_Command3(t *testing.T) { - timestamp := "test" - databases := []string{"testDb"} - bucketName := "testBucket" - backupName := "testBackup" - - cmd := getCommand(timestamp, databases, bucketName, backupName) - equals := "/scripts/restore.sh testBucket testBackup test testDb /secrets/sa.json /cockroach/cockroach-certs" - assert.Equal(t, equals, cmd) -} - -func TestBackup_Command4(t *testing.T) { - timestamp := "" - databases := []string{} - bucketName := "test" - backupName := "test" - - cmd := getCommand(timestamp, databases, bucketName, backupName) - equals := "" + cmd := getCommand( + timestamp, + bucketName, + backupName, + certPath, + secretPath, + dbURL, + dbPort, + ) + equals := "export SAJSON=$(cat /secrets/sa.json | base64 | tr -d '\n' ) && cockroach sql --certs-dir=/cockroach/cockroach-certs --host=testDB2 --port=81 -e \"RESTORE FROM \\\"gs://testBucket/testBackup/test2?AUTH=specified&CREDENTIALS=${SAJSON}\\\";\"" assert.Equal(t, equals, cmd) } diff --git a/operator/database/kinds/backups/bucket/restore/job.go b/operator/database/kinds/backups/bucket/restore/job.go index 7193fc3db..fc0647794 100644 --- a/operator/database/kinds/backups/bucket/restore/job.go +++ b/operator/database/kinds/backups/bucket/restore/job.go @@ -46,7 +46,7 @@ func getJob( SubPath: secretKey, MountPath: secretPath, }}, - ImagePullPolicy: corev1.PullAlways, + ImagePullPolicy: corev1.PullIfNotPresent, }}, Volumes: []corev1.Volume{{ Name: internalSecretName, diff --git a/operator/database/kinds/backups/bucket/restore/job_test.go b/operator/database/kinds/backups/bucket/restore/job_test.go index d9547968c..dbd95d611 100644 --- a/operator/database/kinds/backups/bucket/restore/job_test.go +++ b/operator/database/kinds/backups/bucket/restore/job_test.go @@ -61,7 +61,7 @@ func TestBackup_Job1(t *testing.T) { SubPath: secretKey, MountPath: secretPath, }}, - ImagePullPolicy: corev1.PullAlways, + ImagePullPolicy: corev1.PullIfNotPresent, }}, Volumes: []corev1.Volume{{ Name: internalSecretName, @@ -137,7 +137,7 @@ func TestBackup_Job2(t *testing.T) { SubPath: secretKey, MountPath: secretPath, }}, - ImagePullPolicy: corev1.PullAlways, + ImagePullPolicy: corev1.PullIfNotPresent, }}, Volumes: []corev1.Volume{{ Name: internalSecretName, diff --git a/operator/database/kinds/backups/s3/adapt.go b/operator/database/kinds/backups/s3/adapt.go new file mode 100644 index 000000000..c03289fa9 --- /dev/null +++ b/operator/database/kinds/backups/s3/adapt.go @@ -0,0 +1,296 @@ +package s3 + +import ( + "fmt" + "github.com/caos/orbos/mntr" + "github.com/caos/orbos/pkg/kubernetes" + "github.com/caos/orbos/pkg/kubernetes/resources/secret" + "github.com/caos/orbos/pkg/labels" + secretpkg "github.com/caos/orbos/pkg/secret" + "github.com/caos/orbos/pkg/secret/read" + "github.com/caos/orbos/pkg/tree" + "github.com/caos/zitadel/operator" + "github.com/caos/zitadel/operator/common" + "github.com/caos/zitadel/operator/database/kinds/backups/s3/backup" + "github.com/caos/zitadel/operator/database/kinds/backups/s3/restore" + corev1 "k8s.io/api/core/v1" +) + +const ( + accessKeyIDName = "backup-accessaccountkey" + accessKeyIDKey = "accessaccountkey" + secretAccessKeyName = "backup-secretaccesskey" + secretAccessKeyKey = "secretaccesskey" + sessionTokenName = "backup-sessiontoken" + sessionTokenKey = "sessiontoken" +) + +func AdaptFunc( + name string, + namespace string, + componentLabels *labels.Component, + checkDBReady operator.EnsureFunc, + timestamp string, + nodeselector map[string]string, + tolerations []corev1.Toleration, + version string, + dbURL string, + dbPort int32, + features []string, + customImageRegistry string, +) operator.AdaptFunc { + return func( + monitor mntr.Monitor, + desired *tree.Tree, + current *tree.Tree, + ) ( + operator.QueryFunc, + operator.DestroyFunc, + operator.ConfigureFunc, + map[string]*secretpkg.Secret, + map[string]*secretpkg.Existing, + bool, + error, + ) { + + internalMonitor := monitor.WithField("component", "backup") + + desiredKind, err := ParseDesiredV0(desired) + if err != nil { + return nil, nil, nil, nil, nil, false, fmt.Errorf("parsing desired state failed: %s", err) + } + desired.Parsed = desiredKind + + secrets, existing := getSecretsMap(desiredKind) + + if !monitor.IsVerbose() && desiredKind.Spec.Verbose { + internalMonitor.Verbose() + } + + destroySAKI, err := secret.AdaptFuncToDestroy(namespace, accessKeyIDName) + if err != nil { + return nil, nil, nil, nil, nil, false, err + } + + destroySSAK, err := secret.AdaptFuncToDestroy(namespace, secretAccessKeyName) + if err != nil { + return nil, nil, nil, nil, nil, false, err + } + + destroySSTK, err := secret.AdaptFuncToDestroy(namespace, sessionTokenName) + if err != nil { + return nil, nil, nil, nil, nil, false, err + } + + image := common.BackupImage.Reference(customImageRegistry, version) + + _, destroyB, err := backup.AdaptFunc( + internalMonitor, + name, + namespace, + componentLabels, + checkDBReady, + desiredKind.Spec.Bucket, + desiredKind.Spec.Cron, + accessKeyIDName, + accessKeyIDKey, + secretAccessKeyName, + secretAccessKeyKey, + sessionTokenName, + sessionTokenKey, + desiredKind.Spec.Region, + desiredKind.Spec.Endpoint, + timestamp, + nodeselector, + tolerations, + dbURL, + dbPort, + features, + image, + ) + if err != nil { + return nil, nil, nil, nil, nil, false, err + } + + _, destroyR, err := restore.AdaptFunc( + monitor, + name, + namespace, + componentLabels, + desiredKind.Spec.Bucket, + timestamp, + accessKeyIDName, + accessKeyIDKey, + secretAccessKeyName, + secretAccessKeyKey, + sessionTokenName, + sessionTokenKey, + desiredKind.Spec.Region, + desiredKind.Spec.Endpoint, + nodeselector, + tolerations, + checkDBReady, + dbURL, + dbPort, + image, + ) + if err != nil { + return nil, nil, nil, nil, nil, false, err + } + + destroyers := make([]operator.DestroyFunc, 0) + for _, feature := range features { + switch feature { + case backup.Normal, backup.Instant: + destroyers = append(destroyers, + operator.ResourceDestroyToZitadelDestroy(destroySSAK), + operator.ResourceDestroyToZitadelDestroy(destroySAKI), + operator.ResourceDestroyToZitadelDestroy(destroySSTK), + destroyB, + ) + case restore.Instant: + destroyers = append(destroyers, + destroyR, + ) + } + } + + return func(k8sClient kubernetes.ClientInt, queried map[string]interface{}) (operator.EnsureFunc, error) { + + if err := desiredKind.validateSecrets(); err != nil { + return nil, err + } + + valueAKI, err := read.GetSecretValue(k8sClient, desiredKind.Spec.AccessKeyID, desiredKind.Spec.ExistingAccessKeyID) + if err != nil { + return nil, err + } + + querySAKI, err := secret.AdaptFuncToEnsure(namespace, labels.MustForName(componentLabels, accessKeyIDName), map[string]string{accessKeyIDKey: valueAKI}) + if err != nil { + return nil, err + } + + valueSAK, err := read.GetSecretValue(k8sClient, desiredKind.Spec.SecretAccessKey, desiredKind.Spec.ExistingSecretAccessKey) + if err != nil { + return nil, err + } + + querySSAK, err := secret.AdaptFuncToEnsure(namespace, labels.MustForName(componentLabels, secretAccessKeyName), map[string]string{secretAccessKeyKey: valueSAK}) + if err != nil { + return nil, err + } + + valueST, err := read.GetSecretValue(k8sClient, desiredKind.Spec.SessionToken, desiredKind.Spec.ExistingSessionToken) + if err != nil { + return nil, err + } + + querySST, err := secret.AdaptFuncToEnsure(namespace, labels.MustForName(componentLabels, sessionTokenName), map[string]string{sessionTokenKey: valueST}) + if err != nil { + return nil, err + } + + queryB, _, err := backup.AdaptFunc( + internalMonitor, + name, + namespace, + componentLabels, + checkDBReady, + desiredKind.Spec.Bucket, + desiredKind.Spec.Cron, + accessKeyIDName, + accessKeyIDKey, + secretAccessKeyName, + secretAccessKeyKey, + sessionTokenName, + sessionTokenKey, + desiredKind.Spec.Region, + desiredKind.Spec.Endpoint, + timestamp, + nodeselector, + tolerations, + dbURL, + dbPort, + features, + image, + ) + if err != nil { + return nil, err + } + + queryR, _, err := restore.AdaptFunc( + monitor, + name, + namespace, + componentLabels, + desiredKind.Spec.Bucket, + timestamp, + accessKeyIDName, + accessKeyIDKey, + secretAccessKeyName, + secretAccessKeyKey, + sessionTokenName, + sessionTokenKey, + desiredKind.Spec.Region, + desiredKind.Spec.Endpoint, + nodeselector, + tolerations, + checkDBReady, + dbURL, + dbPort, + image, + ) + if err != nil { + return nil, err + } + + queriers := make([]operator.QueryFunc, 0) + cleanupQueries := make([]operator.QueryFunc, 0) + for _, feature := range features { + switch feature { + case backup.Normal: + queriers = append(queriers, + operator.ResourceQueryToZitadelQuery(querySAKI), + operator.ResourceQueryToZitadelQuery(querySSAK), + operator.ResourceQueryToZitadelQuery(querySST), + queryB, + ) + case backup.Instant: + queriers = append(queriers, + operator.ResourceQueryToZitadelQuery(querySAKI), + operator.ResourceQueryToZitadelQuery(querySSAK), + operator.ResourceQueryToZitadelQuery(querySST), + queryB, + ) + cleanupQueries = append(cleanupQueries, + operator.EnsureFuncToQueryFunc(backup.GetCleanupFunc(monitor, namespace, name)), + ) + case restore.Instant: + queriers = append(queriers, + operator.ResourceQueryToZitadelQuery(querySAKI), + operator.ResourceQueryToZitadelQuery(querySSAK), + operator.ResourceQueryToZitadelQuery(querySST), + queryR, + ) + cleanupQueries = append(cleanupQueries, + operator.EnsureFuncToQueryFunc(restore.GetCleanupFunc(monitor, namespace, name)), + ) + } + + } + + for _, cleanup := range cleanupQueries { + queriers = append(queriers, cleanup) + } + + return operator.QueriersToEnsureFunc(internalMonitor, false, queriers, k8sClient, queried) + }, + operator.DestroyersToDestroyFunc(internalMonitor, destroyers), + func(kubernetes.ClientInt, map[string]interface{}, bool) error { return nil }, + secrets, + existing, + false, + nil + } +} diff --git a/operator/database/kinds/backups/s3/adapt_test.go b/operator/database/kinds/backups/s3/adapt_test.go new file mode 100644 index 000000000..7fcaabefb --- /dev/null +++ b/operator/database/kinds/backups/s3/adapt_test.go @@ -0,0 +1,500 @@ +package s3 + +import ( + "testing" + + "github.com/caos/orbos/mntr" + "github.com/caos/orbos/pkg/kubernetes" + kubernetesmock "github.com/caos/orbos/pkg/kubernetes/mock" + "github.com/caos/orbos/pkg/labels" + "github.com/caos/orbos/pkg/secret" + "github.com/caos/orbos/pkg/tree" + "github.com/caos/zitadel/operator/database/kinds/backups/bucket/backup" + "github.com/caos/zitadel/operator/database/kinds/backups/bucket/restore" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" +) + +func TestBucket_Secrets(t *testing.T) { + masterkey := "testMk" + features := []string{backup.Normal} + region := "testRegion" + endpoint := "testEndpoint" + akid := "testAKID" + sak := "testSAK" + st := "testST" + + bucketName := "testBucket2" + cron := "testCron2" + monitor := mntr.Monitor{} + namespace := "testNs2" + + dbURL := "testDB" + dbPort := int32(80) + kindVersion := "v0" + kind := "BucketBackup" + componentLabels := labels.MustForComponent(labels.MustForAPI(labels.MustForOperator("testProd", "testOp", "testVersion"), "BucketBackup", kindVersion), "testComponent") + + timestamp := "test2" + nodeselector := map[string]string{"test2": "test2"} + tolerations := []corev1.Toleration{ + {Key: "testKey2", Operator: "testOp2"}} + backupName := "testName2" + version := "testVersion2" + + desired := getDesiredTree(t, masterkey, &DesiredV0{ + Common: tree.NewCommon("databases.caos.ch/"+kind, kindVersion, false), + Spec: &Spec{ + Verbose: true, + Cron: cron, + Bucket: bucketName, + Endpoint: endpoint, + Region: region, + AccessKeyID: &secret.Secret{ + Value: akid, + }, + SecretAccessKey: &secret.Secret{ + Value: sak, + }, + SessionToken: &secret.Secret{ + Value: st, + }, + }, + }) + + checkDBReady := func(k8sClient kubernetes.ClientInt) error { + return nil + } + + allSecrets := map[string]string{ + "accesskeyid": "testAKID", + "secretaccesskey": "testSAK", + "sessiontoken": "testST", + } + + _, _, _, secrets, existing, _, err := AdaptFunc( + backupName, + namespace, + componentLabels, + checkDBReady, + timestamp, + nodeselector, + tolerations, + version, + dbURL, + dbPort, + features, + "", + )( + monitor, + desired, + &tree.Tree{}, + ) + assert.NoError(t, err) + for key, value := range allSecrets { + assert.Contains(t, secrets, key) + assert.Contains(t, existing, key) + assert.Equal(t, value, secrets[key].Value) + } +} + +func TestBucket_AdaptBackup(t *testing.T) { + masterkey := "testMk" + client := kubernetesmock.NewMockClientInt(gomock.NewController(t)) + features := []string{backup.Normal} + region := "testRegion" + endpoint := "testEndpoint" + akid := "testAKID" + sak := "testSAK" + st := "testST" + + dbURL := "testDB" + dbPort := int32(80) + bucketName := "testBucket2" + cron := "testCron2" + monitor := mntr.Monitor{} + namespace := "testNs2" + + componentLabels := labels.MustForComponent(labels.MustForAPI(labels.MustForOperator("testProd", "testOp", "testVersion"), "BucketBackup", "v0"), "testComponent") + k8sLabelsAKID := map[string]string{ + "app.kubernetes.io/component": "testComponent", + "app.kubernetes.io/managed-by": "testOp", + "app.kubernetes.io/name": accessKeyIDName, + "app.kubernetes.io/part-of": "testProd", + "app.kubernetes.io/version": "testVersion", + "caos.ch/apiversion": "v0", + "caos.ch/kind": "BucketBackup", + } + k8sLabelsSAK := map[string]string{ + "app.kubernetes.io/component": "testComponent", + "app.kubernetes.io/managed-by": "testOp", + "app.kubernetes.io/name": secretAccessKeyName, + "app.kubernetes.io/part-of": "testProd", + "app.kubernetes.io/version": "testVersion", + "caos.ch/apiversion": "v0", + "caos.ch/kind": "BucketBackup", + } + k8sLabelsST := map[string]string{ + "app.kubernetes.io/component": "testComponent", + "app.kubernetes.io/managed-by": "testOp", + "app.kubernetes.io/name": sessionTokenName, + "app.kubernetes.io/part-of": "testProd", + "app.kubernetes.io/version": "testVersion", + "caos.ch/apiversion": "v0", + "caos.ch/kind": "BucketBackup", + } + timestamp := "test2" + nodeselector := map[string]string{"test2": "test2"} + tolerations := []corev1.Toleration{ + {Key: "testKey2", Operator: "testOp2"}} + backupName := "testName2" + version := "testVersion2" + + desired := getDesiredTree(t, masterkey, &DesiredV0{ + Common: tree.NewCommon("databases.caos.ch/BucketBackup", "v0", false), + Spec: &Spec{ + Verbose: true, + Cron: cron, + Bucket: bucketName, + Endpoint: endpoint, + Region: region, + AccessKeyID: &secret.Secret{ + Value: akid, + }, + SecretAccessKey: &secret.Secret{ + Value: sak, + }, + SessionToken: &secret.Secret{ + Value: st, + }, + }, + }) + + checkDBReady := func(k8sClient kubernetes.ClientInt) error { + return nil + } + + SetBackup(client, namespace, k8sLabelsAKID, k8sLabelsSAK, k8sLabelsST, akid, sak, st) + + query, _, _, _, _, _, err := AdaptFunc( + backupName, + namespace, + componentLabels, + checkDBReady, + timestamp, + nodeselector, + tolerations, + version, + dbURL, + dbPort, + features, + "", + )( + monitor, + desired, + &tree.Tree{}, + ) + + assert.NoError(t, err) + databases := []string{"test1", "test2"} + queried := SetQueriedForDatabases(databases, []string{}) + ensure, err := query(client, queried) + assert.NoError(t, err) + assert.NotNil(t, ensure) + assert.NoError(t, ensure(client)) +} + +func TestBucket_AdaptInstantBackup(t *testing.T) { + masterkey := "testMk" + client := kubernetesmock.NewMockClientInt(gomock.NewController(t)) + features := []string{backup.Instant} + + bucketName := "testBucket1" + cron := "testCron" + monitor := mntr.Monitor{} + namespace := "testNs" + dbURL := "testDB" + dbPort := int32(80) + + componentLabels := labels.MustForComponent(labels.MustForAPI(labels.MustForOperator("testProd", "testOp", "testVersion"), "BucketBackup", "v0"), "testComponent") + k8sLabelsAKID := map[string]string{ + "app.kubernetes.io/component": "testComponent", + "app.kubernetes.io/managed-by": "testOp", + "app.kubernetes.io/name": accessKeyIDName, + "app.kubernetes.io/part-of": "testProd", + "app.kubernetes.io/version": "testVersion", + "caos.ch/apiversion": "v0", + "caos.ch/kind": "BucketBackup", + } + k8sLabelsSAK := map[string]string{ + "app.kubernetes.io/component": "testComponent", + "app.kubernetes.io/managed-by": "testOp", + "app.kubernetes.io/name": secretAccessKeyName, + "app.kubernetes.io/part-of": "testProd", + "app.kubernetes.io/version": "testVersion", + "caos.ch/apiversion": "v0", + "caos.ch/kind": "BucketBackup", + } + k8sLabelsST := map[string]string{ + "app.kubernetes.io/component": "testComponent", + "app.kubernetes.io/managed-by": "testOp", + "app.kubernetes.io/name": sessionTokenName, + "app.kubernetes.io/part-of": "testProd", + "app.kubernetes.io/version": "testVersion", + "caos.ch/apiversion": "v0", + "caos.ch/kind": "BucketBackup", + } + timestamp := "test" + nodeselector := map[string]string{"test": "test"} + tolerations := []corev1.Toleration{ + {Key: "testKey", Operator: "testOp"}} + backupName := "testName" + version := "testVersion" + region := "testRegion" + endpoint := "testEndpoint" + akid := "testAKID" + sak := "testSAK" + st := "testST" + + desired := getDesiredTree(t, masterkey, &DesiredV0{ + Common: tree.NewCommon("databases.caos.ch/BucketBackup", "v0", false), + Spec: &Spec{ + Verbose: true, + Cron: cron, + Bucket: bucketName, + Endpoint: endpoint, + Region: region, + AccessKeyID: &secret.Secret{ + Value: akid, + }, + SecretAccessKey: &secret.Secret{ + Value: sak, + }, + SessionToken: &secret.Secret{ + Value: st, + }, + }, + }) + + checkDBReady := func(k8sClient kubernetes.ClientInt) error { + return nil + } + + SetInstantBackup(client, namespace, backupName, k8sLabelsAKID, k8sLabelsSAK, k8sLabelsST, akid, sak, st) + + query, _, _, _, _, _, err := AdaptFunc( + backupName, + namespace, + componentLabels, + checkDBReady, + timestamp, + nodeselector, + tolerations, + version, + dbURL, + dbPort, + features, + "", + )( + monitor, + desired, + &tree.Tree{}, + ) + + assert.NoError(t, err) + databases := []string{"test1", "test2"} + queried := SetQueriedForDatabases(databases, []string{}) + ensure, err := query(client, queried) + assert.NotNil(t, ensure) + assert.NoError(t, err) + assert.NoError(t, ensure(client)) +} + +func TestBucket_AdaptRestore(t *testing.T) { + masterkey := "testMk" + client := kubernetesmock.NewMockClientInt(gomock.NewController(t)) + features := []string{restore.Instant} + + bucketName := "testBucket1" + cron := "testCron" + monitor := mntr.Monitor{} + namespace := "testNs" + + componentLabels := labels.MustForComponent(labels.MustForAPI(labels.MustForOperator("testProd", "testOp", "testVersion"), "BucketBackup", "v0"), "testComponent") + k8sLabelsAKID := map[string]string{ + "app.kubernetes.io/component": "testComponent", + "app.kubernetes.io/managed-by": "testOp", + "app.kubernetes.io/name": accessKeyIDName, + "app.kubernetes.io/part-of": "testProd", + "app.kubernetes.io/version": "testVersion", + "caos.ch/apiversion": "v0", + "caos.ch/kind": "BucketBackup", + } + k8sLabelsSAK := map[string]string{ + "app.kubernetes.io/component": "testComponent", + "app.kubernetes.io/managed-by": "testOp", + "app.kubernetes.io/name": secretAccessKeyName, + "app.kubernetes.io/part-of": "testProd", + "app.kubernetes.io/version": "testVersion", + "caos.ch/apiversion": "v0", + "caos.ch/kind": "BucketBackup", + } + k8sLabelsST := map[string]string{ + "app.kubernetes.io/component": "testComponent", + "app.kubernetes.io/managed-by": "testOp", + "app.kubernetes.io/name": sessionTokenName, + "app.kubernetes.io/part-of": "testProd", + "app.kubernetes.io/version": "testVersion", + "caos.ch/apiversion": "v0", + "caos.ch/kind": "BucketBackup", + } + + timestamp := "test" + nodeselector := map[string]string{"test": "test"} + tolerations := []corev1.Toleration{ + {Key: "testKey", Operator: "testOp"}} + backupName := "testName" + version := "testVersion" + region := "testRegion" + endpoint := "testEndpoint" + akid := "testAKID" + sak := "testSAK" + st := "testST" + dbURL := "testDB" + dbPort := int32(80) + + desired := getDesiredTree(t, masterkey, &DesiredV0{ + Common: tree.NewCommon("databases.caos.ch/BucketBackup", "v0", false), + Spec: &Spec{ + Verbose: true, + Cron: cron, + Bucket: bucketName, + Endpoint: endpoint, + Region: region, + AccessKeyID: &secret.Secret{ + Value: akid, + }, + SecretAccessKey: &secret.Secret{ + Value: sak, + }, + SessionToken: &secret.Secret{ + Value: st, + }, + }, + }) + + checkDBReady := func(k8sClient kubernetes.ClientInt) error { + return nil + } + + SetRestore(client, namespace, backupName, k8sLabelsAKID, k8sLabelsSAK, k8sLabelsST, akid, sak, st) + + query, _, _, _, _, _, err := AdaptFunc( + backupName, + namespace, + componentLabels, + checkDBReady, + timestamp, + nodeselector, + tolerations, + version, + dbURL, + dbPort, + features, + "", + )( + monitor, + desired, + &tree.Tree{}, + ) + + assert.NoError(t, err) + databases := []string{"test1", "test2"} + queried := SetQueriedForDatabases(databases, []string{}) + ensure, err := query(client, queried) + assert.NotNil(t, ensure) + assert.NoError(t, err) + assert.NoError(t, ensure(client)) +} + +/* +func TestBucket_AdaptClean(t *testing.T) { + masterkey := "testMk" + client := kubernetesmock.NewMockClientInt(gomock.NewController(t)) + features := []string{clean.Instant} + + bucketName := "testBucket1" + cron := "testCron" + monitor := mntr.Monitor{} + namespace := "testNs" + + componentLabels := labels.MustForComponent(labels.MustForAPI(labels.MustForOperator("testProd", "testOp", "testVersion"), "BucketBackup", "v0"), "testComponent") + k8sLabels := map[string]string{ + "app.kubernetes.io/component": "testComponent", + "app.kubernetes.io/managed-by": "testOp", + "app.kubernetes.io/name": "backup-serviceaccountjson", + "app.kubernetes.io/part-of": "testProd", + "app.kubernetes.io/version": "testVersion", + "caos.ch/apiversion": "v0", + "caos.ch/kind": "BucketBackup", + } + + timestamp := "test" + nodeselector := map[string]string{"test": "test"} + tolerations := []corev1.Toleration{ + {Key: "testKey", Operator: "testOp"}} + backupName := "testName" + version := "testVersion" + saJson := "testSA" + dbURL := "testDB" + dbPort := int32(80) + + desired := getDesiredTree(t, masterkey, &DesiredV0{ + Common: &tree.Common{ + Kind: "databases.caos.ch/BucketBackup", + Version: "v0", + }, + Spec: &Spec{ + Verbose: true, + Cron: cron, + Bucket: bucketName, + ServiceAccountJSON: &secret.Secret{ + Value: saJson, + }, + }, + }) + + checkDBReady := func(k8sClient kubernetes.ClientInt) error { + return nil + } + + SetClean(client, namespace, backupName, k8sLabels, saJson) + + query, _, _, _, _, _, err := AdaptFunc( + backupName, + namespace, + componentLabels, + checkDBReady, + timestamp, + nodeselector, + tolerations, + version, + dbURL, + dbPort, + features, + )( + monitor, + desired, + &tree.Tree{}, + ) + + assert.NoError(t, err) + databases := []string{"test1", "test2"} + users := []string{"test1", "test2"} + queried := SetQueriedForDatabases(databases, users) + ensure, err := query(client, queried) + assert.NotNil(t, ensure) + assert.NoError(t, err) + assert.NoError(t, ensure(client)) +}*/ diff --git a/operator/database/kinds/backups/s3/backup/adapt.go b/operator/database/kinds/backups/s3/backup/adapt.go new file mode 100644 index 000000000..a04a4ca4d --- /dev/null +++ b/operator/database/kinds/backups/s3/backup/adapt.go @@ -0,0 +1,154 @@ +package backup + +import ( + "time" + + "github.com/caos/zitadel/operator" + + "github.com/caos/orbos/mntr" + "github.com/caos/orbos/pkg/kubernetes" + "github.com/caos/orbos/pkg/kubernetes/resources/cronjob" + "github.com/caos/orbos/pkg/kubernetes/resources/job" + "github.com/caos/orbos/pkg/labels" + corev1 "k8s.io/api/core/v1" +) + +const ( + defaultMode int32 = 256 + certPath = "/cockroach/cockroach-certs" + accessKeyIDPath = "/secrets/accessaccountkey" + secretAccessKeyPath = "/secrets/secretaccesskey" + sessionTokenPath = "/secrets/sessiontoken" + backupNameEnv = "BACKUP_NAME" + cronJobNamePrefix = "backup-" + internalSecretName = "client-certs" + rootSecretName = "cockroachdb.client.root" + timeout = 15 * time.Minute + Normal = "backup" + Instant = "instantbackup" +) + +func AdaptFunc( + monitor mntr.Monitor, + backupName string, + namespace string, + componentLabels *labels.Component, + checkDBReady operator.EnsureFunc, + bucketName string, + cron string, + accessKeyIDName string, + accessKeyIDKey string, + secretAccessKeyName string, + secretAccessKeyKey string, + sessionTokenName string, + sessionTokenKey string, + region string, + endpoint string, + timestamp string, + nodeselector map[string]string, + tolerations []corev1.Toleration, + dbURL string, + dbPort int32, + features []string, + image string, +) ( + queryFunc operator.QueryFunc, + destroyFunc operator.DestroyFunc, + err error, +) { + + command := getBackupCommand( + timestamp, + bucketName, + backupName, + certPath, + accessKeyIDPath, + secretAccessKeyPath, + sessionTokenPath, + region, + endpoint, + dbURL, + dbPort, + ) + + jobSpecDef := getJobSpecDef( + nodeselector, + tolerations, + accessKeyIDName, + accessKeyIDKey, + secretAccessKeyName, + secretAccessKeyKey, + sessionTokenName, + sessionTokenKey, + backupName, + image, + command, + ) + + destroyers := []operator.DestroyFunc{} + queriers := []operator.QueryFunc{} + + cronJobDef := getCronJob( + namespace, + labels.MustForName(componentLabels, GetJobName(backupName)), + cron, + jobSpecDef, + ) + + destroyCJ, err := cronjob.AdaptFuncToDestroy(cronJobDef.Namespace, cronJobDef.Name) + if err != nil { + return nil, nil, err + } + + queryCJ, err := cronjob.AdaptFuncToEnsure(cronJobDef) + if err != nil { + return nil, nil, err + } + + jobDef := getJob( + namespace, + labels.MustForName(componentLabels, cronJobNamePrefix+backupName), + jobSpecDef, + ) + + destroyJ, err := job.AdaptFuncToDestroy(jobDef.Namespace, jobDef.Name) + if err != nil { + return nil, nil, err + } + + queryJ, err := job.AdaptFuncToEnsure(jobDef) + if err != nil { + return nil, nil, err + } + + for _, feature := range features { + switch feature { + case Normal: + destroyers = append(destroyers, + operator.ResourceDestroyToZitadelDestroy(destroyCJ), + ) + queriers = append(queriers, + operator.EnsureFuncToQueryFunc(checkDBReady), + operator.ResourceQueryToZitadelQuery(queryCJ), + ) + case Instant: + destroyers = append(destroyers, + operator.ResourceDestroyToZitadelDestroy(destroyJ), + ) + queriers = append(queriers, + operator.EnsureFuncToQueryFunc(checkDBReady), + operator.ResourceQueryToZitadelQuery(queryJ), + ) + } + } + + return func(k8sClient kubernetes.ClientInt, queried map[string]interface{}) (operator.EnsureFunc, error) { + return operator.QueriersToEnsureFunc(monitor, false, queriers, k8sClient, queried) + }, + operator.DestroyersToDestroyFunc(monitor, destroyers), + nil +} + +func GetJobName(backupName string) string { + return cronJobNamePrefix + backupName +} diff --git a/operator/database/kinds/backups/s3/backup/adapt_test.go b/operator/database/kinds/backups/s3/backup/adapt_test.go new file mode 100644 index 000000000..aa3a259fc --- /dev/null +++ b/operator/database/kinds/backups/s3/backup/adapt_test.go @@ -0,0 +1,404 @@ +package backup + +import ( + "testing" + + "github.com/caos/orbos/mntr" + "github.com/caos/orbos/pkg/kubernetes" + kubernetesmock "github.com/caos/orbos/pkg/kubernetes/mock" + "github.com/caos/orbos/pkg/labels" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/assert" + corev1 "k8s.io/api/core/v1" + macherrs "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +func TestBackup_AdaptInstantBackup1(t *testing.T) { + client := kubernetesmock.NewMockClientInt(gomock.NewController(t)) + + features := []string{Instant} + monitor := mntr.Monitor{} + namespace := "testNs" + + bucketName := "testBucket" + cron := "testCron" + timestamp := "test" + nodeselector := map[string]string{"test": "test"} + tolerations := []corev1.Toleration{ + {Key: "testKey", Operator: "testOp"}} + backupName := "testName" + version := "testVersion" + accessKeyIDName := "testAKIN" + accessKeyIDKey := "testAKIK" + secretAccessKeyName := "testSAKN" + secretAccessKeyKey := "testSAKK" + sessionTokenName := "testSTN" + sessionTokenKey := "testSTK" + region := "region" + endpoint := "endpoint" + dbURL := "testDB" + dbPort := int32(80) + jobName := GetJobName(backupName) + componentLabels := labels.MustForComponent(labels.MustForAPI(labels.MustForOperator("testProd2", "testOp2", "testVersion2"), "testKind2", "testVersion2"), "testComponent") + nameLabels := labels.MustForName(componentLabels, jobName) + + checkDBReady := func(k8sClient kubernetes.ClientInt) error { + return nil + } + + jobDef := getJob( + namespace, + nameLabels, + getJobSpecDef( + nodeselector, + tolerations, + accessKeyIDName, + accessKeyIDKey, + secretAccessKeyName, + secretAccessKeyKey, + sessionTokenName, + sessionTokenKey, + backupName, + version, + getBackupCommand( + timestamp, + bucketName, + backupName, + certPath, + accessKeyIDPath, + secretAccessKeyPath, + sessionTokenPath, + region, + endpoint, + dbURL, + dbPort, + ), + ), + ) + + client.EXPECT().ApplyJob(jobDef).Times(1).Return(nil) + client.EXPECT().GetJob(jobDef.Namespace, jobDef.Name).Times(1).Return(nil, macherrs.NewNotFound(schema.GroupResource{"batch", "jobs"}, jobName)) + + query, _, err := AdaptFunc( + monitor, + backupName, + namespace, + componentLabels, + checkDBReady, + bucketName, + cron, + accessKeyIDName, + accessKeyIDKey, + secretAccessKeyName, + secretAccessKeyKey, + sessionTokenName, + sessionTokenKey, + region, + endpoint, + timestamp, + nodeselector, + tolerations, + dbURL, + dbPort, + features, + version, + ) + + assert.NoError(t, err) + queried := map[string]interface{}{} + ensure, err := query(client, queried) + assert.NoError(t, err) + assert.NoError(t, ensure(client)) +} + +func TestBackup_AdaptInstantBackup2(t *testing.T) { + client := kubernetesmock.NewMockClientInt(gomock.NewController(t)) + + features := []string{Instant} + monitor := mntr.Monitor{} + namespace := "testNs2" + dbURL := "testDB" + dbPort := int32(80) + bucketName := "testBucket2" + cron := "testCron2" + timestamp := "test2" + nodeselector := map[string]string{"test2": "test2"} + tolerations := []corev1.Toleration{ + {Key: "testKey2", Operator: "testOp2"}} + backupName := "testName2" + version := "testVersion2" + accessKeyIDName := "testAKIN2" + accessKeyIDKey := "testAKIK2" + secretAccessKeyName := "testSAKN2" + secretAccessKeyKey := "testSAKK2" + sessionTokenName := "testSTN2" + sessionTokenKey := "testSTK2" + region := "region2" + endpoint := "endpoint2" + jobName := GetJobName(backupName) + componentLabels := labels.MustForComponent(labels.MustForAPI(labels.MustForOperator("testProd2", "testOp2", "testVersion2"), "testKind2", "testVersion2"), "testComponent") + nameLabels := labels.MustForName(componentLabels, jobName) + + checkDBReady := func(k8sClient kubernetes.ClientInt) error { + return nil + } + + jobDef := getJob( + namespace, + nameLabels, + getJobSpecDef( + nodeselector, + tolerations, + accessKeyIDName, + accessKeyIDKey, + secretAccessKeyName, + secretAccessKeyKey, + sessionTokenName, + sessionTokenKey, + backupName, + version, + getBackupCommand( + timestamp, + bucketName, + backupName, + certPath, + accessKeyIDPath, + secretAccessKeyPath, + sessionTokenPath, + region, + endpoint, + dbURL, + dbPort, + ), + ), + ) + + client.EXPECT().ApplyJob(jobDef).Times(1).Return(nil) + client.EXPECT().GetJob(jobDef.Namespace, jobDef.Name).Times(1).Return(nil, macherrs.NewNotFound(schema.GroupResource{"batch", "jobs"}, jobName)) + + query, _, err := AdaptFunc( + monitor, + backupName, + namespace, + componentLabels, + checkDBReady, + bucketName, + cron, + accessKeyIDName, + accessKeyIDKey, + secretAccessKeyName, + secretAccessKeyKey, + sessionTokenName, + sessionTokenKey, + region, + endpoint, + timestamp, + nodeselector, + tolerations, + dbURL, + dbPort, + features, + version, + ) + + assert.NoError(t, err) + queried := map[string]interface{}{} + ensure, err := query(client, queried) + assert.NoError(t, err) + assert.NoError(t, ensure(client)) +} + +func TestBackup_AdaptBackup1(t *testing.T) { + client := kubernetesmock.NewMockClientInt(gomock.NewController(t)) + + features := []string{Normal} + monitor := mntr.Monitor{} + namespace := "testNs" + bucketName := "testBucket" + cron := "testCron" + timestamp := "test" + dbURL := "testDB" + dbPort := int32(80) + nodeselector := map[string]string{"test": "test"} + tolerations := []corev1.Toleration{ + {Key: "testKey", Operator: "testOp"}} + backupName := "testName" + version := "testVersion" + accessKeyIDName := "testAKIN" + accessKeyIDKey := "testAKIK" + secretAccessKeyName := "testSAKN" + secretAccessKeyKey := "testSAKK" + sessionTokenName := "testSTN" + sessionTokenKey := "testSTK" + region := "region" + endpoint := "endpoint" + jobName := GetJobName(backupName) + componentLabels := labels.MustForComponent(labels.MustForAPI(labels.MustForOperator("testProd2", "testOp2", "testVersion2"), "testKind2", "testVersion2"), "testComponent") + nameLabels := labels.MustForName(componentLabels, jobName) + + checkDBReady := func(k8sClient kubernetes.ClientInt) error { + return nil + } + + jobDef := getCronJob( + namespace, + nameLabels, + cron, + getJobSpecDef( + nodeselector, + tolerations, + accessKeyIDName, + accessKeyIDKey, + secretAccessKeyName, + secretAccessKeyKey, + sessionTokenName, + sessionTokenKey, + backupName, + version, + getBackupCommand( + timestamp, + bucketName, + backupName, + certPath, + accessKeyIDPath, + secretAccessKeyPath, + sessionTokenPath, + region, + endpoint, + dbURL, + dbPort, + ), + ), + ) + + client.EXPECT().ApplyCronJob(jobDef).Times(1).Return(nil) + + query, _, err := AdaptFunc( + monitor, + backupName, + namespace, + componentLabels, + checkDBReady, + bucketName, + cron, + accessKeyIDName, + accessKeyIDKey, + secretAccessKeyName, + secretAccessKeyKey, + sessionTokenName, + sessionTokenKey, + region, + endpoint, + timestamp, + nodeselector, + tolerations, + dbURL, + dbPort, + features, + version, + ) + + assert.NoError(t, err) + queried := map[string]interface{}{} + ensure, err := query(client, queried) + assert.NoError(t, err) + assert.NoError(t, ensure(client)) +} + +func TestBackup_AdaptBackup2(t *testing.T) { + client := kubernetesmock.NewMockClientInt(gomock.NewController(t)) + + features := []string{Normal} + monitor := mntr.Monitor{} + namespace := "testNs2" + dbURL := "testDB" + dbPort := int32(80) + bucketName := "testBucket2" + cron := "testCron2" + timestamp := "test2" + nodeselector := map[string]string{"test2": "test2"} + tolerations := []corev1.Toleration{ + {Key: "testKey2", Operator: "testOp2"}} + backupName := "testName2" + version := "testVersion2" + accessKeyIDName := "testAKIN2" + accessKeyIDKey := "testAKIK2" + secretAccessKeyName := "testSAKN2" + secretAccessKeyKey := "testSAKK2" + sessionTokenName := "testSTN2" + sessionTokenKey := "testSTK2" + region := "region2" + endpoint := "endpoint2" + jobName := GetJobName(backupName) + componentLabels := labels.MustForComponent(labels.MustForAPI(labels.MustForOperator("testProd2", "testOp2", "testVersion2"), "testKind2", "testVersion2"), "testComponent") + nameLabels := labels.MustForName(componentLabels, jobName) + + checkDBReady := func(k8sClient kubernetes.ClientInt) error { + return nil + } + + jobDef := getCronJob( + namespace, + nameLabels, + cron, + getJobSpecDef( + nodeselector, + tolerations, + accessKeyIDName, + accessKeyIDKey, + secretAccessKeyName, + secretAccessKeyKey, + sessionTokenName, + sessionTokenKey, + backupName, + version, + getBackupCommand( + timestamp, + bucketName, + backupName, + certPath, + accessKeyIDPath, + secretAccessKeyPath, + sessionTokenPath, + region, + endpoint, + dbURL, + dbPort, + ), + ), + ) + + client.EXPECT().ApplyCronJob(jobDef).Times(1).Return(nil) + + query, _, err := AdaptFunc( + monitor, + backupName, + namespace, + componentLabels, + checkDBReady, + bucketName, + cron, + accessKeyIDName, + accessKeyIDKey, + secretAccessKeyName, + secretAccessKeyKey, + sessionTokenName, + sessionTokenKey, + region, + endpoint, + timestamp, + nodeselector, + tolerations, + dbURL, + dbPort, + features, + version, + ) + + assert.NoError(t, err) + queried := map[string]interface{}{} + ensure, err := query(client, queried) + assert.NoError(t, err) + assert.NoError(t, ensure(client)) +} diff --git a/operator/database/kinds/backups/bucket/clean/cleanup.go b/operator/database/kinds/backups/s3/backup/cleanup.go similarity index 61% rename from operator/database/kinds/backups/bucket/clean/cleanup.go rename to operator/database/kinds/backups/s3/backup/cleanup.go index 0aede1466..357693915 100644 --- a/operator/database/kinds/backups/bucket/clean/cleanup.go +++ b/operator/database/kinds/backups/s3/backup/cleanup.go @@ -1,11 +1,9 @@ -package clean +package backup import ( "fmt" - "github.com/caos/orbos/mntr" "github.com/caos/orbos/pkg/kubernetes" - "github.com/caos/zitadel/operator" ) @@ -15,15 +13,15 @@ func GetCleanupFunc( backupName string, ) operator.EnsureFunc { return func(k8sClient kubernetes.ClientInt) error { - monitor.Info("waiting for clean to be completed") + monitor.Info("waiting for backup to be completed") if err := k8sClient.WaitUntilJobCompleted(namespace, GetJobName(backupName), timeout); err != nil { - return fmt.Errorf("error while waiting for clean to be completed: %w", err) + return fmt.Errorf("error while waiting for backup to be completed: %w", err) } - monitor.Info("clean is completed, cleanup") + monitor.Info("backup is completed, cleanup") if err := k8sClient.DeleteJob(namespace, GetJobName(backupName)); err != nil { - return fmt.Errorf("error while trying to cleanup clean: %w", err) + return fmt.Errorf("error while trying to cleanup backup: %w", err) } - monitor.Info("clean cleanup is completed") + monitor.Info("cleanup backup is completed") return nil } } diff --git a/operator/database/kinds/backups/s3/backup/cleanup_test.go b/operator/database/kinds/backups/s3/backup/cleanup_test.go new file mode 100644 index 000000000..f41ac374f --- /dev/null +++ b/operator/database/kinds/backups/s3/backup/cleanup_test.go @@ -0,0 +1,41 @@ +package backup + +import ( + "fmt" + "testing" + + "github.com/caos/orbos/mntr" + kubernetesmock "github.com/caos/orbos/pkg/kubernetes/mock" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/assert" +) + +func TestBackup_Cleanup1(t *testing.T) { + client := kubernetesmock.NewMockClientInt(gomock.NewController(t)) + monitor := mntr.Monitor{} + name := "test" + namespace := "testNs" + + cleanupFunc := GetCleanupFunc(monitor, namespace, name) + client.EXPECT().WaitUntilJobCompleted(namespace, GetJobName(name), timeout).Times(1).Return(nil) + client.EXPECT().DeleteJob(namespace, GetJobName(name)).Times(1) + assert.NoError(t, cleanupFunc(client)) + + client.EXPECT().WaitUntilJobCompleted(namespace, GetJobName(name), timeout).Times(1).Return(fmt.Errorf("fail")) + assert.Error(t, cleanupFunc(client)) +} + +func TestBackup_Cleanup2(t *testing.T) { + client := kubernetesmock.NewMockClientInt(gomock.NewController(t)) + monitor := mntr.Monitor{} + name := "test2" + namespace := "testNs2" + + cleanupFunc := GetCleanupFunc(monitor, namespace, name) + client.EXPECT().WaitUntilJobCompleted(namespace, GetJobName(name), timeout).Times(1).Return(nil) + client.EXPECT().DeleteJob(namespace, GetJobName(name)).Times(1) + assert.NoError(t, cleanupFunc(client)) + + client.EXPECT().WaitUntilJobCompleted(namespace, GetJobName(name), timeout).Times(1).Return(fmt.Errorf("fail")) + assert.Error(t, cleanupFunc(client)) +} diff --git a/operator/database/kinds/backups/s3/backup/command.go b/operator/database/kinds/backups/s3/backup/command.go new file mode 100644 index 000000000..027774141 --- /dev/null +++ b/operator/database/kinds/backups/s3/backup/command.go @@ -0,0 +1,53 @@ +package backup + +import ( + "strconv" + "strings" +) + +func getBackupCommand( + timestamp string, + bucketName string, + backupName string, + certsFolder string, + accessKeyIDPath string, + secretAccessKeyPath string, + sessionTokenPath string, + region string, + endpoint string, + dbURL string, + dbPort int32, +) string { + + backupCommands := make([]string, 0) + if timestamp != "" { + backupCommands = append(backupCommands, "export "+backupNameEnv+"="+timestamp) + } else { + backupCommands = append(backupCommands, "export "+backupNameEnv+"=$(date +%Y-%m-%dT%H:%M:%SZ)") + } + + parameters := []string{ + "AWS_ACCESS_KEY_ID=$(cat " + accessKeyIDPath + ")", + "AWS_SECRET_ACCESS_KEY=$(cat " + secretAccessKeyPath + ")", + "AWS_SESSION_TOKEN=$(cat " + sessionTokenPath + ")", + "AWS_ENDPOINT=" + endpoint, + } + if region != "" { + parameters = append(parameters, "AWS_REGION="+region) + } + + backupCommands = append(backupCommands, + strings.Join([]string{ + "cockroach", + "sql", + "--certs-dir=" + certsFolder, + "--host=" + dbURL, + "--port=" + strconv.Itoa(int(dbPort)), + "-e", + "\"BACKUP TO \\\"s3://" + bucketName + "/" + backupName + "/${" + backupNameEnv + "}?" + strings.Join(parameters, "&") + "\\\";\"", + }, " ", + ), + ) + + return strings.Join(backupCommands, " && ") +} diff --git a/operator/database/kinds/backups/s3/backup/command_test.go b/operator/database/kinds/backups/s3/backup/command_test.go new file mode 100644 index 000000000..a99718947 --- /dev/null +++ b/operator/database/kinds/backups/s3/backup/command_test.go @@ -0,0 +1,58 @@ +package backup + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestBackup_Command1(t *testing.T) { + timestamp := "" + bucketName := "test" + backupName := "test" + dbURL := "testDB" + dbPort := int32(80) + region := "region" + endpoint := "endpoint" + + cmd := getBackupCommand( + timestamp, + bucketName, + backupName, + certPath, + accessKeyIDPath, + secretAccessKeyPath, + sessionTokenPath, + region, + endpoint, + dbURL, + dbPort, + ) + equals := "export " + backupNameEnv + "=$(date +%Y-%m-%dT%H:%M:%SZ) && cockroach sql --certs-dir=" + certPath + " --host=testDB --port=80 -e \"BACKUP TO \\\"s3://test/test/${BACKUP_NAME}?AWS_ACCESS_KEY_ID=$(cat " + accessKeyIDPath + ")&AWS_SECRET_ACCESS_KEY=$(cat " + secretAccessKeyPath + ")&AWS_SESSION_TOKEN=$(cat " + sessionTokenPath + ")&AWS_ENDPOINT=endpoint&AWS_REGION=region\\\";\"" + assert.Equal(t, equals, cmd) +} + +func TestBackup_Command2(t *testing.T) { + timestamp := "test" + bucketName := "test" + backupName := "test" + dbURL := "testDB" + dbPort := int32(80) + region := "region" + endpoint := "endpoint" + + cmd := getBackupCommand( + timestamp, + bucketName, + backupName, + certPath, + accessKeyIDPath, + secretAccessKeyPath, + sessionTokenPath, + region, + endpoint, + dbURL, + dbPort, + ) + equals := "export " + backupNameEnv + "=test && cockroach sql --certs-dir=" + certPath + " --host=testDB --port=80 -e \"BACKUP TO \\\"s3://test/test/${BACKUP_NAME}?AWS_ACCESS_KEY_ID=$(cat " + accessKeyIDPath + ")&AWS_SECRET_ACCESS_KEY=$(cat " + secretAccessKeyPath + ")&AWS_SESSION_TOKEN=$(cat " + sessionTokenPath + ")&AWS_ENDPOINT=endpoint&AWS_REGION=region\\\";\"" + assert.Equal(t, equals, cmd) +} diff --git a/operator/database/kinds/backups/s3/backup/job.go b/operator/database/kinds/backups/s3/backup/job.go new file mode 100644 index 000000000..2c2cc14b7 --- /dev/null +++ b/operator/database/kinds/backups/s3/backup/job.go @@ -0,0 +1,127 @@ +package backup + +import ( + "github.com/caos/orbos/pkg/labels" + "github.com/caos/zitadel/operator/helpers" + batchv1 "k8s.io/api/batch/v1" + "k8s.io/api/batch/v1beta1" + corev1 "k8s.io/api/core/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func getCronJob( + namespace string, + nameLabels *labels.Name, + cron string, + jobSpecDef batchv1.JobSpec, +) *v1beta1.CronJob { + return &v1beta1.CronJob{ + ObjectMeta: v1.ObjectMeta{ + Name: nameLabels.Name(), + Namespace: namespace, + Labels: labels.MustK8sMap(nameLabels), + }, + Spec: v1beta1.CronJobSpec{ + Schedule: cron, + ConcurrencyPolicy: v1beta1.ForbidConcurrent, + JobTemplate: v1beta1.JobTemplateSpec{ + Spec: jobSpecDef, + }, + }, + } +} + +func getJob( + namespace string, + nameLabels *labels.Name, + jobSpecDef batchv1.JobSpec, +) *batchv1.Job { + return &batchv1.Job{ + ObjectMeta: v1.ObjectMeta{ + Name: nameLabels.Name(), + Namespace: namespace, + Labels: labels.MustK8sMap(nameLabels), + }, + Spec: jobSpecDef, + } +} + +func getJobSpecDef( + nodeselector map[string]string, + tolerations []corev1.Toleration, + accessKeyIDName string, + accessKeyIDKey string, + secretAccessKeyName string, + secretAccessKeyKey string, + sessionTokenName string, + sessionTokenKey string, + backupName string, + image string, + command string, +) batchv1.JobSpec { + return batchv1.JobSpec{ + Template: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + RestartPolicy: corev1.RestartPolicyNever, + NodeSelector: nodeselector, + Tolerations: tolerations, + Containers: []corev1.Container{{ + Name: backupName, + Image: image, + Command: []string{ + "/bin/bash", + "-c", + command, + }, + VolumeMounts: []corev1.VolumeMount{{ + Name: internalSecretName, + MountPath: certPath, + }, { + Name: accessKeyIDKey, + SubPath: accessKeyIDKey, + MountPath: accessKeyIDPath, + }, { + Name: secretAccessKeyKey, + SubPath: secretAccessKeyKey, + MountPath: secretAccessKeyPath, + }, { + Name: sessionTokenKey, + SubPath: sessionTokenKey, + MountPath: sessionTokenPath, + }}, + ImagePullPolicy: corev1.PullIfNotPresent, + }}, + Volumes: []corev1.Volume{{ + Name: internalSecretName, + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: rootSecretName, + DefaultMode: helpers.PointerInt32(defaultMode), + }, + }, + }, { + Name: accessKeyIDKey, + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: accessKeyIDName, + }, + }, + }, { + Name: secretAccessKeyKey, + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: secretAccessKeyName, + }, + }, + }, { + Name: sessionTokenKey, + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: sessionTokenName, + }, + }, + }}, + }, + }, + } +} diff --git a/operator/database/kinds/backups/s3/backup/job_test.go b/operator/database/kinds/backups/s3/backup/job_test.go new file mode 100644 index 000000000..c18e9070e --- /dev/null +++ b/operator/database/kinds/backups/s3/backup/job_test.go @@ -0,0 +1,199 @@ +package backup + +import ( + "github.com/caos/zitadel/operator/common" + "github.com/caos/zitadel/operator/helpers" + "github.com/stretchr/testify/assert" + batchv1 "k8s.io/api/batch/v1" + corev1 "k8s.io/api/core/v1" + "testing" +) + +func TestBackup_JobSpec1(t *testing.T) { + nodeselector := map[string]string{"test": "test"} + tolerations := []corev1.Toleration{ + {Key: "testKey", Operator: "testOp"}} + backupName := "testName" + version := "testVersion" + command := "test" + accessKeyIDName := "testAKIN" + accessKeyIDKey := "testAKIK" + secretAccessKeyName := "testSAKN" + secretAccessKeyKey := "testSAKK" + sessionTokenName := "testSTN" + sessionTokenKey := "testSTK" + + equals := batchv1.JobSpec{ + Template: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + RestartPolicy: corev1.RestartPolicyNever, + NodeSelector: nodeselector, + Tolerations: tolerations, + Containers: []corev1.Container{{ + Name: backupName, + Image: common.BackupImage.Reference("", version), + Command: []string{ + "/bin/bash", + "-c", + command, + }, + VolumeMounts: []corev1.VolumeMount{{ + Name: internalSecretName, + MountPath: certPath, + }, { + Name: accessKeyIDKey, + SubPath: accessKeyIDKey, + MountPath: accessKeyIDPath, + }, { + Name: secretAccessKeyKey, + SubPath: secretAccessKeyKey, + MountPath: secretAccessKeyPath, + }, { + Name: sessionTokenKey, + SubPath: sessionTokenKey, + MountPath: sessionTokenPath, + }}, + ImagePullPolicy: corev1.PullIfNotPresent, + }}, + Volumes: []corev1.Volume{{ + Name: internalSecretName, + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: rootSecretName, + DefaultMode: helpers.PointerInt32(defaultMode), + }, + }, + }, { + Name: accessKeyIDKey, + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: accessKeyIDName, + }, + }, + }, { + Name: secretAccessKeyKey, + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: secretAccessKeyName, + }, + }, + }, { + Name: sessionTokenKey, + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: sessionTokenName, + }, + }, + }}, + }, + }, + } + + assert.Equal(t, equals, getJobSpecDef( + nodeselector, + tolerations, + accessKeyIDName, + accessKeyIDKey, + secretAccessKeyName, + secretAccessKeyKey, + sessionTokenName, + sessionTokenKey, + backupName, + common.BackupImage.Reference("", version), + command)) +} + +func TestBackup_JobSpec2(t *testing.T) { + nodeselector := map[string]string{"test2": "test2"} + tolerations := []corev1.Toleration{ + {Key: "testKey2", Operator: "testOp2"}} + backupName := "testName2" + version := "testVersion2" + command := "test2" + accessKeyIDName := "testAKIN2" + accessKeyIDKey := "testAKIK2" + secretAccessKeyName := "testSAKN2" + secretAccessKeyKey := "testSAKK2" + sessionTokenName := "testSTN2" + sessionTokenKey := "testSTK2" + + equals := batchv1.JobSpec{ + Template: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + RestartPolicy: corev1.RestartPolicyNever, + NodeSelector: nodeselector, + Tolerations: tolerations, + Containers: []corev1.Container{{ + Name: backupName, + Image: common.BackupImage.Reference("", version), + Command: []string{ + "/bin/bash", + "-c", + command, + }, + VolumeMounts: []corev1.VolumeMount{{ + Name: internalSecretName, + MountPath: certPath, + }, { + Name: accessKeyIDKey, + SubPath: accessKeyIDKey, + MountPath: accessKeyIDPath, + }, { + Name: secretAccessKeyKey, + SubPath: secretAccessKeyKey, + MountPath: secretAccessKeyPath, + }, { + Name: sessionTokenKey, + SubPath: sessionTokenKey, + MountPath: sessionTokenPath, + }}, + ImagePullPolicy: corev1.PullIfNotPresent, + }}, + Volumes: []corev1.Volume{{ + Name: internalSecretName, + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: rootSecretName, + DefaultMode: helpers.PointerInt32(defaultMode), + }, + }, + }, { + Name: accessKeyIDKey, + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: accessKeyIDName, + }, + }, + }, { + Name: secretAccessKeyKey, + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: secretAccessKeyName, + }, + }, + }, { + Name: sessionTokenKey, + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: sessionTokenName, + }, + }, + }}, + }, + }, + } + + assert.Equal(t, equals, getJobSpecDef( + nodeselector, + tolerations, + accessKeyIDName, + accessKeyIDKey, + secretAccessKeyName, + secretAccessKeyKey, + sessionTokenName, + sessionTokenKey, + backupName, + common.BackupImage.Reference("", version), + command, + )) +} diff --git a/operator/database/kinds/backups/s3/desired.go b/operator/database/kinds/backups/s3/desired.go new file mode 100644 index 000000000..e00a4ae51 --- /dev/null +++ b/operator/database/kinds/backups/s3/desired.go @@ -0,0 +1,65 @@ +package s3 + +import ( + "fmt" + + "github.com/caos/orbos/pkg/secret" + "github.com/caos/orbos/pkg/tree" +) + +type DesiredV0 struct { + Common *tree.Common `yaml:",inline"` + Spec *Spec +} + +type Spec struct { + Verbose bool + Cron string `yaml:"cron,omitempty"` + Bucket string `yaml:"bucket,omitempty"` + Endpoint string `yaml:"endpoint,omitempty"` + Region string `yaml:"region,omitempty"` + AccessKeyID *secret.Secret `yaml:"accessKeyID,omitempty"` + ExistingAccessKeyID *secret.Existing `yaml:"existingAccessKeyID,omitempty"` + SecretAccessKey *secret.Secret `yaml:"secretAccessKey,omitempty"` + ExistingSecretAccessKey *secret.Existing `yaml:"existingSecretAccessKey,omitempty"` + SessionToken *secret.Secret `yaml:"sessionToken,omitempty"` + ExistingSessionToken *secret.Existing `yaml:"existingSessionToken,omitempty"` +} + +func (s *Spec) IsZero() bool { + if ((s.AccessKeyID == nil || s.AccessKeyID.IsZero()) && (s.ExistingAccessKeyID == nil || s.ExistingAccessKeyID.IsZero())) && + ((s.SecretAccessKey == nil || s.SecretAccessKey.IsZero()) && (s.ExistingSecretAccessKey == nil || s.ExistingSecretAccessKey.IsZero())) && + ((s.SessionToken == nil || s.SessionToken.IsZero()) && (s.ExistingSessionToken == nil || s.ExistingSessionToken.IsZero())) && + !s.Verbose && + s.Bucket == "" && + s.Cron == "" && + s.Endpoint == "" && + s.Region == "" { + return true + } + return false +} + +func ParseDesiredV0(desiredTree *tree.Tree) (*DesiredV0, error) { + desiredKind := &DesiredV0{ + Common: desiredTree.Common, + Spec: &Spec{}, + } + + if err := desiredTree.Original.Decode(desiredKind); err != nil { + return nil, fmt.Errorf("parsing desired state failed: %s", err) + } + + return desiredKind, nil +} + +func (d *DesiredV0) validateSecrets() error { + if err := secret.ValidateSecret(d.Spec.AccessKeyID, d.Spec.ExistingAccessKeyID); err != nil { + return fmt.Errorf("validating access key id failed: %w", err) + } + if err := secret.ValidateSecret(d.Spec.SecretAccessKey, d.Spec.ExistingSecretAccessKey); err != nil { + return fmt.Errorf("validating secret access key failed: %w", err) + } + + return nil +} diff --git a/operator/database/kinds/backups/s3/desired_test.go b/operator/database/kinds/backups/s3/desired_test.go new file mode 100644 index 000000000..6b0899977 --- /dev/null +++ b/operator/database/kinds/backups/s3/desired_test.go @@ -0,0 +1,155 @@ +package s3 + +import ( + "github.com/caos/orbos/pkg/secret" + "github.com/caos/orbos/pkg/tree" + "github.com/stretchr/testify/assert" + "gopkg.in/yaml.v3" + "testing" +) + +const ( + masterkey = "testMk" + cron = "testCron" + bucketName = "testBucket" + region = "testRegion" + endpoint = "testEndpoint" + akid = "testAKID" + sak = "testSAK" + st = "testST" + yamlFile = `kind: databases.caos.ch/BucketBackup +version: v0 +spec: + verbose: true + cron: testCron + bucket: testBucket + region: testRegion + endpoint: testEndpoint + accessKeyID: + encryption: AES256 + encoding: Base64 + value: l7GEXvmCT8hBXereT4FIG4j5vKQIycjS + secretAccessKey: + encryption: AES256 + encoding: Base64 + value: NWYnOpFpME-9FESqWi0bFQ3M6e0iNQw= + sessionToken: + encryption: AES256 + encoding: Base64 + value: xVY9pEXuh0Wbf2P2X_yThXwqRX08sA== +` + + yamlFileWithoutSecret = `kind: databases.caos.ch/BucketBackup +version: v0 +spec: + verbose: true + cron: testCron + bucket: testBucket + endpoint: testEndpoint + region: testRegion +` + yamlEmpty = `kind: databases.caos.ch/BucketBackup +version: v0` +) + +var ( + desired = DesiredV0{ + Common: tree.NewCommon("databases.caos.ch/BucketBackup", "v0", false), + Spec: &Spec{ + Verbose: true, + Cron: cron, + Bucket: bucketName, + Endpoint: endpoint, + Region: region, + AccessKeyID: &secret.Secret{ + Value: akid, + Encryption: "AES256", + Encoding: "Base64", + }, + SecretAccessKey: &secret.Secret{ + Value: sak, + Encryption: "AES256", + Encoding: "Base64", + }, + SessionToken: &secret.Secret{ + Value: st, + Encryption: "AES256", + Encoding: "Base64", + }, + }, + } + desiredWithoutSecret = DesiredV0{ + Common: tree.NewCommon("databases.caos.ch/BucketBackup", "v0", false), + Spec: &Spec{ + Verbose: true, + Cron: cron, + Bucket: bucketName, + Region: region, + Endpoint: endpoint, + }, + } + desiredEmpty = DesiredV0{ + Common: tree.NewCommon("databases.caos.ch/BucketBackup", "v0", false), + Spec: &Spec{ + Verbose: false, + Cron: "", + Bucket: "", + Endpoint: "", + Region: "", + AccessKeyID: &secret.Secret{ + Value: "", + }, + SecretAccessKey: &secret.Secret{ + Value: "", + }, + SessionToken: &secret.Secret{ + Value: "", + }, + }, + } + + desiredNil = DesiredV0{ + Common: tree.NewCommon("databases.caos.ch/BucketBackup", "v0", false), + } +) + +func marshalYaml(t *testing.T, masterkey string, struc *DesiredV0) []byte { + secret.Masterkey = masterkey + data, err := yaml.Marshal(struc) + assert.NoError(t, err) + return data +} + +func unmarshalYaml(t *testing.T, masterkey string, yamlFile []byte) *tree.Tree { + secret.Masterkey = masterkey + desiredTree := &tree.Tree{} + assert.NoError(t, yaml.Unmarshal(yamlFile, desiredTree)) + return desiredTree +} + +func getDesiredTree(t *testing.T, masterkey string, desired *DesiredV0) *tree.Tree { + return unmarshalYaml(t, masterkey, marshalYaml(t, masterkey, desired)) +} + +func TestBucket_DesiredParse(t *testing.T) { + assert.Equal(t, yamlFileWithoutSecret, string(marshalYaml(t, masterkey, &desiredWithoutSecret))) + + desiredTree := unmarshalYaml(t, masterkey, []byte(yamlFile)) + desiredKind, err := ParseDesiredV0(desiredTree) + assert.NoError(t, err) + assert.Equal(t, &desired, desiredKind) +} + +func TestBucket_DesiredNotZero(t *testing.T) { + desiredTree := unmarshalYaml(t, masterkey, []byte(yamlFile)) + desiredKind, err := ParseDesiredV0(desiredTree) + assert.NoError(t, err) + assert.False(t, desiredKind.Spec.IsZero()) +} + +func TestBucket_DesiredZero(t *testing.T) { + desiredTree := unmarshalYaml(t, masterkey, []byte(yamlEmpty)) + desiredKind, err := ParseDesiredV0(desiredTree) + assert.NoError(t, err) + assert.True(t, desiredKind.Spec.IsZero()) +} diff --git a/operator/database/kinds/backups/s3/list.go b/operator/database/kinds/backups/s3/list.go new file mode 100644 index 000000000..8a7458412 --- /dev/null +++ b/operator/database/kinds/backups/s3/list.go @@ -0,0 +1,105 @@ +package s3 + +import ( + "context" + "fmt" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/credentials" + "github.com/aws/aws-sdk-go-v2/service/s3" + "github.com/caos/orbos/mntr" + "github.com/caos/orbos/pkg/kubernetes" + "github.com/caos/orbos/pkg/secret/read" + "github.com/caos/orbos/pkg/tree" + "github.com/caos/zitadel/operator/database/kinds/backups/core" + "strings" +) + +func BackupList() core.BackupListFunc { + return func(monitor mntr.Monitor, k8sClient kubernetes.ClientInt, name string, desired *tree.Tree) ([]string, error) { + desiredKind, err := ParseDesiredV0(desired) + if err != nil { + return nil, fmt.Errorf("parsing desired state failed: %s", err) + } + desired.Parsed = desiredKind + + if !monitor.IsVerbose() && desiredKind.Spec.Verbose { + monitor.Verbose() + } + + valueAKI, err := read.GetSecretValue(k8sClient, desiredKind.Spec.AccessKeyID, desiredKind.Spec.ExistingAccessKeyID) + if err != nil { + return nil, err + } + + valueSAK, err := read.GetSecretValue(k8sClient, desiredKind.Spec.SecretAccessKey, desiredKind.Spec.ExistingSecretAccessKey) + if err != nil { + return nil, err + } + + valueST, err := read.GetSecretValue(k8sClient, desiredKind.Spec.SessionToken, desiredKind.Spec.ExistingSessionToken) + if err != nil { + return nil, err + } + + return listFilesWithFilter(valueAKI, valueSAK, valueST, desiredKind.Spec.Region, desiredKind.Spec.Endpoint, desiredKind.Spec.Bucket, name) + } +} + +func listFilesWithFilter(akid, secretkey, sessionToken string, region string, endpoint string, bucketName, name string) ([]string, error) { + customResolver := aws.EndpointResolverFunc(func(service, region string) (aws.Endpoint, error) { + return aws.Endpoint{ + URL: "https://" + endpoint, + SigningRegion: region, + }, nil + }) + + cfg, err := config.LoadDefaultConfig( + context.Background(), + config.WithRegion(region), + config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider(akid, secretkey, sessionToken)), + config.WithEndpointResolver(customResolver), + ) + if err != nil { + return nil, err + } + + client := s3.NewFromConfig(cfg) + + prefix := name + "/" + params := &s3.ListObjectsV2Input{ + Bucket: aws.String(bucketName), + Prefix: aws.String(prefix), + } + paginator := s3.NewListObjectsV2Paginator(client, params, func(o *s3.ListObjectsV2PaginatorOptions) { + o.Limit = 10 + }) + + names := make([]string, 0) + for paginator.HasMorePages() { + output, err := paginator.NextPage(context.Background()) + if err != nil { + return nil, err + } + for _, value := range output.Contents { + if strings.HasPrefix(*value.Key, prefix) { + parts := strings.Split(*value.Key, "/") + if len(parts) < 2 { + continue + } + found := false + for _, name := range names { + if name == parts[1] { + found = true + } + } + if !found { + names = append(names, parts[1]) + } + names = append(names) + } + + } + } + return names, nil +} diff --git a/operator/database/kinds/backups/s3/mock.go b/operator/database/kinds/backups/s3/mock.go new file mode 100644 index 000000000..0e4e93e1a --- /dev/null +++ b/operator/database/kinds/backups/s3/mock.go @@ -0,0 +1,149 @@ +package s3 + +import ( + kubernetesmock "github.com/caos/orbos/pkg/kubernetes/mock" + "github.com/caos/zitadel/operator/database/kinds/backups/bucket/backup" + "github.com/caos/zitadel/operator/database/kinds/backups/bucket/restore" + "github.com/caos/zitadel/operator/database/kinds/databases/core" + "github.com/golang/mock/gomock" + corev1 "k8s.io/api/core/v1" + macherrs "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +func SetQueriedForDatabases(databases, users []string) map[string]interface{} { + queried := map[string]interface{}{} + core.SetQueriedForDatabaseDBList(queried, databases, users) + + return queried +} + +func SetInstantBackup( + k8sClient *kubernetesmock.MockClientInt, + namespace string, + backupName string, + labelsAKID map[string]string, + labelsSAK map[string]string, + labelsST map[string]string, + akid, sak, st string, +) { + k8sClient.EXPECT().ApplySecret(&corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: accessKeyIDName, + Namespace: namespace, + Labels: labelsAKID, + }, + StringData: map[string]string{accessKeyIDKey: akid}, + Type: "Opaque", + }).MinTimes(1).MaxTimes(1).Return(nil) + + k8sClient.EXPECT().ApplySecret(&corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: secretAccessKeyName, + Namespace: namespace, + Labels: labelsSAK, + }, + StringData: map[string]string{secretAccessKeyKey: sak}, + Type: "Opaque", + }).MinTimes(1).MaxTimes(1).Return(nil) + + k8sClient.EXPECT().ApplySecret(&corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: sessionTokenName, + Namespace: namespace, + Labels: labelsST, + }, + StringData: map[string]string{sessionTokenKey: st}, + Type: "Opaque", + }).MinTimes(1).MaxTimes(1).Return(nil) + + k8sClient.EXPECT().ApplyJob(gomock.Any()).Times(1).Return(nil) + k8sClient.EXPECT().GetJob(namespace, backup.GetJobName(backupName)).Times(1).Return(nil, macherrs.NewNotFound(schema.GroupResource{"batch", "jobs"}, backup.GetJobName(backupName))) + k8sClient.EXPECT().WaitUntilJobCompleted(namespace, backup.GetJobName(backupName), gomock.Any()).Times(1).Return(nil) + k8sClient.EXPECT().DeleteJob(namespace, backup.GetJobName(backupName)).Times(1).Return(nil) +} + +func SetBackup( + k8sClient *kubernetesmock.MockClientInt, + namespace string, + labelsAKID map[string]string, + labelsSAK map[string]string, + labelsST map[string]string, + akid, sak, st string, +) { + k8sClient.EXPECT().ApplySecret(&corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: accessKeyIDName, + Namespace: namespace, + Labels: labelsAKID, + }, + StringData: map[string]string{accessKeyIDKey: akid}, + Type: "Opaque", + }).MinTimes(1).MaxTimes(1).Return(nil) + + k8sClient.EXPECT().ApplySecret(&corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: secretAccessKeyName, + Namespace: namespace, + Labels: labelsSAK, + }, + StringData: map[string]string{secretAccessKeyKey: sak}, + Type: "Opaque", + }).MinTimes(1).MaxTimes(1).Return(nil) + + k8sClient.EXPECT().ApplySecret(&corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: sessionTokenName, + Namespace: namespace, + Labels: labelsST, + }, + StringData: map[string]string{sessionTokenKey: st}, + Type: "Opaque", + }).MinTimes(1).MaxTimes(1).Return(nil) + k8sClient.EXPECT().ApplyCronJob(gomock.Any()).Times(1).Return(nil) +} + +func SetRestore( + k8sClient *kubernetesmock.MockClientInt, + namespace string, + backupName string, + labelsAKID map[string]string, + labelsSAK map[string]string, + labelsST map[string]string, + akid, sak, st string, +) { + k8sClient.EXPECT().ApplySecret(&corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: accessKeyIDName, + Namespace: namespace, + Labels: labelsAKID, + }, + StringData: map[string]string{accessKeyIDKey: akid}, + Type: "Opaque", + }).MinTimes(1).MaxTimes(1).Return(nil) + + k8sClient.EXPECT().ApplySecret(&corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: secretAccessKeyName, + Namespace: namespace, + Labels: labelsSAK, + }, + StringData: map[string]string{secretAccessKeyKey: sak}, + Type: "Opaque", + }).MinTimes(1).MaxTimes(1).Return(nil) + + k8sClient.EXPECT().ApplySecret(&corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: sessionTokenName, + Namespace: namespace, + Labels: labelsST, + }, + StringData: map[string]string{sessionTokenKey: st}, + Type: "Opaque", + }).MinTimes(1).MaxTimes(1).Return(nil) + k8sClient.EXPECT().ApplyJob(gomock.Any()).Times(1).Return(nil) + k8sClient.EXPECT().GetJob(namespace, restore.GetJobName(backupName)).Times(1).Return(nil, macherrs.NewNotFound(schema.GroupResource{"batch", "jobs"}, restore.GetJobName(backupName))) + k8sClient.EXPECT().WaitUntilJobCompleted(namespace, restore.GetJobName(backupName), gomock.Any()).Times(1).Return(nil) + k8sClient.EXPECT().DeleteJob(namespace, restore.GetJobName(backupName)).Times(1).Return(nil) +} diff --git a/operator/database/kinds/backups/bucket/clean/adapt.go b/operator/database/kinds/backups/s3/restore/adapt.go similarity index 53% rename from operator/database/kinds/backups/bucket/clean/adapt.go rename to operator/database/kinds/backups/s3/restore/adapt.go index 66b741afb..9bf87648f 100644 --- a/operator/database/kinds/backups/bucket/clean/adapt.go +++ b/operator/database/kinds/backups/s3/restore/adapt.go @@ -1,4 +1,4 @@ -package clean +package restore import ( "time" @@ -13,15 +13,17 @@ import ( ) const ( - Instant = "clean" - defaultMode = int32(256) - certPath = "/cockroach/cockroach-certs" - secretPath = "/secrets/sa.json" - internalSecretName = "client-certs" - rootSecretName = "cockroachdb.client.root" - jobPrefix = "backup-" - jobSuffix = "-clean" - timeout = 60 * time.Second + Instant = "restore" + defaultMode = int32(256) + certPath = "/cockroach/cockroach-certs" + accessKeyIDPath = "/secrets/accessaccountkey" + secretAccessKeyPath = "/secrets/secretaccesskey" + sessionTokenPath = "/secrets/sessiontoken" + jobPrefix = "backup-" + jobSuffix = "-restore" + internalSecretName = "client-certs" + rootSecretName = "cockroachdb.client.root" + timeout = 15 * time.Minute ) func AdaptFunc( @@ -29,13 +31,21 @@ func AdaptFunc( backupName string, namespace string, componentLabels *labels.Component, - databases []string, - users []string, + bucketName string, + timestamp string, + accessKeyIDName string, + accessKeyIDKey string, + secretAccessKeyName string, + secretAccessKeyKey string, + sessionTokenName string, + sessionTokenKey string, + region string, + endpoint string, nodeselector map[string]string, tolerations []corev1.Toleration, checkDBReady operator.EnsureFunc, - secretName string, - secretKey string, + dbURL string, + dbPort int32, image string, ) ( queryFunc operator.QueryFunc, @@ -43,20 +53,37 @@ func AdaptFunc( err error, ) { - command := getCommand(databases, users) + jobName := jobPrefix + backupName + jobSuffix + command := getCommand( + timestamp, + bucketName, + backupName, + certPath, + accessKeyIDPath, + secretAccessKeyPath, + sessionTokenPath, + region, + endpoint, + dbURL, + dbPort, + ) - jobDef := getJob( + jobdef := getJob( namespace, labels.MustForName(componentLabels, GetJobName(backupName)), nodeselector, tolerations, - secretName, - secretKey, - command, + accessKeyIDName, + accessKeyIDKey, + secretAccessKeyName, + secretAccessKeyKey, + sessionTokenName, + sessionTokenKey, image, + command, ) - destroyJ, err := job.AdaptFuncToDestroy(jobDef.Namespace, jobDef.Name) + destroyJ, err := job.AdaptFuncToDestroy(jobName, namespace) if err != nil { return nil, nil, err } @@ -65,7 +92,7 @@ func AdaptFunc( operator.ResourceDestroyToZitadelDestroy(destroyJ), } - queryJ, err := job.AdaptFuncToEnsure(jobDef) + queryJ, err := job.AdaptFuncToEnsure(jobdef) if err != nil { return nil, nil, err } @@ -79,6 +106,7 @@ func AdaptFunc( return operator.QueriersToEnsureFunc(monitor, false, queriers, k8sClient, queried) }, operator.DestroyersToDestroyFunc(monitor, destroyers), + nil } diff --git a/operator/database/kinds/backups/bucket/clean/adapt_test.go b/operator/database/kinds/backups/s3/restore/adapt_test.go similarity index 59% rename from operator/database/kinds/backups/bucket/clean/adapt_test.go rename to operator/database/kinds/backups/s3/restore/adapt_test.go index 7339e022d..cd14d1f5e 100644 --- a/operator/database/kinds/backups/bucket/clean/adapt_test.go +++ b/operator/database/kinds/backups/s3/restore/adapt_test.go @@ -1,6 +1,7 @@ -package clean +package restore import ( + "github.com/caos/zitadel/operator/common" "testing" "github.com/caos/orbos/mntr" @@ -19,15 +20,23 @@ func TestBackup_Adapt1(t *testing.T) { monitor := mntr.Monitor{} namespace := "testNs" - databases := []string{"testDb"} - users := []string{"testUser"} nodeselector := map[string]string{"test": "test"} tolerations := []corev1.Toleration{ {Key: "testKey", Operator: "testOp"}} - backupName := "testName" - image := "testImage" - secretKey := "testKey" - secretName := "testSecretName" + timestamp := "testTs" + backupName := "testName2" + bucketName := "testBucket2" + version := "testVersion" + accessKeyIDName := "testAKIN" + accessKeyIDKey := "testAKIK" + secretAccessKeyName := "testSAKN" + secretAccessKeyKey := "testSAKK" + sessionTokenName := "testSTN" + sessionTokenKey := "testSTK" + region := "region" + endpoint := "endpoint" + dbURL := "testDB" + dbPort := int32(80) jobName := GetJobName(backupName) componentLabels := labels.MustForComponent(labels.MustForAPI(labels.MustForOperator("testProd", "testOp", "testVersion"), "testKind", "testVersion"), "testComponent") nameLabels := labels.MustForName(componentLabels, jobName) @@ -41,13 +50,26 @@ func TestBackup_Adapt1(t *testing.T) { nameLabels, nodeselector, tolerations, - secretName, - secretKey, + accessKeyIDName, + accessKeyIDKey, + secretAccessKeyName, + secretAccessKeyKey, + sessionTokenName, + sessionTokenKey, + common.BackupImage.Reference("", version), getCommand( - databases, - users, + timestamp, + bucketName, + backupName, + certPath, + accessKeyIDPath, + secretAccessKeyPath, + sessionTokenPath, + region, + endpoint, + dbURL, + dbPort, ), - image, ) client.EXPECT().ApplyJob(jobDef).Times(1).Return(nil) @@ -58,14 +80,22 @@ func TestBackup_Adapt1(t *testing.T) { backupName, namespace, componentLabels, - databases, - users, + bucketName, + timestamp, + accessKeyIDName, + accessKeyIDKey, + secretAccessKeyName, + secretAccessKeyKey, + sessionTokenName, + sessionTokenKey, + region, + endpoint, nodeselector, tolerations, checkDBReady, - secretName, - secretKey, - image, + dbURL, + dbPort, + common.BackupImage.Reference("", version), ) assert.NoError(t, err) @@ -80,15 +110,23 @@ func TestBackup_Adapt2(t *testing.T) { monitor := mntr.Monitor{} namespace := "testNs2" - databases := []string{"testDb1", "testDb2"} - users := []string{"testUser1", "testUser2"} nodeselector := map[string]string{"test2": "test2"} tolerations := []corev1.Toleration{ {Key: "testKey2", Operator: "testOp2"}} + timestamp := "testTs" backupName := "testName2" - image := "testImage2" - secretKey := "testKey2" - secretName := "testSecretName2" + bucketName := "testBucket2" + version := "testVersion2" + accessKeyIDName := "testAKIN2" + accessKeyIDKey := "testAKIK2" + secretAccessKeyName := "testSAKN2" + secretAccessKeyKey := "testSAKK2" + sessionTokenName := "testSTN2" + sessionTokenKey := "testSTK2" + region := "region2" + endpoint := "endpoint2" + dbURL := "testDB" + dbPort := int32(80) jobName := GetJobName(backupName) componentLabels := labels.MustForComponent(labels.MustForAPI(labels.MustForOperator("testProd2", "testOp2", "testVersion2"), "testKind2", "testVersion2"), "testComponent2") nameLabels := labels.MustForName(componentLabels, jobName) @@ -102,13 +140,26 @@ func TestBackup_Adapt2(t *testing.T) { nameLabels, nodeselector, tolerations, - secretName, - secretKey, + accessKeyIDName, + accessKeyIDKey, + secretAccessKeyName, + secretAccessKeyKey, + sessionTokenName, + sessionTokenKey, + common.BackupImage.Reference("", version), getCommand( - databases, - users, + timestamp, + bucketName, + backupName, + certPath, + accessKeyIDPath, + secretAccessKeyPath, + sessionTokenPath, + region, + endpoint, + dbURL, + dbPort, ), - image, ) client.EXPECT().ApplyJob(jobDef).Times(1).Return(nil) @@ -119,14 +170,22 @@ func TestBackup_Adapt2(t *testing.T) { backupName, namespace, componentLabels, - databases, - users, + bucketName, + timestamp, + accessKeyIDName, + accessKeyIDKey, + secretAccessKeyName, + secretAccessKeyKey, + sessionTokenName, + sessionTokenKey, + region, + endpoint, nodeselector, tolerations, checkDBReady, - secretName, - secretKey, - image, + dbURL, + dbPort, + common.BackupImage.Reference("", version), ) assert.NoError(t, err) diff --git a/operator/database/kinds/backups/s3/restore/cleanup.go b/operator/database/kinds/backups/s3/restore/cleanup.go new file mode 100644 index 000000000..252fddb4b --- /dev/null +++ b/operator/database/kinds/backups/s3/restore/cleanup.go @@ -0,0 +1,27 @@ +package restore + +import ( + "fmt" + "github.com/caos/orbos/mntr" + "github.com/caos/orbos/pkg/kubernetes" + "github.com/caos/zitadel/operator" +) + +func GetCleanupFunc( + monitor mntr.Monitor, + namespace, + backupName string, +) operator.EnsureFunc { + return func(k8sClient kubernetes.ClientInt) error { + monitor.Info("waiting for restore to be completed") + if err := k8sClient.WaitUntilJobCompleted(namespace, GetJobName(backupName), timeout); err != nil { + return fmt.Errorf("error while waiting for restore to be completed: %s", err.Error()) + } + monitor.Info("restore is completed, cleanup") + if err := k8sClient.DeleteJob(namespace, GetJobName(backupName)); err != nil { + return fmt.Errorf("error while trying to cleanup restore: %s", err.Error()) + } + monitor.Info("restore cleanup is completed") + return nil + } +} diff --git a/operator/database/kinds/backups/bucket/clean/cleanup_test.go b/operator/database/kinds/backups/s3/restore/cleanup_test.go similarity index 98% rename from operator/database/kinds/backups/bucket/clean/cleanup_test.go rename to operator/database/kinds/backups/s3/restore/cleanup_test.go index 533e77708..81671b1f3 100644 --- a/operator/database/kinds/backups/bucket/clean/cleanup_test.go +++ b/operator/database/kinds/backups/s3/restore/cleanup_test.go @@ -1,14 +1,12 @@ -package clean +package restore import ( "errors" - "testing" - - "github.com/golang/mock/gomock" - "github.com/stretchr/testify/assert" - "github.com/caos/orbos/mntr" kubernetesmock "github.com/caos/orbos/pkg/kubernetes/mock" + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/assert" + "testing" ) func TestBackup_Cleanup1(t *testing.T) { diff --git a/operator/database/kinds/backups/s3/restore/command.go b/operator/database/kinds/backups/s3/restore/command.go new file mode 100644 index 000000000..d739b7015 --- /dev/null +++ b/operator/database/kinds/backups/s3/restore/command.go @@ -0,0 +1,48 @@ +package restore + +import ( + "strconv" + "strings" +) + +func getCommand( + timestamp string, + bucketName string, + backupName string, + certsFolder string, + accessKeyIDPath string, + secretAccessKeyPath string, + sessionTokenPath string, + region string, + endpoint string, + dbURL string, + dbPort int32, +) string { + + backupCommands := make([]string, 0) + + parameters := []string{ + "AWS_ACCESS_KEY_ID=$(cat " + accessKeyIDPath + ")", + "AWS_SECRET_ACCESS_KEY=$(cat " + secretAccessKeyPath + ")", + "AWS_SESSION_TOKEN=$(cat " + sessionTokenPath + ")", + "AWS_ENDPOINT=" + endpoint, + } + if region != "" { + parameters = append(parameters, "AWS_REGION="+region) + } + + backupCommands = append(backupCommands, + strings.Join([]string{ + "cockroach", + "sql", + "--certs-dir=" + certsFolder, + "--host=" + dbURL, + "--port=" + strconv.Itoa(int(dbPort)), + "-e", + "\"RESTORE FROM \\\"s3://" + bucketName + "/" + backupName + "/" + timestamp + "?" + strings.Join(parameters, "&") + "\\\";\"", + }, " ", + ), + ) + + return strings.Join(backupCommands, " && ") +} diff --git a/operator/database/kinds/backups/s3/restore/command_test.go b/operator/database/kinds/backups/s3/restore/command_test.go new file mode 100644 index 000000000..c8740b267 --- /dev/null +++ b/operator/database/kinds/backups/s3/restore/command_test.go @@ -0,0 +1,59 @@ +package restore + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func TestBackup_Command1(t *testing.T) { + timestamp := "test1" + bucketName := "testBucket" + backupName := "testBackup" + dbURL := "testDB" + dbPort := int32(80) + region := "region" + endpoint := "endpoint" + + cmd := getCommand( + timestamp, + bucketName, + backupName, + certPath, + accessKeyIDPath, + secretAccessKeyPath, + sessionTokenPath, + region, + endpoint, + dbURL, + dbPort, + ) + + equals := "cockroach sql --certs-dir=" + certPath + " --host=testDB --port=80 -e \"RESTORE FROM \\\"s3://testBucket/testBackup/test1?AWS_ACCESS_KEY_ID=$(cat " + accessKeyIDPath + ")&AWS_SECRET_ACCESS_KEY=$(cat " + secretAccessKeyPath + ")&AWS_SESSION_TOKEN=$(cat " + sessionTokenPath + ")&AWS_ENDPOINT=endpoint&AWS_REGION=region\\\";\"" + assert.Equal(t, equals, cmd) +} + +func TestBackup_Command2(t *testing.T) { + timestamp := "test2" + bucketName := "testBucket" + backupName := "testBackup" + dbURL := "testDB2" + dbPort := int32(81) + region := "region2" + endpoint := "endpoint2" + + cmd := getCommand( + timestamp, + bucketName, + backupName, + certPath, + accessKeyIDPath, + secretAccessKeyPath, + sessionTokenPath, + region, + endpoint, + dbURL, + dbPort, + ) + equals := "cockroach sql --certs-dir=" + certPath + " --host=testDB2 --port=81 -e \"RESTORE FROM \\\"s3://testBucket/testBackup/test2?AWS_ACCESS_KEY_ID=$(cat " + accessKeyIDPath + ")&AWS_SECRET_ACCESS_KEY=$(cat " + secretAccessKeyPath + ")&AWS_SESSION_TOKEN=$(cat " + sessionTokenPath + ")&AWS_ENDPOINT=endpoint2&AWS_REGION=region2\\\";\"" + assert.Equal(t, equals, cmd) +} diff --git a/operator/database/kinds/backups/bucket/clean/job.go b/operator/database/kinds/backups/s3/restore/job.go similarity index 59% rename from operator/database/kinds/backups/bucket/clean/job.go rename to operator/database/kinds/backups/s3/restore/job.go index de753259b..7942b6ab4 100644 --- a/operator/database/kinds/backups/bucket/clean/job.go +++ b/operator/database/kinds/backups/s3/restore/job.go @@ -1,4 +1,4 @@ -package clean +package restore import ( "github.com/caos/orbos/pkg/labels" @@ -13,12 +13,16 @@ func getJob( nameLabels *labels.Name, nodeselector map[string]string, tolerations []corev1.Toleration, - secretName string, - secretKey string, - command string, + accessKeyIDName string, + accessKeyIDKey string, + secretAccessKeyName string, + secretAccessKeyKey string, + sessionTokenName string, + sessionTokenKey string, image string, -) *batchv1.Job { + command string, +) *batchv1.Job { return &batchv1.Job{ ObjectMeta: v1.ObjectMeta{ Name: nameLabels.Name(), @@ -43,11 +47,19 @@ func getJob( Name: internalSecretName, MountPath: certPath, }, { - Name: secretKey, - SubPath: secretKey, - MountPath: secretPath, + Name: accessKeyIDKey, + SubPath: accessKeyIDKey, + MountPath: accessKeyIDPath, + }, { + Name: secretAccessKeyKey, + SubPath: secretAccessKeyKey, + MountPath: secretAccessKeyPath, + }, { + Name: sessionTokenKey, + SubPath: sessionTokenKey, + MountPath: sessionTokenPath, }}, - ImagePullPolicy: corev1.PullAlways, + ImagePullPolicy: corev1.PullIfNotPresent, }}, Volumes: []corev1.Volume{{ Name: internalSecretName, @@ -58,10 +70,24 @@ func getJob( }, }, }, { - Name: secretKey, + Name: accessKeyIDKey, VolumeSource: corev1.VolumeSource{ Secret: &corev1.SecretVolumeSource{ - SecretName: secretName, + SecretName: accessKeyIDName, + }, + }, + }, { + Name: secretAccessKeyKey, + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: secretAccessKeyName, + }, + }, + }, { + Name: sessionTokenKey, + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: sessionTokenName, }, }, }}, @@ -69,5 +95,4 @@ func getJob( }, }, } - } diff --git a/operator/database/kinds/backups/bucket/clean/job_test.go b/operator/database/kinds/backups/s3/restore/job_test.go similarity index 60% rename from operator/database/kinds/backups/bucket/clean/job_test.go rename to operator/database/kinds/backups/s3/restore/job_test.go index 8ad27a39a..8bbe1c301 100644 --- a/operator/database/kinds/backups/bucket/clean/job_test.go +++ b/operator/database/kinds/backups/s3/restore/job_test.go @@ -1,27 +1,29 @@ -package clean +package restore import ( - "testing" - "github.com/caos/orbos/pkg/labels" "github.com/caos/zitadel/operator/helpers" "github.com/stretchr/testify/assert" batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "testing" ) func TestBackup_Job1(t *testing.T) { nodeselector := map[string]string{"test": "test"} tolerations := []corev1.Toleration{ {Key: "testKey", Operator: "testOp"}} + image := "testVersion" command := "test" - secretKey := "testKey" - secretName := "testSecretName" + accessKeyIDName := "testAKIN" + accessKeyIDKey := "testAKIK" + secretAccessKeyName := "testSAKN" + secretAccessKeyKey := "testSAKK" + sessionTokenName := "testSTN" + sessionTokenKey := "testSTK" jobName := "testJob" namespace := "testNs" - image := "testImage" - k8sLabels := map[string]string{ "app.kubernetes.io/component": "testComponent", "app.kubernetes.io/managed-by": "testOp", @@ -58,11 +60,19 @@ func TestBackup_Job1(t *testing.T) { Name: internalSecretName, MountPath: certPath, }, { - Name: secretKey, - SubPath: secretKey, - MountPath: secretPath, + Name: accessKeyIDKey, + SubPath: accessKeyIDKey, + MountPath: accessKeyIDPath, + }, { + Name: secretAccessKeyKey, + SubPath: secretAccessKeyKey, + MountPath: secretAccessKeyPath, + }, { + Name: sessionTokenKey, + SubPath: sessionTokenKey, + MountPath: sessionTokenPath, }}, - ImagePullPolicy: corev1.PullAlways, + ImagePullPolicy: corev1.PullIfNotPresent, }}, Volumes: []corev1.Volume{{ Name: internalSecretName, @@ -73,10 +83,24 @@ func TestBackup_Job1(t *testing.T) { }, }, }, { - Name: secretKey, + Name: accessKeyIDKey, VolumeSource: corev1.VolumeSource{ Secret: &corev1.SecretVolumeSource{ - SecretName: secretName, + SecretName: accessKeyIDName, + }, + }, + }, { + Name: secretAccessKeyKey, + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: secretAccessKeyName, + }, + }, + }, { + Name: sessionTokenKey, + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: sessionTokenName, }, }, }}, @@ -85,19 +109,36 @@ func TestBackup_Job1(t *testing.T) { }, } - assert.Equal(t, equals, getJob(namespace, nameLabels, nodeselector, tolerations, secretName, secretKey, command, image)) + assert.Equal(t, equals, getJob( + namespace, + nameLabels, + nodeselector, + tolerations, + accessKeyIDName, + accessKeyIDKey, + secretAccessKeyName, + secretAccessKeyKey, + sessionTokenName, + sessionTokenKey, + image, + command, + )) } func TestBackup_Job2(t *testing.T) { nodeselector := map[string]string{"test2": "test2"} tolerations := []corev1.Toleration{ {Key: "testKey2", Operator: "testOp2"}} + image := "testVersion2" command := "test2" - secretKey := "testKey2" - secretName := "testSecretName2" + accessKeyIDName := "testAKIN2" + accessKeyIDKey := "testAKIK2" + secretAccessKeyName := "testSAKN2" + secretAccessKeyKey := "testSAKK2" + sessionTokenName := "testSTN2" + sessionTokenKey := "testSTK2" jobName := "testJob2" namespace := "testNs2" - image := "testImage2" k8sLabels := map[string]string{ "app.kubernetes.io/component": "testComponent2", "app.kubernetes.io/managed-by": "testOp2", @@ -134,11 +175,19 @@ func TestBackup_Job2(t *testing.T) { Name: internalSecretName, MountPath: certPath, }, { - Name: secretKey, - SubPath: secretKey, - MountPath: secretPath, + Name: accessKeyIDKey, + SubPath: accessKeyIDKey, + MountPath: accessKeyIDPath, + }, { + Name: secretAccessKeyKey, + SubPath: secretAccessKeyKey, + MountPath: secretAccessKeyPath, + }, { + Name: sessionTokenKey, + SubPath: sessionTokenKey, + MountPath: sessionTokenPath, }}, - ImagePullPolicy: corev1.PullAlways, + ImagePullPolicy: corev1.PullIfNotPresent, }}, Volumes: []corev1.Volume{{ Name: internalSecretName, @@ -149,10 +198,24 @@ func TestBackup_Job2(t *testing.T) { }, }, }, { - Name: secretKey, + Name: accessKeyIDKey, VolumeSource: corev1.VolumeSource{ Secret: &corev1.SecretVolumeSource{ - SecretName: secretName, + SecretName: accessKeyIDName, + }, + }, + }, { + Name: secretAccessKeyKey, + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: secretAccessKeyName, + }, + }, + }, { + Name: sessionTokenKey, + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: sessionTokenName, }, }, }}, @@ -161,5 +224,17 @@ func TestBackup_Job2(t *testing.T) { }, } - assert.Equal(t, equals, getJob(namespace, nameLabels, nodeselector, tolerations, secretName, secretKey, command, image)) + assert.Equal(t, equals, getJob( + namespace, + nameLabels, + nodeselector, + tolerations, + accessKeyIDName, + accessKeyIDKey, + secretAccessKeyName, + secretAccessKeyKey, + sessionTokenName, + sessionTokenKey, + image, + command)) } diff --git a/operator/database/kinds/backups/s3/secrets.go b/operator/database/kinds/backups/s3/secrets.go new file mode 100644 index 000000000..809e09a17 --- /dev/null +++ b/operator/database/kinds/backups/s3/secrets.go @@ -0,0 +1,54 @@ +package s3 + +import ( + "github.com/caos/orbos/pkg/secret" +) + +func getSecretsMap(desiredKind *DesiredV0) (map[string]*secret.Secret, map[string]*secret.Existing) { + + var ( + secrets = make(map[string]*secret.Secret, 0) + existing = make(map[string]*secret.Existing, 0) + ) + if desiredKind.Spec == nil { + desiredKind.Spec = &Spec{} + } + + if desiredKind.Spec.AccessKeyID == nil { + desiredKind.Spec.AccessKeyID = &secret.Secret{} + } + + if desiredKind.Spec.ExistingAccessKeyID == nil { + desiredKind.Spec.ExistingAccessKeyID = &secret.Existing{} + } + + akikey := "accesskeyid" + secrets[akikey] = desiredKind.Spec.AccessKeyID + existing[akikey] = desiredKind.Spec.ExistingAccessKeyID + + if desiredKind.Spec.SecretAccessKey == nil { + desiredKind.Spec.SecretAccessKey = &secret.Secret{} + } + + if desiredKind.Spec.ExistingSecretAccessKey == nil { + desiredKind.Spec.ExistingSecretAccessKey = &secret.Existing{} + } + + sakkey := "secretaccesskey" + secrets[sakkey] = desiredKind.Spec.SecretAccessKey + existing[sakkey] = desiredKind.Spec.ExistingSecretAccessKey + + if desiredKind.Spec.SessionToken == nil { + desiredKind.Spec.SessionToken = &secret.Secret{} + } + + if desiredKind.Spec.ExistingSessionToken == nil { + desiredKind.Spec.ExistingSessionToken = &secret.Existing{} + } + + stkey := "sessiontoken" + secrets[stkey] = desiredKind.Spec.SessionToken + existing[stkey] = desiredKind.Spec.ExistingSessionToken + + return secrets, existing +} diff --git a/operator/database/kinds/backups/s3/secrets_test.go b/operator/database/kinds/backups/s3/secrets_test.go new file mode 100644 index 000000000..ada753df7 --- /dev/null +++ b/operator/database/kinds/backups/s3/secrets_test.go @@ -0,0 +1,38 @@ +package s3 + +import ( + "testing" + + "github.com/caos/orbos/pkg/secret" + "github.com/stretchr/testify/assert" +) + +func TestBucket_getSecretsFull(t *testing.T) { + secrets, existing := getSecretsMap(&desired) + assert.Equal(t, desired.Spec.AccessKeyID, secrets["accesskeyid"]) + assert.Equal(t, desired.Spec.ExistingAccessKeyID, existing["accesskeyid"]) + assert.Equal(t, desired.Spec.SecretAccessKey, secrets["secretaccesskey"]) + assert.Equal(t, desired.Spec.ExistingSecretAccessKey, existing["secretaccesskey"]) + assert.Equal(t, desired.Spec.SessionToken, secrets["sessiontoken"]) + assert.Equal(t, desired.Spec.ExistingSessionToken, existing["sessiontoken"]) +} + +func TestBucket_getSecretsEmpty(t *testing.T) { + secrets, existing := getSecretsMap(&desiredWithoutSecret) + assert.Equal(t, &secret.Secret{}, secrets["accesskeyid"]) + assert.Equal(t, &secret.Existing{}, existing["accesskeyid"]) + assert.Equal(t, &secret.Secret{}, secrets["secretaccesskey"]) + assert.Equal(t, &secret.Existing{}, existing["secretaccesskey"]) + assert.Equal(t, &secret.Secret{}, secrets["sessiontoken"]) + assert.Equal(t, &secret.Existing{}, existing["sessiontoken"]) +} + +func TestBucket_getSecretsNil(t *testing.T) { + secrets, existing := getSecretsMap(&desiredNil) + assert.Equal(t, &secret.Secret{}, secrets["accesskeyid"]) + assert.Equal(t, &secret.Existing{}, existing["accesskeyid"]) + assert.Equal(t, &secret.Secret{}, secrets["secretaccesskey"]) + assert.Equal(t, &secret.Existing{}, existing["secretaccesskey"]) + assert.Equal(t, &secret.Secret{}, secrets["sessiontoken"]) + assert.Equal(t, &secret.Existing{}, existing["sessiontoken"]) +} diff --git a/operator/database/kinds/databases/databases.go b/operator/database/kinds/databases/databases.go index 3f20628b7..7c6c26d9b 100644 --- a/operator/database/kinds/databases/databases.go +++ b/operator/database/kinds/databases/databases.go @@ -10,7 +10,6 @@ import ( "github.com/caos/orbos/pkg/labels" "github.com/caos/orbos/pkg/secret" "github.com/caos/orbos/pkg/tree" - "github.com/caos/zitadel/operator" "github.com/caos/zitadel/operator/database/kinds/databases/managed" "github.com/caos/zitadel/operator/database/kinds/databases/provided" @@ -50,16 +49,7 @@ func Adapt( switch desiredTree.Common.Kind { case "databases.caos.ch/CockroachDB": - return managed.Adapter( - componentLabels, - namespace, - timestamp, - nodeselector, - tolerations, - version, - features, - customImageRegistry, - )(internalMonitor, desiredTree, currentTree) + return managed.Adapter(componentLabels, namespace, timestamp, nodeselector, tolerations, version, features, customImageRegistry)(internalMonitor, desiredTree, currentTree) case "databases.caos.ch/ProvidedDatabase": return provided.Adapter()(internalMonitor, desiredTree, currentTree) default: diff --git a/operator/database/kinds/databases/managed/adapt.go b/operator/database/kinds/databases/managed/adapt.go index 6deabf5ee..caf2eb81b 100644 --- a/operator/database/kinds/databases/managed/adapt.go +++ b/operator/database/kinds/databases/managed/adapt.go @@ -33,6 +33,8 @@ const ( privateServiceName = SfsName cockroachPort = int32(26257) cockroachHTTPPort = int32(8080) + Clean = "clean" + DBReady = "dbready" ) func Adapter( @@ -89,14 +91,14 @@ func Adapter( var ( isFeatureDatabase bool - isFeatureRestore bool + isFeatureClean bool ) for _, feature := range features { switch feature { case "database": isFeatureDatabase = true - case "restore": - isFeatureRestore = true + case Clean: + isFeatureClean = true } } @@ -179,9 +181,6 @@ func Adapter( queryS, operator.EnsureFuncToQueryFunc(ensureInit), ) - } - - if isFeatureDatabase { destroyers = append(destroyers, destroyS, operator.ResourceDestroyToZitadelDestroy(destroySFS), @@ -191,6 +190,21 @@ func Adapter( ) } + if isFeatureClean { + queriers = append(queriers, + operator.ResourceQueryToZitadelQuery( + statefulset.CleanPVCs( + monitor, + namespace, + cockroachSelectabel, + desiredKind.Spec.ReplicaCount, + ), + ), + operator.EnsureFuncToQueryFunc(ensureInit), + operator.EnsureFuncToQueryFunc(checkDBReady), + ) + } + if desiredKind.Spec.Backups != nil { oneBackup := false @@ -215,6 +229,8 @@ func Adapter( nodeselector, tolerations, version, + PublicServiceName, + cockroachPort, features, customImageRegistry, ) @@ -233,21 +249,19 @@ func Adapter( } return func(k8sClient kubernetes.ClientInt, queried map[string]interface{}) (operator.EnsureFunc, error) { - if !isFeatureRestore { - queriedCurrentDB, err := core.ParseQueriedForDatabase(queried) - if err != nil || queriedCurrentDB == nil { - // TODO: query system state - currentDB.Current.Port = strconv.Itoa(int(cockroachPort)) - currentDB.Current.URL = PublicServiceName - currentDB.Current.ReadyFunc = checkDBReady - currentDB.Current.AddUserFunc = addUser - currentDB.Current.DeleteUserFunc = deleteUser - currentDB.Current.ListUsersFunc = listUsers - currentDB.Current.ListDatabasesFunc = listDatabases + queriedCurrentDB, err := core.ParseQueriedForDatabase(queried) + if err != nil || queriedCurrentDB == nil { + // TODO: query system state + currentDB.Current.Port = strconv.Itoa(int(cockroachPort)) + currentDB.Current.URL = PublicServiceName + currentDB.Current.ReadyFunc = checkDBReady + currentDB.Current.AddUserFunc = addUser + currentDB.Current.DeleteUserFunc = deleteUser + currentDB.Current.ListUsersFunc = listUsers + currentDB.Current.ListDatabasesFunc = listDatabases - core.SetQueriedForDatabase(queried, current) - internalMonitor.Info("set current state of managed database") - } + core.SetQueriedForDatabase(queried, current) + internalMonitor.Info("set current state of managed database") } ensure, err := operator.QueriersToEnsureFunc(internalMonitor, true, queriers, k8sClient, queried) diff --git a/operator/database/kinds/databases/managed/adapt_backup_test.go b/operator/database/kinds/databases/managed/adapt_backup_test.go index 5a2e33bc0..1ee1ef610 100644 --- a/operator/database/kinds/databases/managed/adapt_backup_test.go +++ b/operator/database/kinds/databases/managed/adapt_backup_test.go @@ -11,7 +11,6 @@ import ( "github.com/caos/orbos/pkg/tree" "github.com/caos/zitadel/operator/database/kinds/backups/bucket" "github.com/caos/zitadel/operator/database/kinds/backups/bucket/backup" - "github.com/caos/zitadel/operator/database/kinds/backups/bucket/clean" "github.com/caos/zitadel/operator/database/kinds/backups/bucket/restore" "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" @@ -66,11 +65,11 @@ func TestManaged_AdaptBucketBackup(t *testing.T) { timestamp := "testTs" nodeselector := map[string]string{"test": "test"} tolerations := []corev1.Toleration{} - version := "testVersion" k8sClient := kubernetesmock.NewMockClientInt(gomock.NewController(t)) backupName := "testBucket" saJson := "testSA" masterkey := "testMk" + version := "test" desired := getTreeWithDBAndBackup(t, masterkey, saJson, backupName) @@ -106,11 +105,11 @@ func TestManaged_AdaptBucketInstantBackup(t *testing.T) { timestamp := "testTs" nodeselector := map[string]string{"test": "test"} tolerations := []corev1.Toleration{} - version := "testVersion" masterkey := "testMk" k8sClient := kubernetesmock.NewMockClientInt(gomock.NewController(t)) saJson := "testSA" backupName := "testBucket" + version := "test" features := []string{backup.Instant} bucket.SetInstantBackup(k8sClient, namespace, backupName, labels, saJson) @@ -152,10 +151,10 @@ func TestManaged_AdaptBucketCleanAndRestore(t *testing.T) { saJson := "testSA" backupName := "testBucket" - features := []string{restore.Instant, clean.Instant} + features := []string{restore.Instant} bucket.SetRestore(k8sClient, namespace, backupName, labels, saJson) - bucket.SetClean(k8sClient, namespace, backupName, labels, saJson) - k8sClient.EXPECT().WaitUntilStatefulsetIsReady(namespace, SfsName, true, true, 60*time.Second).Times(2) + //SetClean(k8sClient, namespace, 1) + k8sClient.EXPECT().WaitUntilStatefulsetIsReady(namespace, SfsName, true, true, 60*time.Second).Times(1) desired := getTreeWithDBAndBackup(t, masterkey, saJson, backupName) diff --git a/operator/database/kinds/databases/managed/adapt_test.go b/operator/database/kinds/databases/managed/adapt_test.go index 4b730f143..5b6a1a826 100644 --- a/operator/database/kinds/databases/managed/adapt_test.go +++ b/operator/database/kinds/databases/managed/adapt_test.go @@ -66,12 +66,12 @@ func TestManaged_Adapt1(t *testing.T) { timestamp := "testTs" nodeselector := map[string]string{"test": "test"} tolerations := []corev1.Toleration{} - version := "testVersion" features := []string{"database"} masterkey := "testMk" k8sClient := kubernetesmock.NewMockClientInt(gomock.NewController(t)) dbCurrent := coremock.NewMockDatabaseCurrent(gomock.NewController(t)) queried := map[string]interface{}{} + version := "test" desired := getDesiredTree(t, masterkey, &DesiredV0{ Common: tree.NewCommon("databases.caos.ch/CockroachDB", "v0", false), @@ -130,16 +130,7 @@ func TestManaged_Adapt1(t *testing.T) { dbCurrent.EXPECT().SetCertificateKey(gomock.Any()).MinTimes(1).MaxTimes(1) k8sClient.EXPECT().ApplySecret(gomock.Any()).MinTimes(1).MaxTimes(1) - query, _, _, _, _, _, err := Adapter( - componentLabels, - namespace, - timestamp, - nodeselector, - tolerations, - version, - features, - "", - )(monitor, desired, &tree.Tree{}) + query, _, _, _, _, _, err := Adapter(componentLabels, namespace, timestamp, nodeselector, tolerations, version, features, "")(monitor, desired, &tree.Tree{}) assert.NoError(t, err) ensure, err := query(k8sClient, queried) @@ -184,12 +175,12 @@ func TestManaged_Adapt2(t *testing.T) { nodeselector := map[string]string{"test2": "test2"} var tolerations []corev1.Toleration - version := "testVersion2" features := []string{"database"} masterkey := "testMk2" k8sClient := kubernetesmock.NewMockClientInt(gomock.NewController(t)) dbCurrent := coremock.NewMockDatabaseCurrent(gomock.NewController(t)) queried := map[string]interface{}{} + version := "test" desired := getDesiredTree(t, masterkey, &DesiredV0{ Common: tree.NewCommon("databases.caos.ch/CockroachDB", "v0", false), @@ -248,16 +239,7 @@ func TestManaged_Adapt2(t *testing.T) { dbCurrent.EXPECT().SetCertificateKey(gomock.Any()).MinTimes(1).MaxTimes(1) k8sClient.EXPECT().ApplySecret(gomock.Any()).MinTimes(1).MaxTimes(1) - query, _, _, _, _, _, err := Adapter( - componentLabels, - namespace, - timestamp, - nodeselector, - tolerations, - version, - features, - "", - )(monitor, desired, &tree.Tree{}) + query, _, _, _, _, _, err := Adapter(componentLabels, namespace, timestamp, nodeselector, tolerations, version, features, "")(monitor, desired, &tree.Tree{}) assert.NoError(t, err) ensure, err := query(k8sClient, queried) diff --git a/operator/database/kinds/databases/managed/mock.go b/operator/database/kinds/databases/managed/mock.go new file mode 100644 index 000000000..46ebd7e08 --- /dev/null +++ b/operator/database/kinds/databases/managed/mock.go @@ -0,0 +1,35 @@ +package managed + +import ( + kubernetesmock "github.com/caos/orbos/pkg/kubernetes/mock" + "github.com/golang/mock/gomock" + core "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "time" +) + +func SetClean( + k8sClient *kubernetesmock.MockClientInt, + namespace string, + replicas int, +) { + k8sClient.EXPECT().ScaleStatefulset(namespace, gomock.Any(), 0).Return(nil) + k8sClient.EXPECT().ListPersistentVolumeClaims(namespace).Return(&core.PersistentVolumeClaimList{ + Items: []core.PersistentVolumeClaim{ + {ObjectMeta: metav1.ObjectMeta{ + Name: "datadir-cockroachdb-0", + }}, + }, + }, nil) + k8sClient.EXPECT().ScaleStatefulset(namespace, gomock.Any(), 1).Return(nil) + k8sClient.EXPECT().DeletePersistentVolumeClaim(namespace, gomock.Any(), gomock.Any()).Times(replicas).Return(nil) + k8sClient.EXPECT().WaitUntilStatefulsetIsReady(namespace, gomock.Any(), true, false, gomock.Any()) + k8sClient.EXPECT().WaitUntilStatefulsetIsReady(namespace, gomock.Any(), true, true, time.Second*1) + k8sClient.EXPECT().WaitUntilStatefulsetIsReady(namespace, gomock.Any(), true, true, gomock.Any()) + + /* + k8sClient.EXPECT().ApplyJob(gomock.Any()).Times(1).Return(nil) + k8sClient.EXPECT().GetJob(namespace, clean.GetJobName(backupName)).Times(1).Return(nil, macherrs.NewNotFound(schema.GroupResource{"batch", "jobs"}, clean.GetJobName(backupName))) + k8sClient.EXPECT().WaitUntilJobCompleted(namespace, clean.GetJobName(backupName), gomock.Any()).Times(1).Return(nil) + k8sClient.EXPECT().DeleteJob(namespace, clean.GetJobName(backupName)).Times(1).Return(nil)*/ +} diff --git a/operator/database/kinds/databases/managed/statefulset/adapt.go b/operator/database/kinds/databases/managed/statefulset/adapt.go index 5a91592c1..759f008fa 100644 --- a/operator/database/kinds/databases/managed/statefulset/adapt.go +++ b/operator/database/kinds/databases/managed/statefulset/adapt.go @@ -34,6 +34,7 @@ const ( defaultMode = int32(256) nodeSecret = "cockroachdb.node" rootSecret = "cockroachdb.client.root" + cleanTimeout = time.Minute * 5 ) type Affinity struct { diff --git a/operator/database/kinds/databases/managed/statefulset/clean.go b/operator/database/kinds/databases/managed/statefulset/clean.go new file mode 100644 index 000000000..3ce9e5a14 --- /dev/null +++ b/operator/database/kinds/databases/managed/statefulset/clean.go @@ -0,0 +1,60 @@ +package statefulset + +import ( + "github.com/caos/orbos/mntr" + "github.com/caos/orbos/pkg/kubernetes" + "github.com/caos/orbos/pkg/kubernetes/resources" + "github.com/caos/orbos/pkg/labels" + macherrs "k8s.io/apimachinery/pkg/api/errors" + "strings" + "time" +) + +func CleanPVCs( + monitor mntr.Monitor, + namespace string, + sfsSelectable *labels.Selectable, + replicaCount int, +) resources.QueryFunc { + name := sfsSelectable.Name() + return func(k8sClient kubernetes.ClientInt) (resources.EnsureFunc, error) { + pvcs, err := k8sClient.ListPersistentVolumeClaims(namespace) + if err != nil { + return nil, err + } + internalPvcs := []string{} + for _, pvc := range pvcs.Items { + if strings.HasPrefix(pvc.Name, datadirInternal+"-"+name) { + internalPvcs = append(internalPvcs, pvc.Name) + } + } + return func(k8sClient kubernetes.ClientInt) error { + noSFS := false + monitor.Info("Scale down statefulset") + if err := k8sClient.ScaleStatefulset(namespace, name, 0); err != nil { + if macherrs.IsNotFound(err) { + noSFS = true + } else { + return err + } + } + time.Sleep(2 * time.Second) + + monitor.Info("Delete persistent volume claims") + for _, pvcName := range internalPvcs { + if err := k8sClient.DeletePersistentVolumeClaim(namespace, pvcName, cleanTimeout); err != nil { + return err + } + } + time.Sleep(2 * time.Second) + + if !noSFS { + monitor.Info("Scale up statefulset") + if err := k8sClient.ScaleStatefulset(namespace, name, replicaCount); err != nil { + return err + } + } + return nil + }, nil + } +} diff --git a/operator/database/kinds/orb/adapt.go b/operator/database/kinds/orb/adapt.go index a96dce476..963750943 100644 --- a/operator/database/kinds/orb/adapt.go +++ b/operator/database/kinds/orb/adapt.go @@ -2,6 +2,7 @@ package orb import ( "fmt" + "github.com/caos/zitadel/operator/database/kinds/databases/managed" "github.com/caos/orbos/mntr" "github.com/caos/orbos/pkg/kubernetes" @@ -13,7 +14,6 @@ import ( "github.com/caos/zitadel/operator" "github.com/caos/zitadel/operator/database/kinds/backups/bucket/backup" - "github.com/caos/zitadel/operator/database/kinds/backups/bucket/clean" "github.com/caos/zitadel/operator/database/kinds/backups/bucket/restore" "github.com/caos/zitadel/operator/database/kinds/databases" ) @@ -77,6 +77,10 @@ func AdaptFunc( databaseCurrent := &tree.Tree{} operatorLabels := mustDatabaseOperator(binaryVersion) + version := "" + if binaryVersion != nil { + version = *binaryVersion + } queryDB, destroyDB, configureDB, secrets, existing, migrate, err := databases.Adapt( orbMonitor, @@ -87,7 +91,7 @@ func AdaptFunc( timestamp, desiredKind.Spec.NodeSelector, desiredKind.Spec.Tolerations, - desiredKind.Spec.Version, + version, features, desiredKind.Spec.CustomImageRegistry, ) @@ -102,7 +106,7 @@ func AdaptFunc( dbOrBackup := false for _, feature := range features { switch feature { - case "database", backup.Instant, backup.Normal, restore.Instant, clean.Instant: + case "database", backup.Instant, backup.Normal, restore.Instant, managed.Clean: if !dbOrBackup { dbOrBackup = true queriers = append(queriers, diff --git a/pkg/databases/clear.go b/pkg/databases/clear.go index 6321da7ae..57d1d2731 100644 --- a/pkg/databases/clear.go +++ b/pkg/databases/clear.go @@ -6,7 +6,7 @@ import ( "github.com/caos/orbos/pkg/kubernetes" "github.com/caos/orbos/pkg/tree" "github.com/caos/zitadel/operator/api/database" - "github.com/caos/zitadel/operator/database/kinds/databases/core" + "github.com/caos/zitadel/operator/database/kinds/databases/managed" orbdb "github.com/caos/zitadel/operator/database/kinds/orb" ) @@ -14,51 +14,42 @@ func GitOpsClear( monitor mntr.Monitor, k8sClient kubernetes.ClientInt, gitClient *git.Client, - databases []string, - users []string, ) error { desired, err := gitClient.ReadTree(git.DatabaseFile) if err != nil { return err } - return clear(monitor, k8sClient, databases, users, desired) + return clear(monitor, k8sClient, desired, true) } func CrdClear( monitor mntr.Monitor, k8sClient kubernetes.ClientInt, - databases []string, - users []string, ) error { desired, err := database.ReadCrd(k8sClient) if err != nil { return err } - return clear(monitor, k8sClient, databases, users, desired) + return clear(monitor, k8sClient, desired, false) } func clear( monitor mntr.Monitor, k8sClient kubernetes.ClientInt, - databases []string, - users []string, desired *tree.Tree, + gitops bool, ) error { current := &tree.Tree{} - query, _, _, _, _, _, err := orbdb.AdaptFunc("", nil, false, "clean")(monitor, desired, current) + query, _, _, _, _, _, err := orbdb.AdaptFunc("", nil, gitops, managed.Clean)(monitor, desired, current) if err != nil { - monitor.Error(err) return err } queried := map[string]interface{}{} - core.SetQueriedForDatabaseDBList(queried, databases, users) - ensure, err := query(k8sClient, queried) if err != nil { - monitor.Error(err) return err } diff --git a/pkg/databases/restore.go b/pkg/databases/restore.go index d18534598..7eb88f1b6 100644 --- a/pkg/databases/restore.go +++ b/pkg/databases/restore.go @@ -6,7 +6,6 @@ import ( "github.com/caos/orbos/pkg/kubernetes" "github.com/caos/orbos/pkg/tree" "github.com/caos/zitadel/operator/api/database" - "github.com/caos/zitadel/operator/database/kinds/databases/core" orbdb "github.com/caos/zitadel/operator/database/kinds/orb" ) @@ -15,26 +14,24 @@ func GitOpsRestore( k8sClient kubernetes.ClientInt, gitClient *git.Client, name string, - databases []string, ) error { desired, err := gitClient.ReadTree(git.DatabaseFile) if err != nil { return err } - return restore(monitor, k8sClient, desired, name, databases) + return restore(monitor, k8sClient, desired, name) } func CrdRestore( monitor mntr.Monitor, k8sClient kubernetes.ClientInt, name string, - databases []string, ) error { desired, err := database.ReadCrd(k8sClient) if err != nil { return err } - return restore(monitor, k8sClient, desired, name, databases) + return restore(monitor, k8sClient, desired, name) } func restore( @@ -42,7 +39,6 @@ func restore( k8sClient kubernetes.ClientInt, desired *tree.Tree, name string, - databases []string, ) error { current := &tree.Tree{} @@ -52,8 +48,6 @@ func restore( return err } queried := map[string]interface{}{} - core.SetQueriedForDatabaseDBList(queried, databases, []string{}) - ensure, err := query(k8sClient, queried) if err != nil { monitor.Error(err) diff --git a/pkg/kubernetes/artifacts.go b/pkg/kubernetes/artifacts.go index b9cc6d419..aa013e65e 100644 --- a/pkg/kubernetes/artifacts.go +++ b/pkg/kubernetes/artifacts.go @@ -354,7 +354,7 @@ func DestroyZitadelOperator( func ScaleZitadelOperator( monitor mntr.Monitor, - client *kubernetes.Client, + client kubernetes.ClientInt, replicaCount int, ) error { monitor.Debug("Scaling zitadel-operator") @@ -363,7 +363,7 @@ func ScaleZitadelOperator( func ScaleDatabaseOperator( monitor mntr.Monitor, - client *kubernetes.Client, + client kubernetes.ClientInt, replicaCount int, ) error { monitor.Debug("Scaling database-operator") diff --git a/pkg/zitadel/clearmigraterestore.go b/pkg/zitadel/clearmigraterestore.go deleted file mode 100644 index dff286b67..000000000 --- a/pkg/zitadel/clearmigraterestore.go +++ /dev/null @@ -1,105 +0,0 @@ -package zitadel - -import ( - "time" - - "github.com/caos/orbos/mntr" - "github.com/caos/orbos/pkg/git" - "github.com/caos/orbos/pkg/kubernetes" - orbconfig "github.com/caos/orbos/pkg/orb" - "github.com/caos/zitadel/pkg/databases" - kubernetes2 "github.com/caos/zitadel/pkg/kubernetes" -) - -var ( - databasesList = []string{ - "notification", - "adminapi", - "auth", - "authz", - "eventstore", - "management", - "zitadel", - } - userList = []string{ - "notification", - "adminapi", - "auth", - "authz", - "eventstore", - "management", - "queries", - } -) - -func GitOpsClearMigrateRestore( - monitor mntr.Monitor, - gitClient *git.Client, - orbCfg *orbconfig.Orb, - k8sClient *kubernetes.Client, - backup string, - version *string, -) error { - - if err := kubernetes2.ScaleZitadelOperator(monitor, k8sClient, 0); err != nil { - return err - } - time.Sleep(5 * time.Second) - - if err := GitOpsScaleDown(monitor, orbCfg, gitClient, k8sClient, version); err != nil { - return err - } - - if err := databases.GitOpsClear(monitor, k8sClient, gitClient, databasesList, userList); err != nil { - return err - } - - if err := GitOpsMigrations(monitor, orbCfg, gitClient, k8sClient, version); err != nil { - return err - } - - if err := databases.GitOpsRestore(monitor, k8sClient, gitClient, backup, databasesList); err != nil { - return err - } - - if err := kubernetes2.ScaleZitadelOperator(monitor, k8sClient, 1); err != nil { - return err - } - - return nil -} - -func CrdClearMigrateRestore( - monitor mntr.Monitor, - k8sClient *kubernetes.Client, - backup string, - version *string, -) error { - - if err := kubernetes2.ScaleZitadelOperator(monitor, k8sClient, 0); err != nil { - return err - } - time.Sleep(5 * time.Second) - - if err := CrdScaleDown(monitor, k8sClient, version); err != nil { - return err - } - - if err := databases.CrdClear(monitor, k8sClient, databasesList, userList); err != nil { - return err - } - - if err := CrdMigrations(monitor, k8sClient, version); err != nil { - return err - } - - if err := databases.CrdRestore(monitor, k8sClient, backup, databasesList); err != nil { - return err - } - - if err := kubernetes2.ScaleZitadelOperator(monitor, k8sClient, 1); err != nil { - return err - } - - return nil -}