From fa9bd5a8e7a5032b21272552fbc4cdf1630db049 Mon Sep 17 00:00:00 2001 From: Stefan Benz <46600784+stebenz@users.noreply.github.com> Date: Tue, 23 Mar 2021 18:48:17 +0100 Subject: [PATCH] feat(crd): add crd mode for operators (#1329) * feat(operator): add base for zitadel operator * fix(operator): changed pipeline to release operator * fix(operator): fmt with only one parameter * fix(operator): corrected workflow job name * fix(zitadelctl): added restore and backuplist command * fix(zitadelctl): scale for restore * chore(container): use scratch for deploy container * fix(zitadelctl): limit image to scratch * fix(migration): added migration scripts for newer version * fix(operator): changed handling of kubeconfig in operator logic * fix(operator): changed handling of secrets in operator logic * fix(operator): use new version of zitadel * fix(operator): added path for migrations * fix(operator): delete doublets of migration scripts * fix(operator): delete subpaths and integrate logic into init container * fix(operator): corrected path in dockerfile for local migrations * fix(operator): added migrations for cockroachdb-secure * fix(operator): delete logic for ambassador module * fix(operator): added read and write secret commands * fix(operator): correct and align operator pipeline with zitadel pipeline * fix(operator): correct yaml error in operator pipeline * fix(operator): correct action name in operator pipeline * fix(operator): correct case-sensitive filename in operator pipeline * fix(operator): upload artifacts from buildx output * fix(operator): corrected attribute spelling error * fix(operator): combined jobs for operator binary and image * fix(operator): added missing comma in operator pipeline * fix(operator): added codecov for operator image * fix(operator): added codecov for operator image * fix(testing): code changes for testing and several unit-tests (#1009) * fix(operator): usage of interface of kubernetes client for testing and several unit-tests * fix(operator): several unit-tests * fix(operator): several unit-tests * fix(operator): changed order for the operator logic * fix(operator): added version of zitadelctl from semantic release * fix(operator): corrected function call with version of zitadelctl * fix(operator): corrected function call with version of zitadelctl * fix(operator): add check output to operator release pipeline * fix(operator): set --short length everywhere to 12 * fix(operator): zitadel setup in job instead of exec with several unit tests * fix(operator): fixes to combine newest zitadel and testing branch * fix(operator): corrected path in Dockerfile * fix(operator): fixed unit-test that was ignored during changes * fix(operator): fixed unit-test that was ignored during changes * fix(operator): corrected Dockerfile to correctly use env variable * fix(operator): quickfix takeoff deployment * fix(operator): corrected the clusterrolename in the applied artifacts * fix: update secure migrations * fix(operator): migrations (#1057) * fix(operator): copied migrations from orbos repository * fix(operator): newest migrations * chore: use cockroach-secure * fix: rename migration * fix: remove insecure cockroach migrations Co-authored-by: Stefan Benz * fix: finalize labels * fix(operator): cli logging concurrent and fixe deployment of operator during restore * fix: finalize labels and cli commands * fix: restore * chore: cockroachdb is always secure * chore: use orbos consistent-labels latest commit * test: make tests compatible with new labels * fix: default to sa token for start command * fix: use cockroachdb v12.02 * fix: don't delete flyway user * test: fix migration test * fix: use correct table qualifiers * fix: don't alter sequence ownership * fix: upgrade flyway * fix: change ownership of all dbs and tables to admin user * fix: change defaultdb user * fix: treat clientid status codes >= 400 as errors * fix: reconcile specified ZITADEL version, not binary version * fix: add ca-certs * fix: use latest orbos code * fix: use orbos with fixed race condition * fix: use latest ORBOS code * fix: use latest ORBOS code * fix: make migration and scaling around restoring work * fix(operator): move zitadel operator * chore(migrations): include owner change migration * feat(db): add code base for database operator * fix(db): change used image registry for database operator * fix(db): generated mock * fix(db): add accidentally ignored file * fix(db): add cockroachdb backup image to pipeline * fix(db): correct pipeline and image versions * fix(db): correct version of used orbos * fix(db): correct database import * fix(db): go mod tidy * fix(db): use new version for orbos * fix(migrations): include migrations into zitadelctl binary (#1211) * fix(db): use statik to integrate migrations into binary * fix(migrations): corrections unit tests and pipeline for integrated migrations into zitadelctl binary * fix(migrations): correction in dockerfile for pipeline build * fix(migrations): correction in dockerfile for pipeline build * fix(migrations): dockerfile changes for cache optimization * fix(database): correct used part-of label in database operator * fix(database): correct used selectable label in zitadel operator * fix(operator): correct lables for user secrets in zitadel operator * fix(operator): correct lables for service test in zitadel operator * fix: don't enable database features for user operations (#1227) * fix: don't enable database features for user operations * fix: omit database feature for connection info adapter * fix: use latest orbos version * fix(crd): corrected logic to get database connection and other info * fix(crd): corrected yaml tags and start for zitadel operator * fix(crd): move some dependencies and use consistent structure * fix(crd): corrected unit-tests * fix(crd): corrected main files for debug starts * chore(pipeline): use correct version for zitadelctl build * fix(crd): correct calculating of current db state for zitadel operator * fix(crd): use binary version for deployment of crd mode operators * fix(crd): add gitops attribute for reconciling * fix(crd): corrected crd with newest version * fix(migration): collect cleanup functions and only use them if all jobs are successful * fix(zitadelctl): import gcp auth to connect to gke cluster * feat: Add read and writesecret options for crd mode (#1435) * fix: don't require orbconfig for crd mode * test: pass * fix(zitadelctl): import gcp auth to connect to gke cluster * feat: add read and writesecret option for crd mode * test: fix * fix: make all crd secrets writable * fix: use in-cluster configs for in-cluster operators * chore: remove unnecessary debug files Co-authored-by: Stefan Benz * fix: Crdoperatormerge review (#1385) * fix: don't require orbconfig for crd mode * test: pass * fix(zitadelctl): import gcp auth to connect to gke cluster * fix: ensure caos-system namespace * fix: apply orbconfig at takeoff * docs: improve help for creating an orbconfig * docs: describe orbconfig properties * docs: add --gitops to help message example * fix(pipeline): correct upload of artifacts in dev releases * test: pass Co-authored-by: Stefan Benz * fix(test): corrected falsely merged tests * chore: update orbos library * fix: only handle exactly named and namespaced crd resource * fix: print errors, check correct crd namespace * fix: validate bucket secret * chore: compile * fix(operator): corrected secret handling when unused secrets are not defined * fix(operator): corrected handling of jobs * fix: dont print logs when readsecret path is provided * fix(operator): corrected handling of jobs and sort for mounted volumes * fix(operator): sort for volumes * fix(operator): change orboos import to newest release Co-authored-by: Florian Forster Co-authored-by: Elio Bischof --- .github/workflows/zitadel.yml | 21 +- cmd/database-debug/main.go | 50 --- cmd/operator-debug/main.go | 47 --- cmd/zitadelctl/cmds/backup.go | 18 +- cmd/zitadelctl/cmds/backuplist.go | 10 +- cmd/zitadelctl/cmds/readsecret.go | 32 +- cmd/zitadelctl/cmds/restore.go | 17 +- cmd/zitadelctl/cmds/root.go | 115 ++++-- cmd/zitadelctl/cmds/start.go | 76 ++-- cmd/zitadelctl/cmds/takeoff.go | 178 ++++++--- cmd/zitadelctl/cmds/writesecret.go | 37 +- go.mod | 18 +- go.sum | 286 +++++++------ hack/boilerplate.go.txt | 15 + operator/adapt.go | 2 +- operator/api/core/api.go | 46 +++ operator/api/database/api.go | 44 ++ operator/api/database/v1/database.go | 57 +++ .../api/database/v1/zz_generated.deepcopy.go | 146 +++++++ operator/api/zitadel/api.go | 44 ++ operator/api/zitadel/v1/zitadel.go | 57 +++ .../api/zitadel/v1/zz_generated.deepcopy.go | 146 +++++++ operator/crtlcrd/controller.go | 74 ++++ operator/crtlcrd/database/database.go | 68 ++++ operator/crtlcrd/zitadel/zitadel.go | 67 ++++ operator/{start => crtlgitops}/start.go | 31 +- operator/database/kinds/backups/backups.go | 4 +- .../database/kinds/backups/bucket/adapt.go | 73 +++- .../kinds/backups/bucket/adapt_test.go | 25 +- .../kinds/backups/bucket/backup/adapt.go | 3 +- .../kinds/backups/bucket/backup/adapt_test.go | 7 +- .../kinds/backups/bucket/backup/cleanup.go | 10 +- .../backups/bucket/backup/cleanup_test.go | 19 +- .../kinds/backups/bucket/clean/adapt.go | 3 +- .../kinds/backups/bucket/clean/adapt_test.go | 7 +- .../kinds/backups/bucket/clean/cleanup.go | 8 +- .../backups/bucket/clean/cleanup_test.go | 16 +- .../database/kinds/backups/bucket/desired.go | 22 +- .../database/kinds/backups/bucket/mock.go | 11 + .../kinds/backups/bucket/restore/adapt.go | 3 +- .../backups/bucket/restore/adapt_test.go | 7 +- .../kinds/backups/bucket/restore/cleanup.go | 10 +- .../backups/bucket/restore/cleanup_test.go | 16 +- .../database/kinds/backups/bucket/secrets.go | 19 +- .../kinds/backups/bucket/secrets_test.go | 12 +- .../database/kinds/databases/databases.go | 4 +- .../database/kinds/databases/managed/adapt.go | 40 +- .../databases/managed/adapt_backup_test.go | 13 +- .../kinds/databases/managed/adapt_test.go | 7 +- .../kinds/databases/provided/adapt.go | 10 +- operator/database/kinds/orb/adapt.go | 65 ++- operator/database/kinds/orb/backups.go | 2 +- operator/database/kinds/orb/desired.go | 28 +- operator/database/kinds/orb/reconcile.go | 44 +- .../kinds/orb/zz_generated.deepcopy.go | 54 +++ operator/database/takeoff.go | 3 +- operator/secrets/secrets.go | 217 ++++++---- operator/zitadel/kinds/iam/iam.go | 13 +- operator/zitadel/kinds/iam/zitadel/adapt.go | 201 +++++----- .../kinds/iam/zitadel/configuration/adapt.go | 161 ++++---- .../iam/zitadel/configuration/adapt_test.go | 32 +- .../iam/zitadel/configuration/desired.go | 75 ++-- .../iam/zitadel/configuration/literals.go | 57 ++- .../zitadel/configuration/literals_test.go | 162 +++++++- .../iam/zitadel/configuration/users/adapt.go | 64 +-- .../zitadel/configuration/users/adapt_test.go | 28 +- .../iam/zitadel/configuration/users/users.go | 4 +- .../zitadel/configuration/users/users_test.go | 7 +- .../kinds/iam/zitadel/database/adapt.go | 2 +- .../kinds/iam/zitadel/database/adapt_test.go | 11 +- .../kinds/iam/zitadel/database/client.go | 32 +- .../iam/zitadel/database/mock/client.mock.go | 46 +-- .../kinds/iam/zitadel/database/user.go | 35 +- .../kinds/iam/zitadel/deployment/adapt.go | 98 +++-- .../iam/zitadel/deployment/adapt_test.go | 15 +- .../kinds/iam/zitadel/deployment/container.go | 6 +- .../iam/zitadel/deployment/container_test.go | 4 +- .../iam/zitadel/deployment/initcontainer.go | 16 +- .../zitadel/deployment/initcontainer_test.go | 39 +- .../kinds/iam/zitadel/deployment/volumes.go | 9 +- .../iam/zitadel/deployment/volumes_test.go | 7 +- .../kinds/iam/zitadel/migration/adapt.go | 12 +- .../kinds/iam/zitadel/migration/adapt_test.go | 7 +- operator/zitadel/kinds/iam/zitadel/secrets.go | 134 +++++-- .../kinds/iam/zitadel/services/adapt_test.go | 66 +-- .../kinds/iam/zitadel/services/clientid.go | 4 +- .../zitadel/kinds/iam/zitadel/setup/adapt.go | 104 ++--- .../kinds/iam/zitadel/setup/adapt_test.go | 32 +- .../zitadel/kinds/iam/zitadel/setup/done.go | 5 + operator/zitadel/kinds/iam/zitadel/users.go | 127 +++--- operator/zitadel/kinds/orb/adapt.go | 57 ++- operator/zitadel/kinds/orb/desired.go | 28 +- operator/zitadel/kinds/orb/reconcile.go | 35 +- .../kinds/orb/zz_generated.deepcopy.go | 54 +++ operator/zitadel/takeoff.go | 10 +- pkg/databases/backup.go | 2 +- pkg/databases/clear.go | 2 +- pkg/databases/connection.go | 26 +- pkg/databases/restore.go | 2 +- pkg/databases/user.go | 81 +++- pkg/kubernetes/artifacts.go | 378 ++++++++++++++++-- scripts/generateCrd.sh | 3 + scripts/operator-debug.sh | 8 - 103 files changed, 3411 insertions(+), 1354 deletions(-) delete mode 100644 cmd/database-debug/main.go delete mode 100644 cmd/operator-debug/main.go create mode 100644 hack/boilerplate.go.txt create mode 100644 operator/api/core/api.go create mode 100644 operator/api/database/api.go create mode 100644 operator/api/database/v1/database.go create mode 100644 operator/api/database/v1/zz_generated.deepcopy.go create mode 100644 operator/api/zitadel/api.go create mode 100644 operator/api/zitadel/v1/zitadel.go create mode 100644 operator/api/zitadel/v1/zz_generated.deepcopy.go create mode 100644 operator/crtlcrd/controller.go create mode 100644 operator/crtlcrd/database/database.go create mode 100644 operator/crtlcrd/zitadel/zitadel.go rename operator/{start => crtlgitops}/start.go (81%) create mode 100644 operator/database/kinds/orb/zz_generated.deepcopy.go create mode 100644 operator/zitadel/kinds/orb/zz_generated.deepcopy.go create mode 100755 scripts/generateCrd.sh delete mode 100755 scripts/operator-debug.sh diff --git a/.github/workflows/zitadel.yml b/.github/workflows/zitadel.yml index bb79009ec1..758eaabb5f 100644 --- a/.github/workflows/zitadel.yml +++ b/.github/workflows/zitadel.yml @@ -265,19 +265,18 @@ jobs: if: steps.semantic.outputs.new_release_published != 'true' && needs.refs.outputs.short_ref != 'master' && needs.refs.outputs.short_ref != '' - name: Dev-Release id: create_release - uses: softprops/action-gh-release@v1 + uses: ncipollo/release-action@v1.8.1 if: steps.semantic.outputs.new_release_published != 'true' && needs.refs.outputs.short_ref != 'master' && needs.refs.outputs.short_ref != '' - env: - GITHUB_TOKEN: ${{ env.GITHUB_TOKEN }} with: - tag_name: ${{ needs.refs.outputs.short_ref }}-dev - name: Branch ${{ needs.refs.outputs.short_ref }} - draft: false - prerelease: true + artifacts: "${{ env.ARTIFACTS_FOLDER }}/zitadelctl-darwin-amd64/zitadelctl-darwin-amd64,${{ env.ARTIFACTS_FOLDER }}/zitadelctl-linux-amd64/zitadelctl-linux-amd64,${{ env.ARTIFACTS_FOLDER }}/zitadelctl-windows-amd64/zitadelctl-windows-amd64.exe" body: | This is a release from a development branch. Do not use these artifacts in production. - files: | - ${{ env.ARTIFACTS_FOLDER }}/zitadelctl-darwin-amd64/zitadelctl-darwin-amd64 - ${{ env.ARTIFACTS_FOLDER }}/zitadelctl-linux-amd64/zitadelctl-linux-amd64 - ${{ env.ARTIFACTS_FOLDER }}/zitadelctl-windows-amd64/zitadelctl-windows-amd64.exe + tag: ${{ needs.refs.outputs.short_ref }}-dev + commit: ${{ needs.refs.outputs.short_ref }} + name: Branch ${{ needs.refs.outputs.short_ref }} + token: ${{ env.GITHUB_TOKEN }} + replacesArtifacts: true + prerelease: true + draft: false + allowUpdates: true \ No newline at end of file diff --git a/cmd/database-debug/main.go b/cmd/database-debug/main.go deleted file mode 100644 index 40cfb3c8c1..0000000000 --- a/cmd/database-debug/main.go +++ /dev/null @@ -1,50 +0,0 @@ -package main - -import ( - "flag" - "io/ioutil" - - "github.com/caos/orbos/pkg/kubernetes" - - "github.com/caos/zitadel/operator/start" - - "github.com/caos/orbos/mntr" - "github.com/caos/zitadel/operator/helpers" -) - -func main() { - - orbconfig := flag.String("orbconfig", "~/.orb/config", "The orbconfig file to use") - kubeconfig := flag.String("kubeconfig", "~/.kube/config", "The kubeconfig file to use") - verbose := flag.Bool("verbose", false, "Print debug levelled logs") - - flag.Parse() - - monitor := mntr.Monitor{ - OnInfo: mntr.LogMessage, - OnChange: mntr.LogMessage, - OnError: mntr.LogError, - } - - if *verbose { - monitor = monitor.Verbose() - } - - kc, err := ioutil.ReadFile(helpers.PruneHome(*kubeconfig)) - if err != nil { - panic(err) - } - - if err := start.Database( - monitor, - helpers.PruneHome(*orbconfig), - kubernetes.NewK8sClient(monitor, strPtr(string(kc))), - strPtr("database-development"), - ); err != nil { - panic(err) - } -} - -func strPtr(str string) *string { - return &str -} diff --git a/cmd/operator-debug/main.go b/cmd/operator-debug/main.go deleted file mode 100644 index 8a1fb005f6..0000000000 --- a/cmd/operator-debug/main.go +++ /dev/null @@ -1,47 +0,0 @@ -package main - -import ( - "flag" - "io/ioutil" - - "github.com/caos/orbos/mntr" - "github.com/caos/orbos/pkg/kubernetes" - "github.com/caos/zitadel/operator/helpers" - "github.com/caos/zitadel/operator/start" -) - -func main() { - orbconfig := flag.String("orbconfig", "~/.orb/config", "The orbconfig file to use") - kubeconfig := flag.String("kubeconfig", "~/.kube/config", "The kubeconfig file to use") - verbose := flag.Bool("verbose", false, "Print debug levelled logs") - - flag.Parse() - - monitor := mntr.Monitor{ - OnInfo: mntr.LogMessage, - OnChange: mntr.LogMessage, - OnError: mntr.LogError, - } - - if *verbose { - monitor = monitor.Verbose() - } - - kc, err := ioutil.ReadFile(helpers.PruneHome(*kubeconfig)) - if err != nil { - panic(err) - } - - if err := start.Operator( - monitor, - helpers.PruneHome(*orbconfig), - kubernetes.NewK8sClient(monitor, strPtr(string(kc))), - strPtr("local-debugging"), - ); err != nil { - panic(err) - } -} - -func strPtr(str string) *string { - return &str -} diff --git a/cmd/zitadelctl/cmds/backup.go b/cmd/zitadelctl/cmds/backup.go index d00ec60046..d19564b60c 100644 --- a/cmd/zitadelctl/cmds/backup.go +++ b/cmd/zitadelctl/cmds/backup.go @@ -1,14 +1,15 @@ package cmds import ( + "io/ioutil" + "github.com/caos/orbos/pkg/kubernetes" "github.com/caos/zitadel/operator/api" - "github.com/caos/zitadel/operator/start" + "github.com/caos/zitadel/operator/crtlgitops" "github.com/spf13/cobra" - "io/ioutil" ) -func BackupCommand(rv RootValues) *cobra.Command { +func BackupCommand(getRv GetRootValues) *cobra.Command { var ( kubeconfig string backup string @@ -24,14 +25,19 @@ func BackupCommand(rv RootValues) *cobra.Command { flags.StringVar(&backup, "backup", "", "Name used for backup folder") cmd.RunE = func(cmd *cobra.Command, args []string) (err error) { - _, monitor, orbConfig, gitClient, version, errFunc, err := rv() + rv, err := getRv() if err != nil { return err } defer func() { - err = errFunc(err) + err = rv.ErrFunc(err) }() + monitor := rv.Monitor + orbConfig := rv.OrbConfig + gitClient := rv.GitClient + version := rv.Version + if err := gitClient.Configure(orbConfig.URL, []byte(orbConfig.Repokey)); err != nil { return err } @@ -55,7 +61,7 @@ func BackupCommand(rv RootValues) *cobra.Command { k8sClient := kubernetes.NewK8sClient(monitor, &kubeconfigStr) if k8sClient.Available() { - if err := start.Backup( + if err := crtlgitops.Backup( monitor, orbConfig.Path, k8sClient, diff --git a/cmd/zitadelctl/cmds/backuplist.go b/cmd/zitadelctl/cmds/backuplist.go index dbf356a352..9d489ab39c 100644 --- a/cmd/zitadelctl/cmds/backuplist.go +++ b/cmd/zitadelctl/cmds/backuplist.go @@ -8,7 +8,7 @@ import ( "github.com/spf13/cobra" ) -func BackupListCommand(rv RootValues) *cobra.Command { +func BackupListCommand(getRv GetRootValues) *cobra.Command { var ( cmd = &cobra.Command{ Use: "backuplist", @@ -18,14 +18,18 @@ func BackupListCommand(rv RootValues) *cobra.Command { ) cmd.RunE = func(cmd *cobra.Command, args []string) error { - _, monitor, orbConfig, gitClient, _, errFunc, err := rv() + rv, err := getRv() if err != nil { return err } defer func() { - err = errFunc(err) + err = rv.ErrFunc(err) }() + monitor := rv.Monitor + orbConfig := rv.OrbConfig + gitClient := rv.GitClient + if err := gitClient.Configure(orbConfig.URL, []byte(orbConfig.Repokey)); err != nil { monitor.Error(err) return nil diff --git a/cmd/zitadelctl/cmds/readsecret.go b/cmd/zitadelctl/cmds/readsecret.go index 3a0d9937cb..b4c4066b0c 100644 --- a/cmd/zitadelctl/cmds/readsecret.go +++ b/cmd/zitadelctl/cmds/readsecret.go @@ -3,12 +3,15 @@ package cmds import ( "os" - "github.com/caos/orbos/pkg/secret" + "github.com/caos/orbos/pkg/kubernetes/cli" + "github.com/caos/zitadel/operator/secrets" + + "github.com/caos/orbos/pkg/secret" "github.com/spf13/cobra" ) -func ReadSecretCommand(rv RootValues) *cobra.Command { +func ReadSecretCommand(getRv GetRootValues) *cobra.Command { return &cobra.Command{ Use: "readsecret [path]", Short: "Print a secrets decrypted value to stdout", @@ -16,32 +19,33 @@ func ReadSecretCommand(rv RootValues) *cobra.Command { Args: cobra.MaximumNArgs(1), Example: `zitadelctl readsecret zitadel.emailappkey > ~/emailappkey`, RunE: func(cmd *cobra.Command, args []string) error { - - _, monitor, orbConfig, gitClient, _, errFunc, err := rv() + rv, err := getRv() if err != nil { return err } defer func() { - err = errFunc(err) + err = rv.ErrFunc(err) }() - if err := gitClient.Configure(orbConfig.URL, []byte(orbConfig.Repokey)); err != nil { - return err - } - if err := gitClient.Clone(); err != nil { - return err - } + monitor := rv.Monitor + orbConfig := rv.OrbConfig + gitClient := rv.GitClient path := "" if len(args) > 0 { path = args[0] } + k8sClient, _, err := cli.Client(monitor, orbConfig, gitClient, rv.Kubeconfig, rv.Gitops) + if err != nil && !rv.Gitops { + return err + } + value, err := secret.Read( - monitor, - gitClient, + k8sClient, path, - secrets.GetAllSecretsFunc(orbConfig)) + secrets.GetAllSecretsFunc(monitor, path == "", rv.Gitops, gitClient, k8sClient, orbConfig), + ) if err != nil { monitor.Error(err) return nil diff --git a/cmd/zitadelctl/cmds/restore.go b/cmd/zitadelctl/cmds/restore.go index a9230d6202..5eb556af22 100644 --- a/cmd/zitadelctl/cmds/restore.go +++ b/cmd/zitadelctl/cmds/restore.go @@ -4,19 +4,20 @@ import ( "errors" "io/ioutil" + "github.com/caos/zitadel/operator/crtlgitops" "github.com/caos/zitadel/operator/helpers" "github.com/caos/orbos/pkg/kubernetes" - "github.com/caos/zitadel/operator/start" "github.com/caos/zitadel/pkg/databases" "github.com/manifoldco/promptui" "github.com/spf13/cobra" ) -func RestoreCommand(rv RootValues) *cobra.Command { +func RestoreCommand(getRv GetRootValues) *cobra.Command { var ( backup string kubeconfig string + gitOpsMode bool cmd = &cobra.Command{ Use: "restore", Short: "Restore from backup", @@ -27,16 +28,22 @@ func RestoreCommand(rv RootValues) *cobra.Command { flags := cmd.Flags() flags.StringVar(&backup, "backup", "", "Backup used for db restore") flags.StringVar(&kubeconfig, "kubeconfig", "~/.kube/config", "Kubeconfig for ZITADEL operator deployment") + flags.BoolVar(&gitOpsMode, "gitops", false, "defines if the operator should run in gitops mode") cmd.RunE = func(cmd *cobra.Command, args []string) error { - _, monitor, orbConfig, gitClient, version, errFunc, err := rv() + rv, err := getRv() if err != nil { return err } defer func() { - err = errFunc(err) + err = rv.ErrFunc(err) }() + monitor := rv.Monitor + orbConfig := rv.OrbConfig + gitClient := rv.GitClient + version := rv.Version + kubeconfig = helpers.PruneHome(kubeconfig) if err := gitClient.Configure(orbConfig.URL, []byte(orbConfig.Repokey)); err != nil { @@ -89,7 +96,7 @@ func RestoreCommand(rv RootValues) *cobra.Command { return nil } - if err := start.Restore(monitor, gitClient, orbConfig, k8sClient, backup, &version); err != nil { + if err := crtlgitops.Restore(monitor, gitClient, orbConfig, k8sClient, backup, gitOpsMode, &version); err != nil { monitor.Error(err) } return nil diff --git a/cmd/zitadelctl/cmds/root.go b/cmd/zitadelctl/cmds/root.go index 1568d40ca9..a1f119e208 100644 --- a/cmd/zitadelctl/cmds/root.go +++ b/cmd/zitadelctl/cmds/root.go @@ -2,6 +2,7 @@ package cmds import ( "context" + "github.com/caos/orbos/mntr" "github.com/caos/orbos/pkg/git" "github.com/caos/orbos/pkg/orb" @@ -9,64 +10,92 @@ import ( "github.com/spf13/cobra" ) -type RootValues func() (context.Context, mntr.Monitor, *orb.Orb, *git.Client, string, errFunc, error) +type RootValues struct { + Ctx context.Context + Monitor mntr.Monitor + Version string + Gitops bool + OrbConfig *orb.Orb + GitClient *git.Client + Kubeconfig string + ErrFunc errFunc +} + +type GetRootValues func() (*RootValues, error) type errFunc func(err error) error -func RootCommand(version string) (*cobra.Command, RootValues) { +func RootCommand(version string) (*cobra.Command, GetRootValues) { var ( - verbose bool - orbConfigPath string - ) - - cmd := &cobra.Command{ - Use: "zitadelctl [flags]", - Short: "Interact with your IAM orbs", - Long: `zitadelctl launches zitadel and simplifies common tasks such as updating your kubeconfig. -Participate in our community on https://github.com/caos/orbos -and visit our website at https://caos.ch`, - Example: `$ mkdir -p ~/.orb -$ cat > ~/.orb/myorb << EOF -> url: git@github.com:me/my-orb.git -> masterkey: "$(gopass my-secrets/orbs/myorb/masterkey)" -> repokey: | -> $(cat ~/.ssh/myorbrepo | sed s/^/\ \ /g) -> EOF -$ orbctl -f ~/.orb/myorb [command] -`, - } - - flags := cmd.PersistentFlags() - flags.StringVarP(&orbConfigPath, "orbconfig", "f", "~/.orb/config", "Path to the file containing the orbs git repo URL, deploy key and the master key for encrypting and decrypting secrets") - flags.BoolVar(&verbose, "verbose", false, "Print debug levelled logs") - - return cmd, func() (context.Context, mntr.Monitor, *orb.Orb, *git.Client, string, errFunc, error) { - - monitor := mntr.Monitor{ + ctx = context.Background() + monitor = mntr.Monitor{ OnInfo: mntr.LogMessage, OnChange: mntr.LogMessage, OnError: mntr.LogError, } + rv = &RootValues{ + Ctx: ctx, + Version: version, + ErrFunc: func(err error) error { + if err != nil { + monitor.Error(err) + } + return nil + }, + } + orbConfigPath string + verbose bool + ) + cmd := &cobra.Command{ + Use: "zitadelctl [flags]", + Short: "Interact with your IAM orbs", + Long: `zitadelctl launches zitadel and simplifies common tasks such as deploying operators or reading and writing secrets. +Participate in our community on https://github.com/caos/orbos +and visit our website at https://caos.ch`, + Example: `$ # For being able to use the --gitops flag, you need to create an orbconfig and add an SSH deploy key to your github project +$ # Create an ssh key pair +$ ssh-keygen -b 2048 -t rsa -f ~/.ssh/myorbrepo -q -N "" +$ # Create the orbconfig +$ mkdir -p ~/.orb +$ cat > ~/.orb/myorb << EOF +> # this is the ssh URL to your git repository +> url: git@github.com:me/my-orb.git +> masterkey: "$(openssl rand -base64 21)" # used for encrypting and decrypting secrets +> # the repokey is used to connect to your git repository +> repokey: | +> $(cat ~/.ssh/myorbrepo | sed s/^/\ \ /g) +> EOF +$ zitadelctl --gitops -f ~/.orb/myorb [command] +`, + } + + flags := cmd.PersistentFlags() + flags.BoolVar(&rv.Gitops, "gitops", false, "Run orbctl in gitops mode. Not specifying this flag is only supported for BOOM and Networking Operator") + flags.StringVarP(&orbConfigPath, "orbconfig", "f", "~/.orb/config", "Path to the file containing the orbs git repo URL, deploy key and the master key for encrypting and decrypting secrets") + flags.StringVarP(&rv.Kubeconfig, "kubeconfig", "k", "~/.kube/config", "Path to the kubeconfig file to the cluster orbctl should target") + flags.BoolVar(&verbose, "verbose", false, "Print debug levelled logs") + + return cmd, func() (*RootValues, error) { if verbose { monitor = monitor.Verbose() } - prunedPath := helpers.PruneHome(orbConfigPath) - orbConfig, err := orb.ParseOrbConfig(prunedPath) - if err != nil { - orbConfig = &orb.Orb{Path: prunedPath} - return nil, mntr.Monitor{}, nil, nil, "", nil, err + rv.Monitor = monitor + rv.Kubeconfig = helpers.PruneHome(rv.Kubeconfig) + rv.GitClient = git.New(ctx, monitor, "orbos", "orbos@caos.ch") + + if rv.Gitops { + prunedPath := helpers.PruneHome(orbConfigPath) + orbConfig, err := orb.ParseOrbConfig(prunedPath) + if err != nil { + orbConfig = &orb.Orb{Path: prunedPath} + return nil, err + } + rv.OrbConfig = orbConfig } - ctx := context.Background() - - return ctx, monitor, orbConfig, git.New(ctx, monitor, "orbos", "orbos@caos.ch"), version, func(err error) error { - if err != nil { - monitor.Error(err) - } - return nil - }, nil + return rv, nil } } diff --git a/cmd/zitadelctl/cmds/start.go b/cmd/zitadelctl/cmds/start.go index 3bbd9bd91c..51743cf7e7 100644 --- a/cmd/zitadelctl/cmds/start.go +++ b/cmd/zitadelctl/cmds/start.go @@ -1,81 +1,95 @@ package cmds import ( - "github.com/caos/orbos/pkg/kubernetes" - "github.com/caos/zitadel/operator/helpers" - "github.com/caos/zitadel/operator/start" + "github.com/caos/orbos/pkg/kubernetes/cli" + + "github.com/caos/zitadel/operator/crtlcrd" + "github.com/caos/zitadel/operator/crtlgitops" "github.com/spf13/cobra" ) -func StartOperator(rv RootValues) *cobra.Command { +func StartOperator(getRv GetRootValues) *cobra.Command { var ( - kubeconfig string - cmd = &cobra.Command{ + metricsAddr string + cmd = &cobra.Command{ Use: "operator", Short: "Launch a ZITADEL operator", Long: "Ensures a desired state of ZITADEL", } ) flags := cmd.Flags() - flags.StringVar(&kubeconfig, "kubeconfig", "", "Kubeconfig for ZITADEL operator deployment") + flags.StringVar(&metricsAddr, "metrics-addr", "", "The address the metric endpoint binds to.") cmd.RunE = func(cmd *cobra.Command, args []string) error { - _, monitor, orbConfig, _, version, errFunc, err := rv() + rv, err := getRv() if err != nil { return err } defer func() { - err = errFunc(err) + err = rv.ErrFunc(err) }() - kubeconfig = helpers.PruneHome(kubeconfig) + monitor := rv.Monitor + orbConfig := rv.OrbConfig + version := rv.Version - k8sClient, err := kubernetes.NewK8sClientWithPath(monitor, kubeconfig) - if err != nil { - monitor.Error(err) - return nil - } + if rv.Gitops { + k8sClient, _, err := cli.Client(monitor, orbConfig, rv.GitClient, rv.Kubeconfig, rv.Gitops) + if err != nil { + return err + } - if k8sClient.Available() { - if err := start.Operator(monitor, orbConfig.Path, k8sClient, &version); err != nil { - monitor.Error(err) - return nil + return crtlgitops.Operator(monitor, orbConfig.Path, k8sClient, &version, rv.Gitops) + } else { + if err := crtlcrd.Start(monitor, version, metricsAddr, crtlcrd.Zitadel); err != nil { + return err } } + return nil } return cmd } -func StartDatabase(rv RootValues) *cobra.Command { +func StartDatabase(getRv GetRootValues) *cobra.Command { var ( - kubeconfig string - cmd = &cobra.Command{ + kubeconfig string + metricsAddr string + cmd = &cobra.Command{ Use: "database", Short: "Launch a database operator", Long: "Ensures a desired state of the database", } ) flags := cmd.Flags() - flags.StringVar(&kubeconfig, "kubeconfig", "", "kubeconfig used by zitadel operator") + flags.StringVar(&kubeconfig, "kubeconfig", "", "kubeconfig used by database operator") + flags.StringVar(&metricsAddr, "metrics-addr", "", "The address the metric endpoint binds to.") cmd.RunE = func(cmd *cobra.Command, args []string) (err error) { - _, monitor, orbConfig, _, version, errFunc, err := rv() + rv, err := getRv() if err != nil { return err } defer func() { - err = errFunc(err) + err = rv.ErrFunc(err) }() - k8sClient, err := kubernetes.NewK8sClientWithPath(monitor, kubeconfig) - if err != nil { - return err + monitor := rv.Monitor + orbConfig := rv.OrbConfig + version := rv.Version + + if rv.Gitops { + k8sClient, _, err := cli.Client(monitor, orbConfig, rv.GitClient, rv.Kubeconfig, rv.Gitops) + if err != nil { + return err + } + return crtlgitops.Database(monitor, orbConfig.Path, k8sClient, &version, rv.Gitops) + } else { + if err := crtlcrd.Start(monitor, version, metricsAddr, crtlcrd.Database); err != nil { + return err + } } - if k8sClient.Available() { - return start.Database(monitor, orbConfig.Path, k8sClient, &version) - } return nil } return cmd diff --git a/cmd/zitadelctl/cmds/takeoff.go b/cmd/zitadelctl/cmds/takeoff.go index 9352f43fe2..cc49e1c00a 100644 --- a/cmd/zitadelctl/cmds/takeoff.go +++ b/cmd/zitadelctl/cmds/takeoff.go @@ -1,23 +1,25 @@ package cmds import ( - orbdb "github.com/caos/zitadel/operator/database/kinds/orb" - "io/ioutil" + "github.com/caos/orbos/pkg/kubernetes/cli" + "github.com/ghodss/yaml" - "github.com/caos/zitadel/operator/helpers" + orbdb "github.com/caos/zitadel/operator/database/kinds/orb" "github.com/caos/orbos/mntr" "github.com/caos/orbos/pkg/git" "github.com/caos/orbos/pkg/kubernetes" "github.com/caos/zitadel/operator/api" - "github.com/caos/zitadel/operator/zitadel/kinds/orb" + orbzit "github.com/caos/zitadel/operator/zitadel/kinds/orb" "github.com/spf13/cobra" + _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" ) -func TakeoffCommand(rv RootValues) *cobra.Command { +func TakeoffCommand(getRv GetRootValues) *cobra.Command { var ( - kubeconfig string - cmd = &cobra.Command{ + gitOpsZitadel bool + gitOpsDatabase bool + cmd = &cobra.Command{ Use: "takeoff", Short: "Launch a ZITADEL operator on the orb", Long: "Ensures a desired state of the resources on the orb", @@ -25,39 +27,57 @@ func TakeoffCommand(rv RootValues) *cobra.Command { ) flags := cmd.Flags() - flags.StringVar(&kubeconfig, "kubeconfig", "~/.kube/config", "Kubeconfig for ZITADEL operator deployment") + flags.BoolVar(&gitOpsZitadel, "gitops-zitadel", false, "defines if the zitadel operator should run in gitops mode") + flags.BoolVar(&gitOpsDatabase, "gitops-database", false, "defines if the database operator should run in gitops mode") cmd.RunE = func(cmd *cobra.Command, args []string) error { - _, monitor, orbConfig, gitClient, _, errFunc, err := rv() + rv, err := getRv() if err != nil { return err } defer func() { - err = errFunc(err) + err = rv.ErrFunc(err) }() - kubeconfig = helpers.PruneHome(kubeconfig) - if err := gitClient.Configure(orbConfig.URL, []byte(orbConfig.Repokey)); err != nil { - monitor.Error(err) - return nil - } + monitor := rv.Monitor + orbConfig := rv.OrbConfig + gitClient := rv.GitClient - if err := gitClient.Clone(); err != nil { - monitor.Error(err) - return nil - } - - value, err := ioutil.ReadFile(kubeconfig) + k8sClient, _, err := cli.Client( + monitor, + orbConfig, + gitClient, + rv.Kubeconfig, + gitOpsZitadel || gitOpsDatabase, + ) if err != nil { - monitor.Error(err) - return nil + return err + } + + if err := kubernetes.EnsureCaosSystemNamespace(monitor, k8sClient); err != nil { + monitor.Info("failed to apply common resources into k8s-cluster") + return err + } + + if gitOpsZitadel || gitOpsDatabase { + + orbConfigBytes, err := yaml.Marshal(orbConfig) + if err != nil { + return err + } + + if err := kubernetes.EnsureOrbconfigSecret(monitor, k8sClient, orbConfigBytes); err != nil { + monitor.Info("failed to apply configuration resources into k8s-cluster") + return err + } } - kubeconfigStr := string(value) if err := deployOperator( monitor, gitClient, - &kubeconfigStr, + k8sClient, + rv.Version, + rv.Gitops || gitOpsZitadel, ); err != nil { monitor.Error(err) } @@ -65,7 +85,9 @@ func TakeoffCommand(rv RootValues) *cobra.Command { if err := deployDatabase( monitor, gitClient, - &kubeconfigStr, + k8sClient, + rv.Version, + rv.Gitops || gitOpsDatabase, ); err != nil { monitor.Error(err) } @@ -74,53 +96,85 @@ func TakeoffCommand(rv RootValues) *cobra.Command { return cmd } -func deployOperator(monitor mntr.Monitor, gitClient *git.Client, kubeconfig *string) error { - found, err := api.ExistsZitadelYml(gitClient) - if err != nil { - return err - } - if !found { - monitor.Info("No ZITADEL operator deployed as no zitadel.yml present") - return nil - } +func deployOperator(monitor mntr.Monitor, gitClient *git.Client, k8sClient kubernetes.ClientInt, version string, gitops bool) error { + if gitops { + found, err := api.ExistsZitadelYml(gitClient) + if err != nil { + return err + } + if found { - if found { - k8sClient := kubernetes.NewK8sClient(monitor, kubeconfig) - - if k8sClient.Available() { desiredTree, err := api.ReadZitadelYml(gitClient) if err != nil { return err } - if err := orb.Reconcile(monitor, desiredTree, true)(k8sClient); err != nil { - return err - } - } - } - return nil -} - -func deployDatabase(monitor mntr.Monitor, gitClient *git.Client, kubeconfig *string) error { - found, err := api.ExistsDatabaseYml(gitClient) - if err != nil { - return err - } - if found { - k8sClient := kubernetes.NewK8sClient(monitor, kubeconfig) - - if k8sClient.Available() { - tree, err := api.ReadDatabaseYml(gitClient) + desired, err := orbzit.ParseDesiredV0(desiredTree) if err != nil { return err } + spec := desired.Spec + spec.GitOps = gitops - if err := orbdb.Reconcile( - monitor, - tree)(k8sClient); err != nil { + // at takeoff the artifacts have to be applied + spec.SelfReconciling = true + if err := orbzit.Reconcile(monitor, spec)(k8sClient); err != nil { return err } - } else { - monitor.Info("Failed to connect to k8s") + } + } else { + // at takeoff the artifacts have to be applied + spec := &orbzit.Spec{ + Version: version, + SelfReconciling: true, + GitOps: gitops, + } + + if err := orbzit.Reconcile(monitor, spec)(k8sClient); err != nil { + return err + } + } + + return nil +} + +func deployDatabase(monitor mntr.Monitor, gitClient *git.Client, k8sClient kubernetes.ClientInt, version string, gitops bool) error { + if gitops { + found, err := api.ExistsDatabaseYml(gitClient) + if err != nil { + return err + } + if found { + desiredTree, err := api.ReadDatabaseYml(gitClient) + if err != nil { + return err + } + desired, err := orbdb.ParseDesiredV0(desiredTree) + if err != nil { + return err + } + spec := desired.Spec + spec.GitOps = gitops + + // at takeoff the artifacts have to be applied + spec.SelfReconciling = true + if err := orbdb.Reconcile( + monitor, + spec)(k8sClient); err != nil { + return err + } + } + } else { + // at takeoff the artifacts have to be applied + spec := &orbdb.Spec{ + Version: version, + SelfReconciling: true, + GitOps: gitops, + } + + if err := orbdb.Reconcile( + monitor, + spec)(k8sClient); err != nil { + return err } } return nil diff --git a/cmd/zitadelctl/cmds/writesecret.go b/cmd/zitadelctl/cmds/writesecret.go index d49568d23d..5fe4dd15c4 100644 --- a/cmd/zitadelctl/cmds/writesecret.go +++ b/cmd/zitadelctl/cmds/writesecret.go @@ -2,15 +2,18 @@ package cmds import ( "errors" + "fmt" "io/ioutil" "os" + "github.com/caos/orbos/pkg/kubernetes/cli" + "github.com/caos/orbos/pkg/secret" "github.com/caos/zitadel/operator/secrets" "github.com/spf13/cobra" ) -func WriteSecretCommand(rv RootValues) *cobra.Command { +func WriteSecretCommand(getRv GetRootValues) *cobra.Command { var ( value string @@ -32,43 +35,43 @@ orbctl writesecret mygceprovider.google_application_credentials_value --value "$ flags.BoolVar(&stdin, "stdin", false, "Value to encrypt is read from standard input") cmd.RunE = func(cmd *cobra.Command, args []string) error { - - _, monitor, orbConfig, gitClient, _, errFunc, err := rv() + rv, err := getRv() if err != nil { return err } defer func() { - err = errFunc(err) + err = rv.ErrFunc(err) }() + monitor := rv.Monitor + orbConfig := rv.OrbConfig + gitClient := rv.GitClient + s, err := key(value, file, stdin) if err != nil { monitor.Error(err) return nil } - if err := gitClient.Configure(orbConfig.URL, []byte(orbConfig.Repokey)); err != nil { - monitor.Error(err) - return nil - } - - if err := gitClient.Clone(); err != nil { - monitor.Error(err) - return nil - } - path := "" if len(args) > 0 { path = args[0] } + k8sClient, _, err := cli.Client(monitor, orbConfig, gitClient, rv.Kubeconfig, rv.Gitops) + if err != nil && !rv.Gitops { + return err + } + if err := secret.Write( monitor, - gitClient, + k8sClient, path, s, - secrets.GetAllSecretsFunc(orbConfig), - secrets.PushFunc(), + "zitadelctl", + fmt.Sprintf(rv.Version), + secrets.GetAllSecretsFunc(monitor, path != "", rv.Gitops, gitClient, k8sClient, orbConfig), + secrets.PushFunc(monitor, rv.Gitops, gitClient, k8sClient), ); err != nil { monitor.Error(err) } diff --git a/go.mod b/go.mod index fa97b046e2..e6b95a97b6 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc github.com/caos/logging v0.0.2 github.com/caos/oidc v0.14.3 - github.com/caos/orbos v1.5.14-0.20210302165604-744ecfd88280 + github.com/caos/orbos v0.33.1-0.20210323170932-bc2a0ccb8cd5 github.com/cockroachdb/cockroach-go/v2 v2.1.0 github.com/duo-labs/webauthn v0.0.0-20200714211715-1daaee874e43 github.com/envoyproxy/protoc-gen-validate v0.1.0 @@ -54,7 +54,7 @@ require ( github.com/rakyll/statik v0.1.7 github.com/rs/cors v1.7.0 github.com/sony/sonyflake v1.0.0 - github.com/spf13/cobra v0.0.7 + github.com/spf13/cobra v1.1.1 github.com/stretchr/testify v1.7.0 github.com/ttacon/builder v0.0.0-20170518171403-c099f663e1c2 // indirect github.com/ttacon/libphonenumber v1.1.0 @@ -66,19 +66,21 @@ require ( go.opentelemetry.io/otel/exporters/stdout v0.13.0 go.opentelemetry.io/otel/sdk v0.13.0 golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 - golang.org/x/net v0.0.0-20201031054903-ff519b6c9102 // indirect golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 // indirect golang.org/x/text v0.3.5 golang.org/x/tools v0.0.0-20201103235415-b653051172e4 google.golang.org/api v0.34.0 google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20201103154000-415bd0cd5df6 + google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a google.golang.org/grpc v1.34.0 google.golang.org/protobuf v1.25.0 gopkg.in/square/go-jose.v2 v2.5.1 - gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c + gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 gotest.tools v2.2.0+incompatible - k8s.io/api v0.18.5 - k8s.io/apiextensions-apiserver v0.18.5 - k8s.io/apimachinery v0.18.5 + k8s.io/api v0.20.2 + k8s.io/apiextensions-apiserver v0.20.1 + k8s.io/apimachinery v0.20.2 + k8s.io/client-go v0.20.2 + sigs.k8s.io/controller-runtime v0.8.1 + sigs.k8s.io/yaml v1.2.0 ) diff --git a/go.sum b/go.sum index 3824c6a66a..a85e9e6878 100644 --- a/go.sum +++ b/go.sum @@ -6,6 +6,7 @@ cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxK cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= cloud.google.com/go v0.53.0 h1:MZQCQQaRwOrAcuKjiHWHrgKykt4fZyuwF2dtiG3fGW8= cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= @@ -30,6 +31,7 @@ cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM7 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/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= @@ -49,13 +51,26 @@ github.com/AlecAivazis/survey/v2 v2.0.8/go.mod h1:9FJRdMdDm8rnT+zHVbvQT2RTSTLq0T 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-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.9.6/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630= +github.com/Azure/go-autorest/autorest v0.11.1/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw= github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= +github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= +github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg= +github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= 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.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= +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.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= +github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +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/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= @@ -133,17 +148,30 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce 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/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= -github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI= +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/caos/logging v0.0.0-20191210002624-b3260f690a6a/go.mod h1:9LKiDE2ChuGv6CHYif/kiugrfEXu9AwDiFWSreX7Wp0= -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.6.2/go.mod h1:ozoi3b+aY33gzdvjz4w90VZShIHGsmDa0goruuV0arQ= -github.com/caos/oidc v0.14.3 h1:ItpN396oY/lcIG2dm3rAm8Wm5ZM7kJRJ/BUIXn/tHtI= github.com/caos/oidc v0.14.3/go.mod h1:fSLPGlxZhjSMP2LYKZ5QMaM/YYmLHfj/Fce+ji48kYY= -github.com/caos/orbos v1.5.14-0.20210302165604-744ecfd88280 h1:0c87LbDKLYZdDKhxcODZ+V4rwcz8Fnt7S4DVJG8bL1U= -github.com/caos/orbos v1.5.14-0.20210302165604-744ecfd88280/go.mod h1:hyjRSGFdmfGHjeiFzL/wyuNKiUPVdkP3eY7+H/JXqAU= +github.com/caos/orbos v0.33.1-0.20210323170932-bc2a0ccb8cd5 h1:s322Ni5AMc40+svoOvIR46Cr5ssJa54Iz1jZGENok4E= +github.com/caos/orbos v0.33.1-0.20210323170932-bc2a0ccb8cd5/go.mod h1:pydYnEk6rLwun8ur79Et0Fx7BaIJoLmeDWsNy7m4O0o= +github.com/caos/orbos v1.5.14-0.20210318145026-29a60a2f679a h1:CYt6Oi7jnC2Xi1s8OKtyNjMYb5nrfNLYb8gwLZqUE44= +github.com/caos/orbos v1.5.14-0.20210318145026-29a60a2f679a/go.mod h1:pydYnEk6rLwun8ur79Et0Fx7BaIJoLmeDWsNy7m4O0o= +github.com/caos/orbos v1.5.14-0.20210319172131-c7aa31e81c0c h1:eehatx9X5jo6MGweYfAXtHggjERVu+G+Vtem5fVvyOw= +github.com/caos/orbos v1.5.14-0.20210319172131-c7aa31e81c0c/go.mod h1:pydYnEk6rLwun8ur79Et0Fx7BaIJoLmeDWsNy7m4O0o= +github.com/caos/orbos v1.5.14-0.20210322110337-6e1740fabeed h1:wzXHr/N9m/Lg1jwDNdEiCtBpB/l98fxQJZDbbRcZGMM= +github.com/caos/orbos v1.5.14-0.20210322110337-6e1740fabeed/go.mod h1:pydYnEk6rLwun8ur79Et0Fx7BaIJoLmeDWsNy7m4O0o= +github.com/caos/orbos v1.5.14-0.20210322154317-41a25881ee33 h1:w0XfbYptPW49uuqrJm85A6vyuWnS+reAsyMbuFKwWP8= +github.com/caos/orbos v1.5.14-0.20210322154317-41a25881ee33/go.mod h1:pydYnEk6rLwun8ur79Et0Fx7BaIJoLmeDWsNy7m4O0o= +github.com/caos/orbos v1.5.14-0.20210323084053-ddea4d17b402 h1:aMJM077TK30HdnoWp2hnYR6i1x8reDYfI6s0z31oj9Y= +github.com/caos/orbos v1.5.14-0.20210323084053-ddea4d17b402/go.mod h1:pydYnEk6rLwun8ur79Et0Fx7BaIJoLmeDWsNy7m4O0o= +github.com/caos/orbos v1.5.14-0.20210323105159-c63e531533ca h1:sJJwtfgWyB8JMDwG3A1+7R2eoJ/2ClOddM17DAHHY/E= +github.com/caos/orbos v1.5.14-0.20210323105159-c63e531533ca/go.mod h1:pydYnEk6rLwun8ur79Et0Fx7BaIJoLmeDWsNy7m4O0o= +github.com/caos/orbos v1.5.14-0.20210323144458-54a1193030e6 h1:P8Nx0ArLQfYaeuOIQWjZgvOnlnEswSM0r4JFcJrx+nc= +github.com/caos/orbos v1.5.14-0.20210323144458-54a1193030e6/go.mod h1:pydYnEk6rLwun8ur79Et0Fx7BaIJoLmeDWsNy7m4O0o= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= @@ -153,27 +181,26 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 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= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8= 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/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= 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= +github.com/cloudflare/cloudflare-go v0.12.1 h1:j6TfMkFbfoRYqC9wbktl59Nd7xIqPem0XXXvZ9Vtj1I= github.com/cloudflare/cloudflare-go v0.12.1/go.mod h1:gmzHQPAyHh8N8UgX0Z+3rSMRbNj47JDEbzXDICHVXys= +github.com/cloudscale-ch/cloudscale-go-sdk v1.6.0 h1:qKHn4YlgYKS0oHnOoDvPnL5jDUPpqGRn9RnKUgoPbKY= 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/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= -github.com/cockroachdb/cockroach-go/v2 v2.1.0 h1:zicZlBhWZu6wfK7Ezg4Owdc3HamLpRdBllPTT9tb+2k= github.com/cockroachdb/cockroach-go/v2 v2.1.0/go.mod h1:ilhrLnPDDwGHL+iK2UxQhp1UzUhst8sfItSAgCYwAyg= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= 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/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= 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= @@ -187,19 +214,14 @@ github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfc 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/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/creack/pty v1.1.7 h1:6pwm8kMQKCmgUg0ZHTm5+/YvRK0s3THD/28+T6/kk4A= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= -github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= 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/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/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-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= @@ -209,7 +231,6 @@ github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDD 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/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= -github.com/duo-labs/webauthn v0.0.0-20200714211715-1daaee874e43 h1:eEEfwrmEwl0LVuWz/VkAefdgtPbX174Huu5dxxceihI= github.com/duo-labs/webauthn v0.0.0-20200714211715-1daaee874e43/go.mod h1:/X2OJiJxjQ7alqWZqX9EtBTmZc+4qQ0LvZ1k5wP67RM= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= @@ -217,7 +238,6 @@ github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5m github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= -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/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= @@ -228,30 +248,28 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= -github.com/envoyproxy/protoc-gen-validate v0.1.0 h1:EQciDnbrYxy13PgWoY8AqoxGiPrpgBZ1R8UNe3ddc+A= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -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/evanphx/json-patch v4.2.0+incompatible h1:fUDGZCv/7iAN7u0puUVhvKCcsR6vRfwrJatElLBEf0I= github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQobrkAqrL+WFZwQses= +github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ= github.com/felixge/httpsnoop v1.0.1/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/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= -github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fxamacker/cbor/v2 v2.2.0 h1:6eXqdDDe588rSYAi1HfZKbx6YYQO4mxQ9eC6xYpU/JQ= +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/fxamacker/cbor/v2 v2.2.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -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/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= @@ -259,7 +277,6 @@ github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= github.com/go-git/go-billy/v5 v5.0.0 h1:7NQHvd9FVid8VL4qVUMm8XifBK+2xCoZ2lSk0agRrHM= github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= -github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12 h1:PbKy9zOy4aAKrJ5pibIRpVO2BXnK1Tlcg+caKI7Ox5M= 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= @@ -273,6 +290,10 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= 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= +github.com/go-logr/logr v0.3.0 h1:q4c+kbcR0d5rSurhBR8dIgieOaYpXtsdTYfx22Cu6rs= +github.com/go-logr/logr v0.3.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-logr/zapr v0.2.0/go.mod h1:qhKdvif7YF5GI9NWEpyxTSSBdGmzkNguibrdCNVPunU= 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= @@ -317,10 +338,10 @@ github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+ 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-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -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/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/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -328,9 +349,7 @@ github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= -github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -344,7 +363,6 @@ github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFU github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/mock v1.5.0 h1:jlYHihg//f7RRwuPfptm04yp4s7O6Kw8EZiVYIGcH0g= github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= @@ -366,14 +384,12 @@ github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.2 h1:aeE13tS0IiQgFjYdoL8qN3K1N2bXXtI6Vi51/y7BpMw= github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golangplus/bytes v0.0.0-20160111154220-45c989fe5450/go.mod h1:Bk6SMAONeMXrxql8uvOKuAZSu8aM5RUGv+1C6IJaEho= github.com/golangplus/fmt v0.0.0-20150411045040-2a5d6d7d2995/go.mod h1:lJgMEyOkYFkPcDKwRXegd+iM6E7matEszMG5HhwytU8= github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk= 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/certificate-transparency-go v1.0.21 h1:Yf1aXowfZ2nuboBsg7iYGLmwsOARdV86pfH3g95wXmE= github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -390,10 +406,8 @@ github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.1.0 h1:wCKgOCHuUEVfsaQLpPSJb7VdYCdTVZQAuOdYm1yc/60= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -406,7 +420,6 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 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= -github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -415,41 +428,37 @@ github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= -github.com/googleapis/gnostic v0.3.1 h1:WeAefnSUHlBb0iJKwxFDZdbfGwkd7xRNuV+IpXMJhYk= -github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU= -github.com/googleinterns/cloud-operations-api-mock v0.0.0-20200709193332-a1e58c29bdd3 h1:eHv/jVY/JNop1xg2J9cBb4EzyMpWZoNCP1BslSAIkOI= +github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= +github.com/googleapis/gnostic v0.5.1 h1:A8Yhf6EtqTv9RMsU6MQTyrtV1TjWlR6xU9BsZIwuTCM= +github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= 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/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= -github.com/gorilla/csrf v1.7.0 h1:mMPjV5/3Zd460xCavIkppUdvnl5fPXMpv2uz2Zyg7/Y= github.com/gorilla/csrf v1.7.0/go.mod h1:+a/4tCmqhG6/w4oafeAZ9pEa3/NZOWYVbD9fV0FwIQA= github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= -github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/schema v1.1.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU= -github.com/gorilla/schema v1.2.0 h1:YufUaxZYCKGFuAq3c96BOhjgd5nmXiOY9NGzF247Tsc= github.com/gorilla/schema v1.2.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU= -github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= 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.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 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.2.2 h1:FlFbCRLd5Jr4iYXZufAvgWN6Ao0JrI5chLINnUXDDr0= github.com/grpc-ecosystem/go-grpc-middleware v1.2.2/go.mod h1:EaizFBKfUKtMIF5iaDEhniwNedqGo9FuLFzppDr3uwI= 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/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= +github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= @@ -465,27 +474,25 @@ github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09 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/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= 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/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= 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.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= -github.com/inconshreveable/log15 v0.0.0-20200109203555-b30bc20e4fd1 h1:KUDFlmBg2buRWNzIcwLlKvfcnujcHQRQ1As1LoaCLAM= github.com/inconshreveable/log15 v0.0.0-20200109203555-b30bc20e4fd1/go.mod h1:cOaXtrgN4ScfRrD9Bre7U1thNq5RtJ8ZoP4iXVGRj6o= -github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= @@ -536,12 +543,9 @@ github.com/jackc/puddle v1.1.2/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dv 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/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= -github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= 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.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik= @@ -551,11 +555,9 @@ github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX 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= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfEUpgAwUN0o= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a h1:FaWFmfWdAUKbSCtOU2QjDaorUexogfaMgbipgYATUMU= @@ -565,15 +567,11 @@ github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8 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= -github.com/kevinburke/go-types v0.0.0-20200309064045-f2d4aea18a7a h1:Z7+SSApKiwPjNic+NF9+j7h657Uyvdp/jA3iTKhpj4E= github.com/kevinburke/go-types v0.0.0-20200309064045-f2d4aea18a7a/go.mod h1:/Pk5i/SqYdYv1cie5wGwoZ4P6TpgMi+Yf58mtJSHdOw= -github.com/kevinburke/go.uuid v1.2.0 h1:+1qP8NdkJfgOSTrrrUuA7h0djr1VY77HFXYjR+zUcUo= github.com/kevinburke/go.uuid v1.2.0/go.mod h1:9gVngk1Hq1FjwewVAjsWEUT+xc6jP+p62CASaGmQ0NQ= -github.com/kevinburke/rest v0.0.0-20200429221318-0d2892b400f8 h1:KpuDJTaTPQAyWqETt70dHX3pMz65/XYTAZymrKKNvh8= github.com/kevinburke/rest v0.0.0-20200429221318-0d2892b400f8/go.mod h1:pD+iEcdAGVXld5foVN4e24zb/6fnb60tgZPZ3P/3T/I= github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v2wtGp9Gmz1Ze3eVRAWJMLokvN3QjdzCHLY= github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= -github.com/kevinburke/twilio-go v0.0.0-20200810163702-320748330fac h1:qQ7NAZEHpTyDfmZBH79KEiH3OK47Z+KvYVSR4sS3650= github.com/kevinburke/twilio-go v0.0.0-20200810163702-320748330fac/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= @@ -583,14 +581,12 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxv github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 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/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.4/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= -github.com/kr/pty v1.1.8 h1:AkaSdXYQOWeaO3neb8EM634ahkXXe3jYbVh/F9lq+GI= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= 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/landoop/tableprinter v0.0.0-20200805134727-ea32388e35c1/go.mod h1:f0X1c0za3TbET/rl5ThtCSel0+G3/yZ8iuU9BxnyVK0= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= @@ -599,7 +595,6 @@ 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.4.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.9.0 h1:L8nSXQQzAYByakOFMTwpjRoHsMJklur4Gi59b6VivR8= github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= @@ -608,9 +603,9 @@ github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z 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-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= -github.com/magefile/mage v1.10.0 h1:3HiXzCUY12kh9bIuyXShaVe529fJfyqoVM42o/uom2g= github.com/magefile/mage v1.10.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= 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/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -640,15 +635,14 @@ github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus= -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/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= 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/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/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= -github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= @@ -658,11 +652,10 @@ github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUb github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= 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 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/mitchellh/reflectwalk v1.0.1 h1:FVzMWA5RllMAKIdUSC8mdWo3XtwoecrH79BY70sEEpE= github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo= 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= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -681,10 +674,9 @@ github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzE github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= -github.com/nicksnyder/go-i18n/v2 v2.1.1 h1:ATCOanRDlrfKVB4WHAdJnLEqZtDmKYsweqsOUYflnBU= github.com/nicksnyder/go-i18n/v2 v2.1.1/go.mod h1:d++QJC9ZVf7pa48qrsRWhMJ5pSHIPmS3OLqK1niyLxs= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= @@ -693,12 +685,16 @@ github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FW 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= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw= github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.14.1/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +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.10.2/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= @@ -728,14 +724,12 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= -github.com/pquerna/otp v1.2.0 h1:/A3+Jn+cagqayeR3iHs/L62m5ue7710D35zl1zJ1kok= github.com/pquerna/otp v1.2.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= -github.com/prometheus/client_golang v1.6.0/go.mod h1:ZLOG9ck3JLRdB5MgO8f+lLTe83AXG6ro35rLTxvnIl4= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.8.0 h1:zvJNkoCFAnYFNC24FV8nW4JdRJ3GIFcLbg65lL/JDcw= github.com/prometheus/client_golang v1.8.0/go.mod h1:O9VU6huf47PktckDQfMTX0Y8tY0/7TSWwj+ITvv0TnM= @@ -751,7 +745,6 @@ github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= -github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.14.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= github.com/prometheus/common v0.15.0 h1:4fgOnadei3EZvgRwxJ7RMpG1k1pOZth5Pc13tyspaKM= @@ -761,7 +754,6 @@ github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= -github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.2.0 h1:wH4vA7pcjKuZzjF7lM8awk4fnuJO6idemZXoKnULUx4= github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= @@ -772,7 +764,6 @@ github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqn github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= @@ -784,7 +775,6 @@ github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0 github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= 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= @@ -796,13 +786,11 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/sirupsen/logrus v1.8.0 h1:nfhvjKcUMhBMVqbKHJlk5RPrrfYr/NMo3692g0dwfWU= github.com/sirupsen/logrus v1.8.0/go.mod h1:4GuYW9TZmE769R5STWrRakJc4UqQ3+QQ95fyz7ENv1A= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= 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/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= -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/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= @@ -810,8 +798,9 @@ github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTd github.com/spf13/cast v1.3.0/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= -github.com/spf13/cobra v0.0.7 h1:FfTH+vuMXOas8jmfb5/M7dzEYx7LpcLb7a0LPe34uOU= -github.com/spf13/cobra v0.0.7/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/cobra v1.1.1 h1:KfztREH0tPxJJ+geloSLaAkaPkr4ki2Er5quFV1TDo4= +github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= 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= @@ -820,6 +809,8 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 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/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= @@ -831,16 +822,14 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= 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/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= 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/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.1.0 h1:tC6kE4t8UI4OqQVQjW5q8gSWhG2wnY5moEpSEORdYm4= github.com/ttacon/libphonenumber v1.1.0/go.mod h1:E0TpmdVMq5dyVlQ7oenAkhsLu86OkUl+yR4OAxyEg/M= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= @@ -849,7 +838,6 @@ github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtX github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= -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= @@ -863,7 +851,10 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec 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/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.etcd.io/etcd v0.5.0-alpha.5.0.20200819165624-17cef6e3e9d5/go.mod h1:skWido08r9w6Lq/w70DO5XYIKMu4QFu1+4VsqLQuJy8= +go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg= 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/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= @@ -877,33 +868,28 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5 h1:dntmOdLpSpHlVqbW5Eay97DelsZHe+55D+xC6i0dDS0= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opentelemetry.io/contrib v0.13.0 h1:q34CFu5REx9Dt2ksESHC/doIjFJkEg1oV3aSwlL5JR0= go.opentelemetry.io/contrib v0.13.0/go.mod h1:HzCu6ebm0ywgNxGaEfs3izyJOMP4rZnzxycyTgpI5Sg= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.13.0 h1:Ys1lnE8Y6rv3aKc9Ha13n7UM4pMHC0kvLSFtNx+gUfY= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.13.0/go.mod h1:ffigAFAlfY9AfFwJocEw88qbbvjAKfvqZg5tLyZv0l0= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.13.0 h1:dnZy1afzxEDrHybTYoJE1bQ3fphNwZF2ipSsynlITP4= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.13.0/go.mod h1:SeQm4RTCcZ2/hlMSTuHb7nwIROe5odBtgfKx+7MMqEs= -go.opentelemetry.io/otel v0.13.0 h1:2isEnyzjjJZq6r2EKMsFj4TxiQiexsM04AVhwbR/oBA= go.opentelemetry.io/otel v0.13.0/go.mod h1:dlSNewoRYikTkotEnxdmuBHgzT+k/idJSfDv/FxEnOY= -go.opentelemetry.io/otel/exporters/metric/prometheus v0.13.0 h1:Jf7AdsEoHKtNTWxXLj/g9XGjsGpdk0otEf0lx00r2Ps= go.opentelemetry.io/otel/exporters/metric/prometheus v0.13.0/go.mod h1:Tyh3ACxU9a1tu1mF4at7xvNu+BaiPThrr5XZmsoIW7g= -go.opentelemetry.io/otel/exporters/otlp v0.13.0 h1:iithmYmMAfLFgCW5TcRXHpXR5NTWO7nGtX3WcBiusVE= go.opentelemetry.io/otel/exporters/otlp v0.13.0/go.mod h1:YHH58UrGcqCKtBkY7sl3zPKpxBzfC1HUUYMRQONJJ9E= -go.opentelemetry.io/otel/exporters/stdout v0.13.0 h1:A+XiGIPQbGoJoBOJfKAKnZyiUSjSWvL3XWETUvtom5k= go.opentelemetry.io/otel/exporters/stdout v0.13.0/go.mod h1:JJt8RpNY6K+ft9ir3iKpceCvT/rhzJXEExGrWFCbv1o= -go.opentelemetry.io/otel/sdk v0.13.0 h1:4VCfpKamZ8GtnepXxMRurSpHpMKkcxhtO33z1S4rGDQ= go.opentelemetry.io/otel/sdk v0.13.0/go.mod h1:dKvLH8Uu8LcEPlSAUsfW7kMGaJBhk/1NYvpPZ6wIMbU= 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= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.8.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -924,10 +910,12 @@ golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191128160524-b544559bb6d1/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 h1:pLI5jrR7OSLijeIDcmRxNmw2api+jEfxLoykJVice/E= golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -952,7 +940,6 @@ golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/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/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= @@ -1003,6 +990,7 @@ golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= @@ -1011,8 +999,8 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201026091529-146b70c837a4/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201031054903-ff519b6c9102 h1:42cLlJJdEh+ySyeUUbEQ5bsTiq8voBeTuweGVkY6Puw= -golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b h1:uwuIcX0g4Yl1NC5XAz37xsr2lTtcqevgzYNVt49waME= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190517181255-950ef44c6e07/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1030,7 +1018,6 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1060,9 +1047,12 @@ golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191206220618-eeba5f6aabab/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1081,13 +1071,16 @@ golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1096,7 +1089,6 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -1126,6 +1118,7 @@ golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -1134,6 +1127,8 @@ golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -1154,8 +1149,11 @@ golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjs golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200616195046-dc31b401abb5/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200701151220-7cb253f4c4f8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200713011307-fd294ab11aed/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= @@ -1173,6 +1171,8 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gomodules.xyz/jsonpatch/v2 v2.1.0 h1:Phva6wqu+xR//Njw6iorylFFgn/z547tw5Ne3HZPQ+k= +gomodules.xyz/jsonpatch/v2 v2.1.0/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= @@ -1200,7 +1200,6 @@ google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -1239,8 +1238,8 @@ google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201030142918-24207fddd1c3/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201103154000-415bd0cd5df6 h1:rMoZiLTOobSD3eg30lPMcFkBFNSyKUQQIQlw/hsAXME= -google.golang.org/genproto v0.0.0-20201103154000-415bd0cd5df6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a h1:pOwg4OoaRYScjmR4LlLgdtnyoHYTSAVhhqe5uPdpII8= +google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= @@ -1279,22 +1278,19 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U= gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= 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/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= 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= +gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= 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.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w= gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= @@ -1308,14 +1304,16 @@ gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20190905181640-827449938966/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c h1:grhR+C34yXImVGp7EzNk+DTIk+323eIUWOmEevy6bDo= -gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gorm.io/driver/postgres v1.0.5/go.mod h1:qrD92UurYzNctBMVCJ8C3VQEjffEuphycXtxOudXNCA= gorm.io/gorm v1.20.4/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= gorm.io/gorm v1.20.6/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= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 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= @@ -1324,43 +1322,85 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh 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/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +k8s.io/api v0.18.2/go.mod h1:SJCWI7OLzhZSvbY7U8zwNl9UA4o1fizoug34OV/2r78= k8s.io/api v0.18.3/go.mod h1:UOaMwERbqJMfeeeHc8XJKawj4P9TgDRnViIqqBeH2QA= -k8s.io/api v0.18.5 h1:fKbCxr+U3fu7k6jB+QeYPD/c6xKYeSJ2KVWmyUypuWM= -k8s.io/api v0.18.5/go.mod h1:tN+e/2nbdGKOAH55NMV8oGrMG+3uRlA9GaRfvnCCSNk= -k8s.io/apiextensions-apiserver v0.18.5 h1:pvbXjB/BRXZiO+/Erp5Pxr+lnhDCv5uxNxHh3FLGZ/g= -k8s.io/apiextensions-apiserver v0.18.5/go.mod h1:woZ7PkEIMHjhHIyApvOwkGOkBLUYKuet0VWVkPTQ/Fs= +k8s.io/api v0.19.2/go.mod h1:IQpK0zFQ1xc5iNIQPqzgoOwuFugaYHK4iCknlAQP9nI= +k8s.io/api v0.20.1/go.mod h1:KqwcCVogGxQY3nBlRpwt+wpAMF/KjaCc7RpywacvqUo= +k8s.io/api v0.20.2 h1:y/HR22XDZY3pniu9hIFDLpUCPq2w5eQ6aV/VFQ7uJMw= +k8s.io/api v0.20.2/go.mod h1:d7n6Ehyzx+S+cE3VhTGfVNNqtGc/oL9DCdYYahlurV8= +k8s.io/apiextensions-apiserver v0.18.2/go.mod h1:q3faSnRGmYimiocj6cHQ1I3WpLqmDgJFlKL37fC4ZvY= +k8s.io/apiextensions-apiserver v0.19.2/go.mod h1:EYNjpqIAvNZe+svXVx9j4uBaVhTB4C94HkY3w058qcg= +k8s.io/apiextensions-apiserver v0.20.1 h1:ZrXQeslal+6zKM/HjDXLzThlz/vPSxrfK3OqL8txgVQ= +k8s.io/apiextensions-apiserver v0.20.1/go.mod h1:ntnrZV+6a3dB504qwC5PN/Yg9PBiDNt1EVqbW2kORVk= +k8s.io/apimachinery v0.18.2/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA= k8s.io/apimachinery v0.18.3/go.mod h1:OaXp26zu/5J7p0f92ASynJa1pZo06YlV9fG7BoWbCko= -k8s.io/apimachinery v0.18.5 h1:Lh6tgsM9FMkC12K5T5QjRm7rDs6aQN5JHkA0JomULDM= -k8s.io/apimachinery v0.18.5/go.mod h1:OaXp26zu/5J7p0f92ASynJa1pZo06YlV9fG7BoWbCko= -k8s.io/apiserver v0.18.5/go.mod h1:+1XgOMq7YJ3OyqPNSJ54EveHwCoBWcJT9CaPycYI5ps= +k8s.io/apimachinery v0.19.2/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= +k8s.io/apimachinery v0.20.1/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= +k8s.io/apimachinery v0.20.2 h1:hFx6Sbt1oG0n6DZ+g4bFt5f6BoMkOjKWsQFu077M3Vg= +k8s.io/apimachinery v0.20.2/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= +k8s.io/apiserver v0.18.2/go.mod h1:Xbh066NqrZO8cbsoenCwyDJ1OSi8Ag8I2lezeHxzwzw= +k8s.io/apiserver v0.19.2/go.mod h1:FreAq0bJ2vtZFj9Ago/X0oNGC51GfubKK/ViOKfVAOA= +k8s.io/apiserver v0.20.1/go.mod h1:ro5QHeQkgMS7ZGpvf4tSMx6bBOgPfE+f52KwvXfScaU= k8s.io/cli-runtime v0.18.3/go.mod h1:pqbbi4nqRIQhUWAVzen8uE8DD/zcZLwf+8sQYO4lwLk= +k8s.io/client-go v0.18.2/go.mod h1:Xcm5wVGXX9HAA2JJ2sSBUn3tCJ+4SVlCbl2MNNv+CIU= k8s.io/client-go v0.18.3/go.mod h1:4a/dpQEvzAhT1BbuWW09qvIaGw6Gbu1gZYiQZIi1DMw= -k8s.io/client-go v0.18.5 h1:cLhGZdOmyPhwtt20Lrb7uAqxxB1uvY+NTmNJvno1oKA= -k8s.io/client-go v0.18.5/go.mod h1:EsiD+7Fx+bRckKWZXnAXRKKetm1WuzPagH4iOSC8x58= +k8s.io/client-go v0.19.2/go.mod h1:S5wPhCqyDNAlzM9CnEdgTGV4OqhsW3jGO1UM1epwfJA= +k8s.io/client-go v0.20.1/go.mod h1:/zcHdt1TeWSd5HoUe6elJmHSQ6uLLgp4bIJHVEuy+/Y= +k8s.io/client-go v0.20.2 h1:uuf+iIAbfnCSw8IGAv/Rg0giM+2bOzHLOsbbrwrdhNQ= +k8s.io/client-go v0.20.2/go.mod h1:kH5brqWqp7HDxUFKoEgiI4v8G1xzbe9giaCenUWJzgE= +k8s.io/code-generator v0.18.2/go.mod h1:+UHX5rSbxmR8kzS+FAv7um6dtYrZokQvjHpDSYRVkTc= k8s.io/code-generator v0.18.3/go.mod h1:TgNEVx9hCyPGpdtCWA34olQYLkh3ok9ar7XfSsr8b6c= -k8s.io/code-generator v0.18.5/go.mod h1:TgNEVx9hCyPGpdtCWA34olQYLkh3ok9ar7XfSsr8b6c= +k8s.io/code-generator v0.19.2/go.mod h1:moqLn7w0t9cMs4+5CQyxnfA/HV8MF6aAVENF+WZZhgk= +k8s.io/code-generator v0.20.1/go.mod h1:UsqdF+VX4PU2g46NC2JRs4gc+IfrctnwHb76RNbWHJg= +k8s.io/component-base v0.18.2/go.mod h1:kqLlMuhJNHQ9lz8Z7V5bxUUtjFZnrypArGl58gmDfUM= k8s.io/component-base v0.18.3/go.mod h1:bp5GzGR0aGkYEfTj+eTY0AN/vXTgkJdQXjNTTVUaa3k= -k8s.io/component-base v0.18.5/go.mod h1:RSbcboNk4B+S8Acs2JaBOVW3XNz1+A637s2jL+QQrlU= +k8s.io/component-base v0.19.2/go.mod h1:g5LrsiTiabMLZ40AR6Hl45f088DevyGY+cCE2agEIVo= +k8s.io/component-base v0.20.1/go.mod h1:guxkoJnNoh8LNrbtiQOlyp2Y2XFCZQmrcg2n/DeYNLk= +k8s.io/component-base v0.20.2 h1:LMmu5I0pLtwjpp5009KLuMGFqSc2S2isGw8t1hpYKLE= +k8s.io/component-base v0.20.2/go.mod h1:pzFtCiwe/ASD0iV7ySMu8SYVJjCapNM9bjvk7ptpKh0= 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-20200428234225-8167cfdcfc14/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20201113003025-83324d819ded/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= k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= -k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6 h1:Oh3Mzx5pJ+yIumsAD0MOECPVeXsVot0UkiaCGVyfGQY= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/klog/v2 v2.4.0 h1:7+X0fUguPyrKEC4WjH8iGDg3laWgMo5tMnRTIGTTxGQ= +k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= +k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o= +k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd h1:sOHNzJIkytDF6qadMNKhhDRpc6ODik8lVC6nOur7B2c= +k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= k8s.io/kubectl v0.18.3/go.mod h1:k/EpvXBDgEsHBzWr0A44l9+ArvYi3txBBnzXBjQasUQ= k8s.io/metrics v0.18.3/go.mod h1:TkuJE3ezDZ1ym8pYkZoEzJB7HDiFE7qxl+EmExEBoPA= -k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89 h1:d4vVOjXm687F1iLSP2q3lyPPuyvTUt3aVoBpi2DqRsU= k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20200912215256-4140de9c8800/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20210111153108-fddb29f9d009 h1:0T5IaWHO3sJTEmCP6mUlBvMukxPKUQWqiI/YuiBNMiQ= +k8s.io/utils v0.0.0-20210111153108-fddb29f9d009/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/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= 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.9/go.mod h1:dzAXnQbTRyDlZPJX2SUPEqvnB+j7AJjtlox7PEwigU0= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= +sigs.k8s.io/controller-runtime v0.7.0/go.mod h1:pJ3YBrJiAqMAZKi6UVGuE98ZrroV1p+pIhoHsMm9wdU= +sigs.k8s.io/controller-runtime v0.8.1 h1:O0K2CJ2JavK8/Tf4LfcpAwRxOFBhv8DjyrbmE6Qw59s= +sigs.k8s.io/controller-runtime v0.8.1/go.mod h1:U/l+DUopBc1ecfRZ5aviA9JDmGFQKvLf5YkZNx2e0sU= +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 v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU= 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.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.0.2 h1:YHQV7Dajm86OuqnIR6zAelnDWBRjo+YhYV9PmGrh1s8= +sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/hack/boilerplate.go.txt b/hack/boilerplate.go.txt new file mode 100644 index 0000000000..767efde981 --- /dev/null +++ b/hack/boilerplate.go.txt @@ -0,0 +1,15 @@ +/* + + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ \ No newline at end of file diff --git a/operator/adapt.go b/operator/adapt.go index ca307249ab..c11b6c31f2 100644 --- a/operator/adapt.go +++ b/operator/adapt.go @@ -11,7 +11,7 @@ import ( "gopkg.in/yaml.v3" ) -type AdaptFunc func(monitor mntr.Monitor, desired *tree.Tree, current *tree.Tree) (QueryFunc, DestroyFunc, map[string]*secret.Secret, error) +type AdaptFunc func(monitor mntr.Monitor, desired *tree.Tree, current *tree.Tree) (QueryFunc, DestroyFunc, map[string]*secret.Secret, map[string]*secret.Existing, bool, error) type EnsureFunc func(k8sClient kubernetes.ClientInt) error diff --git a/operator/api/core/api.go b/operator/api/core/api.go new file mode 100644 index 0000000000..b57d269a45 --- /dev/null +++ b/operator/api/core/api.go @@ -0,0 +1,46 @@ +package core + +import ( + "errors" + + "github.com/caos/orbos/pkg/tree" + "gopkg.in/yaml.v3" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" +) + +func UnmarshalUnstructuredSpec(unstruct *unstructured.Unstructured) (*tree.Tree, error) { + spec, found := unstruct.Object["spec"] + if !found { + return nil, errors.New("no spec in crd") + } + specMap, ok := spec.(map[string]interface{}) + if !ok { + return nil, errors.New("no spec in crd") + } + + data, err := yaml.Marshal(specMap) + if err != nil { + return nil, err + } + + desired := &tree.Tree{} + if err := yaml.Unmarshal(data, &desired); err != nil { + return nil, err + } + + return desired, nil +} + +func MarshalToUnstructuredSpec(t *tree.Tree) (*unstructured.Unstructured, error) { + data, err := yaml.Marshal(t) + if err != nil { + return nil, err + } + + unstruct := &unstructured.Unstructured{ + Object: map[string]interface{}{ + "spec": make(map[string]interface{}), + }, + } + return unstruct, yaml.Unmarshal(data, unstruct.Object["spec"]) +} diff --git a/operator/api/database/api.go b/operator/api/database/api.go new file mode 100644 index 0000000000..7db8431904 --- /dev/null +++ b/operator/api/database/api.go @@ -0,0 +1,44 @@ +package database + +import ( + "github.com/caos/orbos/pkg/kubernetes" + "github.com/caos/orbos/pkg/tree" + "github.com/caos/zitadel/operator/api/core" + databasev1 "github.com/caos/zitadel/operator/api/database/v1" + macherrs "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/api/meta" +) + +const ( + Namespace = "caos-system" + kind = "Database" + apiVersion = "caos.ch/v1" + Name = "database" +) + +func ReadCrd(k8sClient kubernetes.ClientInt) (*tree.Tree, error) { + unstruct, err := k8sClient.GetNamespacedCRDResource(databasev1.GroupVersion.Group, databasev1.GroupVersion.Version, kind, Namespace, Name) + if err != nil { + if macherrs.IsNotFound(err) || meta.IsNoMatchError(err) { + return nil, nil + } + return nil, err + } + + return core.UnmarshalUnstructuredSpec(unstruct) +} + +func WriteCrd(k8sClient kubernetes.ClientInt, t *tree.Tree) error { + + unstruct, err := core.MarshalToUnstructuredSpec(t) + if err != nil { + return err + } + + unstruct.SetName(Name) + unstruct.SetNamespace(Namespace) + unstruct.SetKind(kind) + unstruct.SetAPIVersion(apiVersion) + + return k8sClient.ApplyNamespacedCRDResource(databasev1.GroupVersion.Group, databasev1.GroupVersion.Version, kind, Namespace, Name, unstruct) +} diff --git a/operator/api/database/v1/database.go b/operator/api/database/v1/database.go new file mode 100644 index 0000000000..569dc07984 --- /dev/null +++ b/operator/api/database/v1/database.go @@ -0,0 +1,57 @@ +// +kubebuilder:object:generate=true +// +groupName=caos.ch +package v1 + +import ( + "github.com/caos/orbos/pkg/tree" + orbdb "github.com/caos/zitadel/operator/database/kinds/orb" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/scheme" +) + +var ( + // GroupVersion is group version used to register these objects + GroupVersion = schema.GroupVersion{Group: "caos.ch", Version: "v1"} + + // SchemeBuilder is used to add go types to the GroupVersionKind scheme + SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} + + // AddToScheme adds the types in this group-version to the given scheme. + AddToScheme = SchemeBuilder.AddToScheme +) + +// +kubebuilder:storageversion +// +kubebuilder:object:root=true +// +kubebuilder:crd=Database +type Database struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec Spec `json:"spec,omitempty"` + Status Status `json:"status,omitempty"` +} + +type Status struct { + // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster + // Important: Run "make" to regenerate code after modifying this file +} + +type Spec struct { + Common *tree.Common `json:",inline" yaml:",inline"` + Spec *orbdb.Spec `json:"spec" yaml:"spec"` + Database *Empty `json:"database" yaml:"database"` +} + +type Empty struct{} + +// +kubebuilder:object:root=true +type DatabaseList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Database `json:"items"` +} + +func init() { + SchemeBuilder.Register(&Database{}, &DatabaseList{}) +} diff --git a/operator/api/database/v1/zz_generated.deepcopy.go b/operator/api/database/v1/zz_generated.deepcopy.go new file mode 100644 index 0000000000..c97c16b038 --- /dev/null +++ b/operator/api/database/v1/zz_generated.deepcopy.go @@ -0,0 +1,146 @@ +// +build !ignore_autogenerated + +/* + + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package v1 + +import ( + "github.com/caos/orbos/pkg/tree" + "github.com/caos/zitadel/operator/database/kinds/orb" + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Database) DeepCopyInto(out *Database) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + out.Status = in.Status +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Database. +func (in *Database) DeepCopy() *Database { + if in == nil { + return nil + } + out := new(Database) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Database) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DatabaseList) DeepCopyInto(out *DatabaseList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Database, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DatabaseList. +func (in *DatabaseList) DeepCopy() *DatabaseList { + if in == nil { + return nil + } + out := new(DatabaseList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *DatabaseList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Empty) DeepCopyInto(out *Empty) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Empty. +func (in *Empty) DeepCopy() *Empty { + if in == nil { + return nil + } + out := new(Empty) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Spec) DeepCopyInto(out *Spec) { + *out = *in + if in.Common != nil { + in, out := &in.Common, &out.Common + *out = new(tree.Common) + **out = **in + } + if in.Spec != nil { + in, out := &in.Spec, &out.Spec + *out = new(orb.Spec) + (*in).DeepCopyInto(*out) + } + if in.Database != nil { + in, out := &in.Database, &out.Database + *out = new(Empty) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Spec. +func (in *Spec) DeepCopy() *Spec { + if in == nil { + return nil + } + out := new(Spec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Status) DeepCopyInto(out *Status) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Status. +func (in *Status) DeepCopy() *Status { + if in == nil { + return nil + } + out := new(Status) + in.DeepCopyInto(out) + return out +} diff --git a/operator/api/zitadel/api.go b/operator/api/zitadel/api.go new file mode 100644 index 0000000000..32cff71582 --- /dev/null +++ b/operator/api/zitadel/api.go @@ -0,0 +1,44 @@ +package zitadel + +import ( + "github.com/caos/orbos/pkg/kubernetes" + "github.com/caos/orbos/pkg/tree" + "github.com/caos/zitadel/operator/api/core" + zitadelv1 "github.com/caos/zitadel/operator/api/zitadel/v1" + macherrs "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/api/meta" +) + +const ( + Namespace = "caos-system" + kind = "Zitadel" + apiVersion = "caos.ch/v1" + Name = "zitadel" +) + +func ReadCrd(k8sClient kubernetes.ClientInt) (*tree.Tree, error) { + unstruct, err := k8sClient.GetNamespacedCRDResource(zitadelv1.GroupVersion.Group, zitadelv1.GroupVersion.Version, kind, Namespace, Name) + if err != nil { + if macherrs.IsNotFound(err) || meta.IsNoMatchError(err) { + return nil, nil + } + return nil, err + } + + return core.UnmarshalUnstructuredSpec(unstruct) +} + +func WriteCrd(k8sClient kubernetes.ClientInt, t *tree.Tree) error { + + unstruct, err := core.MarshalToUnstructuredSpec(t) + if err != nil { + return err + } + + unstruct.SetName(Name) + unstruct.SetNamespace(Namespace) + unstruct.SetKind(kind) + unstruct.SetAPIVersion(apiVersion) + + return k8sClient.ApplyNamespacedCRDResource(zitadelv1.GroupVersion.Group, zitadelv1.GroupVersion.Version, kind, Namespace, Name, unstruct) +} diff --git a/operator/api/zitadel/v1/zitadel.go b/operator/api/zitadel/v1/zitadel.go new file mode 100644 index 0000000000..22e1135ba1 --- /dev/null +++ b/operator/api/zitadel/v1/zitadel.go @@ -0,0 +1,57 @@ +// +kubebuilder:object:generate=true +// +groupName=caos.ch +package v1 + +import ( + "github.com/caos/orbos/pkg/tree" + orbz "github.com/caos/zitadel/operator/zitadel/kinds/orb" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/scheme" +) + +var ( + // GroupVersion is group version used to register these objects + GroupVersion = schema.GroupVersion{Group: "caos.ch", Version: "v1"} + + // SchemeBuilder is used to add go types to the GroupVersionKind scheme + SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} + + // AddToScheme adds the types in this group-version to the given scheme. + AddToScheme = SchemeBuilder.AddToScheme +) + +// +kubebuilder:storageversion +// +kubebuilder:object:root=true +// +kubebuilder:crd=Zitadel +type Zitadel struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec Spec `json:"spec,omitempty"` + Status Status `json:"status,omitempty"` +} + +type Status struct { + // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster + // Important: Run "make" to regenerate code after modifying this file +} + +type Spec struct { + Common *tree.Common `json:",inline" yaml:",inline"` + Spec *orbz.Spec `json:"spec" yaml:"spec"` + IAM *Empty `json:"iam" yaml:"iam"` +} + +type Empty struct{} + +// +kubebuilder:object:root=true +type ZitadelList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Zitadel `json:"items"` +} + +func init() { + SchemeBuilder.Register(&Zitadel{}, &ZitadelList{}) +} diff --git a/operator/api/zitadel/v1/zz_generated.deepcopy.go b/operator/api/zitadel/v1/zz_generated.deepcopy.go new file mode 100644 index 0000000000..f9a3bc874b --- /dev/null +++ b/operator/api/zitadel/v1/zz_generated.deepcopy.go @@ -0,0 +1,146 @@ +// +build !ignore_autogenerated + +/* + + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package v1 + +import ( + "github.com/caos/orbos/pkg/tree" + "github.com/caos/zitadel/operator/zitadel/kinds/orb" + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Empty) DeepCopyInto(out *Empty) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Empty. +func (in *Empty) DeepCopy() *Empty { + if in == nil { + return nil + } + out := new(Empty) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Spec) DeepCopyInto(out *Spec) { + *out = *in + if in.Common != nil { + in, out := &in.Common, &out.Common + *out = new(tree.Common) + **out = **in + } + if in.Spec != nil { + in, out := &in.Spec, &out.Spec + *out = new(orb.Spec) + (*in).DeepCopyInto(*out) + } + if in.IAM != nil { + in, out := &in.IAM, &out.IAM + *out = new(Empty) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Spec. +func (in *Spec) DeepCopy() *Spec { + if in == nil { + return nil + } + out := new(Spec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Status) DeepCopyInto(out *Status) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Status. +func (in *Status) DeepCopy() *Status { + if in == nil { + return nil + } + out := new(Status) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Zitadel) DeepCopyInto(out *Zitadel) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + out.Status = in.Status +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Zitadel. +func (in *Zitadel) DeepCopy() *Zitadel { + if in == nil { + return nil + } + out := new(Zitadel) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Zitadel) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ZitadelList) DeepCopyInto(out *ZitadelList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Zitadel, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZitadelList. +func (in *ZitadelList) DeepCopy() *ZitadelList { + if in == nil { + return nil + } + out := new(ZitadelList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ZitadelList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} diff --git a/operator/crtlcrd/controller.go b/operator/crtlcrd/controller.go new file mode 100644 index 0000000000..5a2be9389c --- /dev/null +++ b/operator/crtlcrd/controller.go @@ -0,0 +1,74 @@ +package crtlcrd + +import ( + "github.com/caos/orbos/mntr" + "github.com/caos/orbos/pkg/kubernetes" + databasev1 "github.com/caos/zitadel/operator/api/database/v1" + zitadelv1 "github.com/caos/zitadel/operator/api/zitadel/v1" + "github.com/caos/zitadel/operator/crtlcrd/database" + "github.com/caos/zitadel/operator/crtlcrd/zitadel" + "github.com/pkg/errors" + "k8s.io/apimachinery/pkg/runtime" + clientgoscheme "k8s.io/client-go/kubernetes/scheme" + ctrl "sigs.k8s.io/controller-runtime" +) + +const ( + Database = "database" + Zitadel = "zitadel" +) + +var ( + scheme = runtime.NewScheme() +) + +func init() { + _ = clientgoscheme.AddToScheme(scheme) + + _ = databasev1.AddToScheme(scheme) + _ = zitadelv1.AddToScheme(scheme) +} + +func Start(monitor mntr.Monitor, version, metricsAddr string, features ...string) error { + cfg := ctrl.GetConfigOrDie() + mgr, err := ctrl.NewManager(cfg, ctrl.Options{ + Scheme: scheme, + MetricsBindAddress: metricsAddr, + Port: 9443, + LeaderElection: false, + LeaderElectionID: "9adsd12l.caos.ch", + }) + if err != nil { + return errors.Wrap(err, "unable to start manager") + } + + k8sClient := kubernetes.NewK8sClientWithConfig(monitor, cfg) + + for _, feature := range features { + switch feature { + case Database: + if err = (&database.Reconciler{ + ClientInt: k8sClient, + Monitor: monitor, + Scheme: mgr.GetScheme(), + Version: version, + }).SetupWithManager(mgr); err != nil { + return errors.Wrap(err, "unable to create controller") + } + case Zitadel: + if err = (&zitadel.Reconciler{ + ClientInt: k8sClient, + Monitor: monitor, + Scheme: mgr.GetScheme(), + Version: version, + }).SetupWithManager(mgr); err != nil { + return errors.Wrap(err, "unable to create controller") + } + } + } + + if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil { + return errors.Wrap(err, "problem running manager") + } + return nil +} diff --git a/operator/crtlcrd/database/database.go b/operator/crtlcrd/database/database.go new file mode 100644 index 0000000000..89c136a612 --- /dev/null +++ b/operator/crtlcrd/database/database.go @@ -0,0 +1,68 @@ +package database + +import ( + "context" + "fmt" + + "github.com/caos/orbos/mntr" + "github.com/caos/orbos/pkg/kubernetes" + "github.com/caos/orbos/pkg/tree" + "github.com/caos/zitadel/operator/api/database" + v1 "github.com/caos/zitadel/operator/api/database/v1" + orbdb "github.com/caos/zitadel/operator/database/kinds/orb" + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" +) + +type Reconciler struct { + kubernetes.ClientInt + Monitor mntr.Monitor + Scheme *runtime.Scheme + Version string +} + +func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (res ctrl.Result, err error) { + internalMonitor := r.Monitor.WithFields(map[string]interface{}{ + "kind": "database", + "namespace": req.NamespacedName, + }) + + defer func() { + r.Monitor.Error(err) + }() + + if req.Namespace != database.Namespace || req.Name != database.Name { + return res, fmt.Errorf("resource must be named %s and namespaced in %s", database.Name, database.Namespace) + } + + desired, err := database.ReadCrd(r.ClientInt) + if err != nil { + internalMonitor.Error(err) + return res, err + } + + query, _, _, _, _, err := orbdb.AdaptFunc("", &r.Version, false, "database")(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) + return res, err + } + + return res, nil +} + +func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&v1.Database{}). + Complete(r) +} diff --git a/operator/crtlcrd/zitadel/zitadel.go b/operator/crtlcrd/zitadel/zitadel.go new file mode 100644 index 0000000000..9d58dc4cf6 --- /dev/null +++ b/operator/crtlcrd/zitadel/zitadel.go @@ -0,0 +1,67 @@ +package zitadel + +import ( + "context" + "fmt" + + "github.com/caos/orbos/mntr" + "github.com/caos/orbos/pkg/kubernetes" + "github.com/caos/orbos/pkg/tree" + "github.com/caos/zitadel/operator/api/zitadel" + v1 "github.com/caos/zitadel/operator/api/zitadel/v1" + orbz "github.com/caos/zitadel/operator/zitadel/kinds/orb" + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" +) + +type Reconciler struct { + kubernetes.ClientInt + Monitor mntr.Monitor + Scheme *runtime.Scheme + Version string +} + +func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (res ctrl.Result, err error) { + internalMonitor := r.Monitor.WithFields(map[string]interface{}{ + "kind": "zitadel", + "namespace": req.NamespacedName, + }) + + defer func() { + r.Monitor.Error(err) + }() + + if req.Namespace != zitadel.Namespace || req.Name != zitadel.Name { + 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) + return res, err + } + + return res, nil +} + +func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&v1.Zitadel{}). + Complete(r) +} diff --git a/operator/start/start.go b/operator/crtlgitops/start.go similarity index 81% rename from operator/start/start.go rename to operator/crtlgitops/start.go index 9f5a7c3d80..986313b4d4 100644 --- a/operator/start/start.go +++ b/operator/crtlgitops/start.go @@ -1,11 +1,12 @@ -package start +package crtlgitops import ( "context" + "time" + "github.com/caos/zitadel/operator/database" orbdb "github.com/caos/zitadel/operator/database/kinds/orb" "github.com/caos/zitadel/operator/zitadel" - "time" "github.com/caos/orbos/mntr" "github.com/caos/orbos/pkg/git" @@ -16,7 +17,7 @@ import ( kubernetes2 "github.com/caos/zitadel/pkg/kubernetes" ) -func Operator(monitor mntr.Monitor, orbConfigPath string, k8sClient *kubernetes.Client, version *string) error { +func Operator(monitor mntr.Monitor, orbConfigPath string, k8sClient *kubernetes.Client, version *string, gitops bool) error { takeoffChan := make(chan struct{}) go func() { takeoffChan <- struct{}{} @@ -35,7 +36,7 @@ func Operator(monitor mntr.Monitor, orbConfigPath string, k8sClient *kubernetes. return err } - takeoff := zitadel.Takeoff(monitor, gitClient, orb.AdaptFunc(orbConfig, "ensure", version, []string{"operator", "iam"}), k8sClient) + takeoff := zitadel.Takeoff(monitor, gitClient, orb.AdaptFunc(orbConfig, "ensure", version, gitops, []string{"operator", "iam"}), k8sClient) go func() { started := time.Now() @@ -53,7 +54,15 @@ func Operator(monitor mntr.Monitor, orbConfigPath string, k8sClient *kubernetes. return nil } -func Restore(monitor mntr.Monitor, gitClient *git.Client, orbCfg *orbconfig.Orb, k8sClient *kubernetes.Client, backup string, version *string) error { +func Restore( + monitor mntr.Monitor, + gitClient *git.Client, + orbCfg *orbconfig.Orb, + k8sClient *kubernetes.Client, + backup string, + gitops bool, + version *string, +) error { databasesList := []string{ "notification", "adminapi", @@ -67,7 +76,7 @@ func Restore(monitor mntr.Monitor, gitClient *git.Client, orbCfg *orbconfig.Orb, return err } - if err := zitadel.Takeoff(monitor, gitClient, orb.AdaptFunc(orbCfg, "scaledown", version, []string{"scaledown"}), k8sClient)(); err != nil { + if err := zitadel.Takeoff(monitor, gitClient, orb.AdaptFunc(orbCfg, "scaledown", version, gitops, []string{"scaledown"}), k8sClient)(); err != nil { return err } @@ -75,7 +84,7 @@ func Restore(monitor mntr.Monitor, gitClient *git.Client, orbCfg *orbconfig.Orb, return err } - if err := zitadel.Takeoff(monitor, gitClient, orb.AdaptFunc(orbCfg, "migration", version, []string{"migration"}), k8sClient)(); err != nil { + if err := zitadel.Takeoff(monitor, gitClient, orb.AdaptFunc(orbCfg, "migration", version, gitops, []string{"migration"}), k8sClient)(); err != nil { return err } @@ -89,7 +98,7 @@ func Restore(monitor mntr.Monitor, gitClient *git.Client, orbCfg *orbconfig.Orb, return err } - if err := zitadel.Takeoff(monitor, gitClient, orb.AdaptFunc(orbCfg, "scaleup", version, []string{"scaleup"}), k8sClient)(); err != nil { + if err := zitadel.Takeoff(monitor, gitClient, orb.AdaptFunc(orbCfg, "scaleup", version, gitops, []string{"scaleup"}), k8sClient)(); err != nil { return err } @@ -100,7 +109,7 @@ func Restore(monitor mntr.Monitor, gitClient *git.Client, orbCfg *orbconfig.Orb, return nil } -func Database(monitor mntr.Monitor, orbConfigPath string, k8sClient *kubernetes.Client, binaryVersion *string) error { +func Database(monitor mntr.Monitor, orbConfigPath string, k8sClient *kubernetes.Client, binaryVersion *string, gitops bool) error { takeoffChan := make(chan struct{}) go func() { takeoffChan <- struct{}{} @@ -119,7 +128,7 @@ func Database(monitor mntr.Monitor, orbConfigPath string, k8sClient *kubernetes. return err } - takeoff := database.Takeoff(monitor, gitClient, orbdb.AdaptFunc("", binaryVersion, "database", "backup"), k8sClient) + takeoff := database.Takeoff(monitor, gitClient, orbdb.AdaptFunc("", binaryVersion, gitops, "operator", "database", "backup"), k8sClient) go func() { started := time.Now() @@ -150,6 +159,6 @@ func Backup(monitor mntr.Monitor, orbConfigPath string, k8sClient *kubernetes.Cl return err } - database.Takeoff(monitor, gitClient, orbdb.AdaptFunc(backup, binaryVersion, "instantbackup"), k8sClient)() + database.Takeoff(monitor, gitClient, orbdb.AdaptFunc(backup, binaryVersion, false, "instantbackup"), k8sClient)() return nil } diff --git a/operator/database/kinds/backups/backups.go b/operator/database/kinds/backups/backups.go index 2a5e57ab34..14bcdc5021 100644 --- a/operator/database/kinds/backups/backups.go +++ b/operator/database/kinds/backups/backups.go @@ -28,6 +28,8 @@ func GetQueryAndDestroyFuncs( operator.QueryFunc, operator.DestroyFunc, map[string]*secret.Secret, + map[string]*secret.Existing, + bool, error, ) { switch desiredTree.Common.Kind { @@ -50,7 +52,7 @@ func GetQueryAndDestroyFuncs( features, )(monitor, desiredTree, currentTree) default: - return nil, nil, nil, errors.Errorf("unknown database kind %s", desiredTree.Common.Kind) + return nil, nil, nil, nil, false, errors.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 ca685cc129..03c08446ee 100644 --- a/operator/database/kinds/backups/bucket/adapt.go +++ b/operator/database/kinds/backups/bucket/adapt.go @@ -2,6 +2,7 @@ package bucket import ( "github.com/caos/orbos/mntr" + "github.com/caos/orbos/pkg/helper" "github.com/caos/orbos/pkg/kubernetes" "github.com/caos/orbos/pkg/kubernetes/resources/secret" "github.com/caos/orbos/pkg/labels" @@ -32,28 +33,36 @@ func AdaptFunc( version string, features []string, ) operator.AdaptFunc { - return func(monitor mntr.Monitor, desired *tree.Tree, current *tree.Tree) (queryFunc operator.QueryFunc, destroyFunc operator.DestroyFunc, secrets map[string]*secretpkg.Secret, err error) { + return func( + monitor mntr.Monitor, + desired *tree.Tree, + current *tree.Tree, + ) ( + operator.QueryFunc, + operator.DestroyFunc, + 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, errors.Wrap(err, "parsing desired state failed") + return nil, nil, nil, nil, false, errors.Wrap(err, "parsing desired state failed") } desired.Parsed = desiredKind + secrets, existing := getSecretsMap(desiredKind) + if !monitor.IsVerbose() && desiredKind.Spec.Verbose { internalMonitor.Verbose() } destroyS, err := secret.AdaptFuncToDestroy(namespace, secretName) if err != nil { - return nil, nil, nil, err - } - - queryS, err := secret.AdaptFuncToEnsure(namespace, labels.MustForName(componentLabels, secretName), map[string]string{secretKey: desiredKind.Spec.ServiceAccountJSON.Value}) - if err != nil { - return nil, nil, nil, err + return nil, nil, nil, nil, false, err } _, destroyB, err := backup.AdaptFunc( @@ -74,7 +83,7 @@ func AdaptFunc( version, ) if err != nil { - return nil, nil, nil, err + return nil, nil, nil, nil, false, err } _, destroyR, err := restore.AdaptFunc( @@ -93,7 +102,7 @@ func AdaptFunc( version, ) if err != nil { - return nil, nil, nil, err + return nil, nil, nil, nil, false, err } _, destroyC, err := clean.AdaptFunc( @@ -110,7 +119,7 @@ func AdaptFunc( version, ) if err != nil { - return nil, nil, nil, err + return nil, nil, nil, nil, false, err } destroyers := make([]operator.DestroyFunc, 0) @@ -133,6 +142,11 @@ func AdaptFunc( } return func(k8sClient kubernetes.ClientInt, queried map[string]interface{}) (operator.EnsureFunc, error) { + + if err := desiredKind.validateSecrets(); err != nil { + return nil, err + } + currentDB, err := coreDB.ParseQueriedForDatabase(queried) if err != nil { return nil, err @@ -143,6 +157,16 @@ func AdaptFunc( databases = []string{} } + value, err := helper.GetSecretValue(k8sClient, desiredKind.Spec.ServiceAccountJSON, desiredKind.Spec.ExistingServiceAccountJSON) + if err != nil { + return nil, err + } + + queryS, err := secret.AdaptFuncToEnsure(namespace, labels.MustForName(componentLabels, secretName), map[string]string{secretKey: value}) + if err != nil { + return nil, err + } + queryB, _, err := backup.AdaptFunc( internalMonitor, name, @@ -201,30 +225,53 @@ func AdaptFunc( } 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, backup.Instant: + 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 _, cleanup := range cleanupQueries { + queriers = append(queriers, cleanup) + } + return operator.QueriersToEnsureFunc(internalMonitor, false, queriers, k8sClient, queried) }, operator.DestroyersToDestroyFunc(internalMonitor, destroyers), - getSecretsMap(desiredKind), + secrets, + existing, + false, nil } } diff --git a/operator/database/kinds/backups/bucket/adapt_test.go b/operator/database/kinds/backups/bucket/adapt_test.go index 461d89cdd9..4a88bf6309 100644 --- a/operator/database/kinds/backups/bucket/adapt_test.go +++ b/operator/database/kinds/backups/bucket/adapt_test.go @@ -1,6 +1,8 @@ package bucket import ( + "testing" + "github.com/caos/orbos/mntr" "github.com/caos/orbos/pkg/kubernetes" kubernetesmock "github.com/caos/orbos/pkg/kubernetes/mock" @@ -13,7 +15,6 @@ import ( "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" corev1 "k8s.io/api/core/v1" - "testing" ) func TestBucket_Secrets(t *testing.T) { @@ -60,7 +61,7 @@ func TestBucket_Secrets(t *testing.T) { "serviceaccountjson": saJson, } - _, _, secrets, err := AdaptFunc( + _, _, secrets, existing, _, err := AdaptFunc( backupName, namespace, componentLabels, @@ -78,6 +79,7 @@ func TestBucket_Secrets(t *testing.T) { 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) } } @@ -131,7 +133,7 @@ func TestBucket_AdaptBackup(t *testing.T) { SetBackup(client, namespace, k8sLabels, saJson) - query, _, _, err := AdaptFunc( + query, _, _, _, _, err := AdaptFunc( backupName, namespace, componentLabels, @@ -205,7 +207,7 @@ func TestBucket_AdaptInstantBackup(t *testing.T) { SetInstantBackup(client, namespace, backupName, k8sLabels, saJson) - query, _, _, err := AdaptFunc( + query, _, _, _, _, err := AdaptFunc( backupName, namespace, componentLabels, @@ -280,7 +282,7 @@ func TestBucket_AdaptRestore(t *testing.T) { SetRestore(client, namespace, backupName, k8sLabels, saJson) - query, _, _, err := AdaptFunc( + query, _, _, _, _, err := AdaptFunc( backupName, namespace, componentLabels, @@ -316,6 +318,15 @@ func TestBucket_AdaptClean(t *testing.T) { 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"} @@ -344,9 +355,9 @@ func TestBucket_AdaptClean(t *testing.T) { return nil } - SetClean(client, namespace, backupName) + SetClean(client, namespace, backupName, k8sLabels, saJson) - query, _, _, err := AdaptFunc( + query, _, _, _, _, err := AdaptFunc( backupName, namespace, componentLabels, diff --git a/operator/database/kinds/backups/bucket/backup/adapt.go b/operator/database/kinds/backups/bucket/backup/adapt.go index 76dab6cc3f..31732b9db5 100644 --- a/operator/database/kinds/backups/bucket/backup/adapt.go +++ b/operator/database/kinds/backups/bucket/backup/adapt.go @@ -22,7 +22,7 @@ const ( internalSecretName = "client-certs" image = "ghcr.io/caos/zitadel-crbackup" rootSecretName = "cockroachdb.client.root" - timeout time.Duration = 60 + timeout time.Duration = 1200 Normal = "backup" Instant = "instantbackup" ) @@ -119,7 +119,6 @@ func AdaptFunc( queriers = append(queriers, operator.EnsureFuncToQueryFunc(checkDBReady), operator.ResourceQueryToZitadelQuery(queryJ), - operator.EnsureFuncToQueryFunc(getCleanupFunc(monitor, jobDef.Namespace, jobDef.Name)), ) } } diff --git a/operator/database/kinds/backups/bucket/backup/adapt_test.go b/operator/database/kinds/backups/bucket/backup/adapt_test.go index 79912f5af0..76b6f55bb0 100644 --- a/operator/database/kinds/backups/bucket/backup/adapt_test.go +++ b/operator/database/kinds/backups/bucket/backup/adapt_test.go @@ -1,6 +1,8 @@ package backup import ( + "testing" + "github.com/caos/orbos/mntr" "github.com/caos/orbos/pkg/kubernetes" kubernetesmock "github.com/caos/orbos/pkg/kubernetes/mock" @@ -10,7 +12,6 @@ import ( corev1 "k8s.io/api/core/v1" macherrs "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/runtime/schema" - "testing" ) func TestBackup_AdaptInstantBackup1(t *testing.T) { @@ -60,8 +61,6 @@ func TestBackup_AdaptInstantBackup1(t *testing.T) { 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)) - client.EXPECT().WaitUntilJobCompleted(jobDef.Namespace, jobDef.Name, timeout).Times(1).Return(nil) - client.EXPECT().DeleteJob(jobDef.Namespace, jobDef.Name).Times(1).Return(nil) query, _, err := AdaptFunc( monitor, @@ -134,8 +133,6 @@ func TestBackup_AdaptInstantBackup2(t *testing.T) { 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)) - client.EXPECT().WaitUntilJobCompleted(jobDef.Namespace, jobDef.Name, timeout).Times(1).Return(nil) - client.EXPECT().DeleteJob(jobDef.Namespace, jobDef.Name).Times(1).Return(nil) query, _, err := AdaptFunc( monitor, diff --git a/operator/database/kinds/backups/bucket/backup/cleanup.go b/operator/database/kinds/backups/bucket/backup/cleanup.go index 8a833bd86e..f87ee24589 100644 --- a/operator/database/kinds/backups/bucket/backup/cleanup.go +++ b/operator/database/kinds/backups/bucket/backup/cleanup.go @@ -7,15 +7,19 @@ import ( "github.com/pkg/errors" ) -func getCleanupFunc(monitor mntr.Monitor, namespace string, name string) operator.EnsureFunc { +func GetCleanupFunc( + monitor mntr.Monitor, + namespace string, + backupName string, +) operator.EnsureFunc { return func(k8sClient kubernetes.ClientInt) error { monitor.Info("waiting for backup to be completed") - if err := k8sClient.WaitUntilJobCompleted(namespace, name, timeout); err != nil { + if err := k8sClient.WaitUntilJobCompleted(namespace, GetJobName(backupName), timeout); err != nil { monitor.Error(errors.Wrap(err, "error while waiting for backup to be completed")) return err } monitor.Info("backup is completed, cleanup") - if err := k8sClient.DeleteJob(namespace, name); err != nil { + if err := k8sClient.DeleteJob(namespace, GetJobName(backupName)); err != nil { monitor.Error(errors.Wrap(err, "error while trying to cleanup backup")) return err } diff --git a/operator/database/kinds/backups/bucket/backup/cleanup_test.go b/operator/database/kinds/backups/bucket/backup/cleanup_test.go index 2975b380a6..39afa20f4e 100644 --- a/operator/database/kinds/backups/bucket/backup/cleanup_test.go +++ b/operator/database/kinds/backups/bucket/backup/cleanup_test.go @@ -1,12 +1,13 @@ package backup import ( + "testing" + "github.com/caos/orbos/mntr" kubernetesmock "github.com/caos/orbos/pkg/kubernetes/mock" "github.com/golang/mock/gomock" "github.com/pkg/errors" "github.com/stretchr/testify/assert" - "testing" ) func TestBackup_Cleanup1(t *testing.T) { @@ -15,12 +16,12 @@ func TestBackup_Cleanup1(t *testing.T) { name := "test" namespace := "testNs" - cleanupFunc := getCleanupFunc(monitor, namespace, name) - client.EXPECT().WaitUntilJobCompleted(namespace, name, timeout).Times(1).Return(nil) - client.EXPECT().DeleteJob(namespace, name).Times(1) + 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, name, timeout).Times(1).Return(errors.New("fail")) + client.EXPECT().WaitUntilJobCompleted(namespace, GetJobName(name), timeout).Times(1).Return(errors.New("fail")) assert.Error(t, cleanupFunc(client)) } @@ -30,11 +31,11 @@ func TestBackup_Cleanup2(t *testing.T) { name := "test2" namespace := "testNs2" - cleanupFunc := getCleanupFunc(monitor, namespace, name) - client.EXPECT().WaitUntilJobCompleted(namespace, name, timeout).Times(1).Return(nil) - client.EXPECT().DeleteJob(namespace, name).Times(1) + 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, name, timeout).Times(1).Return(errors.New("fail")) + client.EXPECT().WaitUntilJobCompleted(namespace, GetJobName(name), timeout).Times(1).Return(errors.New("fail")) assert.Error(t, cleanupFunc(client)) } diff --git a/operator/database/kinds/backups/bucket/clean/adapt.go b/operator/database/kinds/backups/bucket/clean/adapt.go index a60f134f0b..20214e28e4 100644 --- a/operator/database/kinds/backups/bucket/clean/adapt.go +++ b/operator/database/kinds/backups/bucket/clean/adapt.go @@ -21,7 +21,7 @@ const ( rootSecretName = "cockroachdb.client.root" jobPrefix = "backup-" jobSuffix = "-clean" - timeout time.Duration = 60 + timeout time.Duration = 600 ) func AdaptFunc( @@ -71,7 +71,6 @@ func AdaptFunc( queriers := []operator.QueryFunc{ operator.EnsureFuncToQueryFunc(checkDBReady), operator.ResourceQueryToZitadelQuery(queryJ), - operator.EnsureFuncToQueryFunc(getCleanupFunc(monitor, jobDef.Namespace, jobDef.Name)), } return func(k8sClient kubernetes.ClientInt, queried map[string]interface{}) (operator.EnsureFunc, error) { diff --git a/operator/database/kinds/backups/bucket/clean/adapt_test.go b/operator/database/kinds/backups/bucket/clean/adapt_test.go index ee84e2182f..45a1b0be19 100644 --- a/operator/database/kinds/backups/bucket/clean/adapt_test.go +++ b/operator/database/kinds/backups/bucket/clean/adapt_test.go @@ -1,6 +1,8 @@ package clean import ( + "testing" + "github.com/caos/orbos/mntr" "github.com/caos/orbos/pkg/kubernetes" kubernetesmock "github.com/caos/orbos/pkg/kubernetes/mock" @@ -10,7 +12,6 @@ import ( corev1 "k8s.io/api/core/v1" macherrs "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/runtime/schema" - "testing" ) func TestBackup_Adapt1(t *testing.T) { @@ -49,8 +50,6 @@ func TestBackup_Adapt1(t *testing.T) { 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)) - client.EXPECT().WaitUntilJobCompleted(jobDef.Namespace, jobDef.Name, timeout).Times(1).Return(nil) - client.EXPECT().DeleteJob(jobDef.Namespace, jobDef.Name).Times(1).Return(nil) query, _, err := AdaptFunc( monitor, @@ -109,8 +108,6 @@ func TestBackup_Adapt2(t *testing.T) { 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)) - client.EXPECT().WaitUntilJobCompleted(jobDef.Namespace, jobDef.Name, timeout).Times(1).Return(nil) - client.EXPECT().DeleteJob(jobDef.Namespace, jobDef.Name).Times(1).Return(nil) query, _, err := AdaptFunc( monitor, diff --git a/operator/database/kinds/backups/bucket/clean/cleanup.go b/operator/database/kinds/backups/bucket/clean/cleanup.go index 0336a5719e..ca9a0a30c3 100644 --- a/operator/database/kinds/backups/bucket/clean/cleanup.go +++ b/operator/database/kinds/backups/bucket/clean/cleanup.go @@ -7,19 +7,19 @@ import ( "github.com/pkg/errors" ) -func getCleanupFunc( +func GetCleanupFunc( monitor mntr.Monitor, namespace string, - jobName string, + backupName string, ) operator.EnsureFunc { return func(k8sClient kubernetes.ClientInt) error { monitor.Info("waiting for clean to be completed") - if err := k8sClient.WaitUntilJobCompleted(namespace, jobName, 60); err != nil { + if err := k8sClient.WaitUntilJobCompleted(namespace, GetJobName(backupName), timeout); err != nil { monitor.Error(errors.Wrap(err, "error while waiting for clean to be completed")) return err } monitor.Info("clean is completed, cleanup") - if err := k8sClient.DeleteJob(namespace, jobName); err != nil { + if err := k8sClient.DeleteJob(namespace, GetJobName(backupName)); err != nil { monitor.Error(errors.Wrap(err, "error while trying to cleanup clean")) return err } diff --git a/operator/database/kinds/backups/bucket/clean/cleanup_test.go b/operator/database/kinds/backups/bucket/clean/cleanup_test.go index 6b7b383790..ac83c5a85a 100644 --- a/operator/database/kinds/backups/bucket/clean/cleanup_test.go +++ b/operator/database/kinds/backups/bucket/clean/cleanup_test.go @@ -15,12 +15,12 @@ func TestBackup_Cleanup1(t *testing.T) { name := "test" namespace := "testNs" - cleanupFunc := getCleanupFunc(monitor, namespace, name) - client.EXPECT().WaitUntilJobCompleted(namespace, name, timeout).Times(1).Return(nil) - client.EXPECT().DeleteJob(namespace, name).Times(1) + 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, name, timeout).Times(1).Return(errors.New("fail")) + client.EXPECT().WaitUntilJobCompleted(namespace, GetJobName(name), timeout).Times(1).Return(errors.New("fail")) assert.Error(t, cleanupFunc(client)) } @@ -30,11 +30,11 @@ func TestBackup_Cleanup2(t *testing.T) { name := "test2" namespace := "testNs2" - cleanupFunc := getCleanupFunc(monitor, namespace, name) - client.EXPECT().WaitUntilJobCompleted(namespace, name, timeout).Times(1).Return(nil) - client.EXPECT().DeleteJob(namespace, name).Times(1) + 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, name, timeout).Times(1).Return(errors.New("fail")) + client.EXPECT().WaitUntilJobCompleted(namespace, GetJobName(name), timeout).Times(1).Return(errors.New("fail")) assert.Error(t, cleanupFunc(client)) } diff --git a/operator/database/kinds/backups/bucket/desired.go b/operator/database/kinds/backups/bucket/desired.go index b70b1d89e2..22dc489d28 100644 --- a/operator/database/kinds/backups/bucket/desired.go +++ b/operator/database/kinds/backups/bucket/desired.go @@ -1,7 +1,9 @@ package bucket import ( - secret2 "github.com/caos/orbos/pkg/secret" + "fmt" + + "github.com/caos/orbos/pkg/secret" "github.com/caos/orbos/pkg/tree" "github.com/pkg/errors" ) @@ -12,14 +14,15 @@ type DesiredV0 struct { } type Spec struct { - Verbose bool - Cron string `yaml:"cron,omitempty"` - Bucket string `yaml:"bucket,omitempty"` - ServiceAccountJSON *secret2.Secret `yaml:"serviceAccountJSON,omitempty"` + Verbose bool + Cron string `yaml:"cron,omitempty"` + Bucket string `yaml:"bucket,omitempty"` + ServiceAccountJSON *secret.Secret `yaml:"serviceAccountJSON,omitempty"` + ExistingServiceAccountJSON *secret.Existing `yaml:"existingServiceAccountJSON,omitempty"` } func (s *Spec) IsZero() bool { - if (s.ServiceAccountJSON == nil || s.ServiceAccountJSON.IsZero()) && + if ((s.ServiceAccountJSON == nil || s.ServiceAccountJSON.IsZero()) && (s.ExistingServiceAccountJSON == nil || s.ExistingServiceAccountJSON.IsZero())) && !s.Verbose && s.Cron == "" && s.Bucket == "" { @@ -40,3 +43,10 @@ func ParseDesiredV0(desiredTree *tree.Tree) (*DesiredV0, error) { return desiredKind, nil } + +func (d *DesiredV0) validateSecrets() error { + if err := secret.ValidateSecret(d.Spec.ServiceAccountJSON, d.Spec.ExistingServiceAccountJSON); err != nil { + return fmt.Errorf("validating api key failed: %w", err) + } + return nil +} diff --git a/operator/database/kinds/backups/bucket/mock.go b/operator/database/kinds/backups/bucket/mock.go index dc6ab66708..4c05b25538 100644 --- a/operator/database/kinds/backups/bucket/mock.go +++ b/operator/database/kinds/backups/bucket/mock.go @@ -65,7 +65,18 @@ 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))) diff --git a/operator/database/kinds/backups/bucket/restore/adapt.go b/operator/database/kinds/backups/bucket/restore/adapt.go index 03d2a60594..42f61d1d49 100644 --- a/operator/database/kinds/backups/bucket/restore/adapt.go +++ b/operator/database/kinds/backups/bucket/restore/adapt.go @@ -21,7 +21,7 @@ const ( image = "ghcr.io/caos/zitadel-crbackup" internalSecretName = "client-certs" rootSecretName = "cockroachdb.client.root" - timeout time.Duration = 60 + timeout time.Duration = 1200 ) func AdaptFunc( @@ -79,7 +79,6 @@ func AdaptFunc( queriers := []operator.QueryFunc{ operator.EnsureFuncToQueryFunc(checkDBReady), operator.ResourceQueryToZitadelQuery(queryJ), - operator.EnsureFuncToQueryFunc(getCleanupFunc(monitor, jobdef.Namespace, jobdef.Name)), } return func(k8sClient kubernetes.ClientInt, queried map[string]interface{}) (operator.EnsureFunc, error) { diff --git a/operator/database/kinds/backups/bucket/restore/adapt_test.go b/operator/database/kinds/backups/bucket/restore/adapt_test.go index 771f685a81..b6031def52 100644 --- a/operator/database/kinds/backups/bucket/restore/adapt_test.go +++ b/operator/database/kinds/backups/bucket/restore/adapt_test.go @@ -1,6 +1,8 @@ package restore import ( + "testing" + "github.com/caos/orbos/mntr" "github.com/caos/orbos/pkg/kubernetes" kubernetesmock "github.com/caos/orbos/pkg/kubernetes/mock" @@ -10,7 +12,6 @@ import ( corev1 "k8s.io/api/core/v1" macherrs "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/runtime/schema" - "testing" ) func TestBackup_Adapt1(t *testing.T) { @@ -54,8 +55,6 @@ func TestBackup_Adapt1(t *testing.T) { 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)) - client.EXPECT().WaitUntilJobCompleted(jobDef.Namespace, jobDef.Name, timeout).Times(1).Return(nil) - client.EXPECT().DeleteJob(jobDef.Namespace, jobDef.Name).Times(1).Return(nil) query, _, err := AdaptFunc( monitor, @@ -121,8 +120,6 @@ func TestBackup_Adapt2(t *testing.T) { 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)) - client.EXPECT().WaitUntilJobCompleted(jobDef.Namespace, jobDef.Name, timeout).Times(1).Return(nil) - client.EXPECT().DeleteJob(jobDef.Namespace, jobDef.Name).Times(1).Return(nil) query, _, err := AdaptFunc( monitor, diff --git a/operator/database/kinds/backups/bucket/restore/cleanup.go b/operator/database/kinds/backups/bucket/restore/cleanup.go index 3bb0f4c7b3..08f6249652 100644 --- a/operator/database/kinds/backups/bucket/restore/cleanup.go +++ b/operator/database/kinds/backups/bucket/restore/cleanup.go @@ -7,15 +7,19 @@ import ( "github.com/pkg/errors" ) -func getCleanupFunc(monitor mntr.Monitor, namespace, jobName string) operator.EnsureFunc { +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, jobName, timeout); err != nil { + if err := k8sClient.WaitUntilJobCompleted(namespace, GetJobName(backupName), timeout); err != nil { monitor.Error(errors.Wrap(err, "error while waiting for restore to be completed")) return err } monitor.Info("restore is completed, cleanup") - if err := k8sClient.DeleteJob(namespace, jobName); err != nil { + if err := k8sClient.DeleteJob(namespace, GetJobName(backupName)); err != nil { monitor.Error(errors.Wrap(err, "error while trying to cleanup restore")) return err } diff --git a/operator/database/kinds/backups/bucket/restore/cleanup_test.go b/operator/database/kinds/backups/bucket/restore/cleanup_test.go index ba0307b091..81671b1f30 100644 --- a/operator/database/kinds/backups/bucket/restore/cleanup_test.go +++ b/operator/database/kinds/backups/bucket/restore/cleanup_test.go @@ -15,12 +15,12 @@ func TestBackup_Cleanup1(t *testing.T) { name := "test" namespace := "testNs" - cleanupFunc := getCleanupFunc(monitor, namespace, name) - client.EXPECT().WaitUntilJobCompleted(namespace, name, timeout).Times(1).Return(nil) - client.EXPECT().DeleteJob(namespace, name).Times(1) + 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, name, timeout).Times(1).Return(errors.New("fail")) + client.EXPECT().WaitUntilJobCompleted(namespace, GetJobName(name), timeout).Times(1).Return(errors.New("fail")) assert.Error(t, cleanupFunc(client)) } @@ -30,11 +30,11 @@ func TestBackup_Cleanup2(t *testing.T) { name := "test2" namespace := "testNs2" - cleanupFunc := getCleanupFunc(monitor, namespace, name) - client.EXPECT().WaitUntilJobCompleted(namespace, name, timeout).Times(1).Return(nil) - client.EXPECT().DeleteJob(namespace, name).Times(1) + 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, name, timeout).Times(1).Return(errors.New("fail")) + client.EXPECT().WaitUntilJobCompleted(namespace, GetJobName(name), timeout).Times(1).Return(errors.New("fail")) assert.Error(t, cleanupFunc(client)) } diff --git a/operator/database/kinds/backups/bucket/secrets.go b/operator/database/kinds/backups/bucket/secrets.go index 3d11cf8e18..17eca944c8 100644 --- a/operator/database/kinds/backups/bucket/secrets.go +++ b/operator/database/kinds/backups/bucket/secrets.go @@ -4,8 +4,12 @@ import ( "github.com/caos/orbos/pkg/secret" ) -func getSecretsMap(desiredKind *DesiredV0) map[string]*secret.Secret { - secrets := make(map[string]*secret.Secret, 0) +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{} } @@ -13,7 +17,14 @@ func getSecretsMap(desiredKind *DesiredV0) map[string]*secret.Secret { if desiredKind.Spec.ServiceAccountJSON == nil { desiredKind.Spec.ServiceAccountJSON = &secret.Secret{} } - secrets["serviceaccountjson"] = desiredKind.Spec.ServiceAccountJSON - return secrets + if desiredKind.Spec.ExistingServiceAccountJSON == nil { + desiredKind.Spec.ExistingServiceAccountJSON = &secret.Existing{} + } + + sakey := "serviceaccountjson" + secrets[sakey] = desiredKind.Spec.ServiceAccountJSON + existing[sakey] = desiredKind.Spec.ExistingServiceAccountJSON + + return secrets, existing } diff --git a/operator/database/kinds/backups/bucket/secrets_test.go b/operator/database/kinds/backups/bucket/secrets_test.go index bac7fac674..4b4810b394 100644 --- a/operator/database/kinds/backups/bucket/secrets_test.go +++ b/operator/database/kinds/backups/bucket/secrets_test.go @@ -1,22 +1,26 @@ package bucket import ( + "testing" + "github.com/caos/orbos/pkg/secret" "github.com/stretchr/testify/assert" - "testing" ) func TestBucket_getSecretsFull(t *testing.T) { - secrets := getSecretsMap(&desired) + secrets, existing := getSecretsMap(&desired) assert.Equal(t, desired.Spec.ServiceAccountJSON, secrets["serviceaccountjson"]) + assert.Equal(t, desired.Spec.ExistingServiceAccountJSON, existing["serviceaccountjson"]) } func TestBucket_getSecretsEmpty(t *testing.T) { - secrets := getSecretsMap(&desiredWithoutSecret) + secrets, existing := getSecretsMap(&desiredWithoutSecret) assert.Equal(t, &secret.Secret{}, secrets["serviceaccountjson"]) + assert.Equal(t, &secret.Existing{}, existing["serviceaccountjson"]) } func TestBucket_getSecretsNil(t *testing.T) { - secrets := getSecretsMap(&desiredNil) + secrets, existing := getSecretsMap(&desiredNil) assert.Equal(t, &secret.Secret{}, secrets["serviceaccountjson"]) + assert.Equal(t, &secret.Existing{}, existing["serviceaccountjson"]) } diff --git a/operator/database/kinds/databases/databases.go b/operator/database/kinds/databases/databases.go index b48172c1ac..40f0aea8b1 100644 --- a/operator/database/kinds/databases/databases.go +++ b/operator/database/kinds/databases/databases.go @@ -35,6 +35,8 @@ func GetQueryAndDestroyFuncs( query operator.QueryFunc, destroy operator.DestroyFunc, secrets map[string]*secret.Secret, + existing map[string]*secret.Existing, + migrate bool, err error, ) { componentLabels := labels.MustForComponent(apiLabels, component) @@ -46,7 +48,7 @@ func GetQueryAndDestroyFuncs( case "databases.caos.ch/ProvidedDatabase": return provided.AdaptFunc()(internalMonitor, desiredTree, currentTree) default: - return nil, nil, nil, errors.Errorf("unknown database kind %s", desiredTree.Common.Kind) + return nil, nil, nil, nil, false, errors.Errorf("unknown database kind %s", desiredTree.Common.Kind) } } diff --git a/operator/database/kinds/databases/managed/adapt.go b/operator/database/kinds/databases/managed/adapt.go index 17afc3e8e5..0ad2835dc2 100644 --- a/operator/database/kinds/databases/managed/adapt.go +++ b/operator/database/kinds/databases/managed/adapt.go @@ -1,10 +1,11 @@ package managed import ( - "github.com/caos/zitadel/operator" "strconv" "strings" + "github.com/caos/zitadel/operator" + "github.com/caos/orbos/pkg/labels" "github.com/caos/orbos/pkg/secret" @@ -51,6 +52,8 @@ func AdaptFunc( operator.QueryFunc, operator.DestroyFunc, map[string]*secret.Secret, + map[string]*secret.Existing, + bool, error, ) { @@ -62,14 +65,21 @@ func AdaptFunc( operator.QueryFunc, operator.DestroyFunc, map[string]*secret.Secret, + map[string]*secret.Existing, + bool, error, ) { - internalMonitor := monitor.WithField("kind", "cockroachdb") - allSecrets := map[string]*secret.Secret{} + + var ( + internalMonitor = monitor.WithField("kind", "cockroachdb") + allSecrets = make(map[string]*secret.Secret) + allExisting = make(map[string]*secret.Existing) + migrate bool + ) desiredKind, err := parseDesiredV0(desired) if err != nil { - return nil, nil, nil, errors.Wrap(err, "parsing desired state failed") + return nil, nil, nil, nil, false, errors.Wrap(err, "parsing desired state failed") } desired.Parsed = desiredKind @@ -92,15 +102,15 @@ func AdaptFunc( queryCert, destroyCert, addUser, deleteUser, listUsers, err := certificate.AdaptFunc(internalMonitor, namespace, componentLabels, desiredKind.Spec.ClusterDns, isFeatureDatabase) if err != nil { - return nil, nil, nil, err + return nil, nil, nil, nil, false, err } addRoot, err := addUser("root") if err != nil { - return nil, nil, nil, err + return nil, nil, nil, nil, false, err } destroyRoot, err := deleteUser("root") if err != nil { - return nil, nil, nil, err + return nil, nil, nil, nil, false, err } queryRBAC, destroyRBAC, err := rbac.AdaptFunc(internalMonitor, namespace, labels.MustForName(componentLabels, serviceAccountName)) @@ -126,7 +136,7 @@ func AdaptFunc( desiredKind.Spec.Resources, ) if err != nil { - return nil, nil, nil, err + return nil, nil, nil, nil, false, err } queryS, destroyS, err := services.AdaptFunc( @@ -147,12 +157,12 @@ func AdaptFunc( queryPDB, err := pdb.AdaptFuncToEnsure(namespace, labels.MustForName(componentLabels, pdbName), cockroachSelector, "1") if err != nil { - return nil, nil, nil, err + return nil, nil, nil, nil, false, err } destroyPDB, err := pdb.AdaptFuncToDestroy(namespace, pdbName) if err != nil { - return nil, nil, nil, err + return nil, nil, nil, nil, false, err } currentDB := &Current{ @@ -203,7 +213,7 @@ func AdaptFunc( for backupName, desiredBackup := range desiredKind.Spec.Backups { currentBackup := &tree.Tree{} if timestamp == "" || !oneBackup || (timestamp != "" && strings.HasPrefix(timestamp, backupName)) { - queryB, destroyB, secrets, err := backups.GetQueryAndDestroyFuncs( + queryB, destroyB, secrets, existing, migrateB, err := backups.GetQueryAndDestroyFuncs( internalMonitor, desiredBackup, currentBackup, @@ -218,10 +228,12 @@ func AdaptFunc( features, ) if err != nil { - return nil, nil, nil, err + return nil, nil, nil, nil, false, err } - secret.AppendSecrets(backupName, allSecrets, secrets) + migrate = migrate || migrateB + + secret.AppendSecrets(backupName, allSecrets, secrets, allExisting, existing) destroyers = append(destroyers, destroyB) queriers = append(queriers, queryB) } @@ -251,6 +263,8 @@ func AdaptFunc( }, operator.DestroyersToDestroyFunc(internalMonitor, destroyers), allSecrets, + allExisting, + migrate, nil } } diff --git a/operator/database/kinds/databases/managed/adapt_backup_test.go b/operator/database/kinds/databases/managed/adapt_backup_test.go index c82f0614ec..aa96a60949 100644 --- a/operator/database/kinds/databases/managed/adapt_backup_test.go +++ b/operator/database/kinds/databases/managed/adapt_backup_test.go @@ -1,6 +1,9 @@ package managed import ( + "testing" + "time" + "github.com/caos/orbos/mntr" kubernetesmock "github.com/caos/orbos/pkg/kubernetes/mock" "github.com/caos/orbos/pkg/labels" @@ -13,8 +16,6 @@ import ( "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" corev1 "k8s.io/api/core/v1" - "testing" - "time" ) func getTreeWithDBAndBackup(t *testing.T, masterkey string, saJson string, backupName string) *tree.Tree { @@ -83,7 +84,7 @@ func TestManaged_AdaptBucketBackup(t *testing.T) { bucket.SetBackup(k8sClient, namespace, labels, saJson) k8sClient.EXPECT().WaitUntilStatefulsetIsReady(namespace, SfsName, true, true, time.Duration(60)) - query, _, _, err := AdaptFunc(componentLabels, namespace, timestamp, nodeselector, tolerations, version, features)(monitor, desired, &tree.Tree{}) + query, _, _, _, _, err := AdaptFunc(componentLabels, namespace, timestamp, nodeselector, tolerations, version, features)(monitor, desired, &tree.Tree{}) assert.NoError(t, err) databases := []string{"test1", "test2"} @@ -123,7 +124,7 @@ func TestManaged_AdaptBucketInstantBackup(t *testing.T) { desired := getTreeWithDBAndBackup(t, masterkey, saJson, backupName) - query, _, _, err := AdaptFunc(componentLabels, namespace, timestamp, nodeselector, tolerations, version, features)(monitor, desired, &tree.Tree{}) + query, _, _, _, _, err := AdaptFunc(componentLabels, namespace, timestamp, nodeselector, tolerations, version, features)(monitor, desired, &tree.Tree{}) assert.NoError(t, err) databases := []string{"test1", "test2"} @@ -159,12 +160,12 @@ func TestManaged_AdaptBucketCleanAndRestore(t *testing.T) { features := []string{restore.Instant, clean.Instant} bucket.SetRestore(k8sClient, namespace, backupName, labels, saJson) - bucket.SetClean(k8sClient, namespace, backupName) + bucket.SetClean(k8sClient, namespace, backupName, labels, saJson) k8sClient.EXPECT().WaitUntilStatefulsetIsReady(namespace, SfsName, true, true, time.Duration(60)).Times(2) desired := getTreeWithDBAndBackup(t, masterkey, saJson, backupName) - query, _, _, err := AdaptFunc(componentLabels, namespace, timestamp, nodeselector, tolerations, version, features)(monitor, desired, &tree.Tree{}) + query, _, _, _, _, err := AdaptFunc(componentLabels, namespace, timestamp, nodeselector, tolerations, version, features)(monitor, desired, &tree.Tree{}) assert.NoError(t, err) databases := []string{"test1", "test2"} diff --git a/operator/database/kinds/databases/managed/adapt_test.go b/operator/database/kinds/databases/managed/adapt_test.go index 2c718191a0..62ba07b15a 100644 --- a/operator/database/kinds/databases/managed/adapt_test.go +++ b/operator/database/kinds/databases/managed/adapt_test.go @@ -1,10 +1,11 @@ package managed import ( - "gopkg.in/yaml.v3" "testing" "time" + "gopkg.in/yaml.v3" + "github.com/caos/orbos/mntr" kubernetesmock "github.com/caos/orbos/pkg/kubernetes/mock" "github.com/caos/orbos/pkg/labels" @@ -132,7 +133,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 := AdaptFunc(componentLabels, namespace, timestamp, nodeselector, tolerations, version, features)(monitor, desired, &tree.Tree{}) + query, _, _, _, _, err := AdaptFunc(componentLabels, namespace, timestamp, nodeselector, tolerations, version, features)(monitor, desired, &tree.Tree{}) assert.NoError(t, err) ensure, err := query(k8sClient, queried) @@ -244,7 +245,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 := AdaptFunc(componentLabels, namespace, timestamp, nodeselector, tolerations, version, features)(monitor, desired, &tree.Tree{}) + query, _, _, _, _, err := AdaptFunc(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/provided/adapt.go b/operator/database/kinds/databases/provided/adapt.go index 0e96da8d65..5b5463d2dd 100644 --- a/operator/database/kinds/databases/provided/adapt.go +++ b/operator/database/kinds/databases/provided/adapt.go @@ -17,6 +17,8 @@ func AdaptFunc() func( operator.QueryFunc, operator.DestroyFunc, map[string]*secret.Secret, + map[string]*secret.Existing, + bool, error, ) { return func( @@ -27,11 +29,13 @@ func AdaptFunc() func( operator.QueryFunc, operator.DestroyFunc, map[string]*secret.Secret, + map[string]*secret.Existing, + bool, error, ) { desiredKind, err := parseDesiredV0(desired) if err != nil { - return nil, nil, nil, errors.Wrap(err, "parsing desired state failed") + return nil, nil, nil, nil, false, errors.Wrap(err, "parsing desired state failed") } desired.Parsed = desiredKind @@ -53,7 +57,9 @@ func AdaptFunc() func( }, func(k8sClient kubernetes.ClientInt) error { return nil }, - map[string]*secret.Secret{}, + make(map[string]*secret.Secret), + make(map[string]*secret.Existing), + false, nil } } diff --git a/operator/database/kinds/orb/adapt.go b/operator/database/kinds/orb/adapt.go index dc1e1ed2a1..a7ce0668b6 100644 --- a/operator/database/kinds/orb/adapt.go +++ b/operator/database/kinds/orb/adapt.go @@ -9,6 +9,9 @@ import ( "github.com/caos/orbos/pkg/tree" "github.com/caos/orbos/pkg/treelabels" "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" "github.com/pkg/errors" ) @@ -21,18 +24,29 @@ func OperatorSelector() *labels.Selector { return labels.OpenOperatorSelector("ZITADEL", "database.caos.ch") } -func AdaptFunc(timestamp string, binaryVersion *string, features ...string) operator.AdaptFunc { +func AdaptFunc(timestamp string, binaryVersion *string, gitops bool, features ...string) operator.AdaptFunc { - return func(monitor mntr.Monitor, orbDesiredTree *tree.Tree, currentTree *tree.Tree) (queryFunc operator.QueryFunc, destroyFunc operator.DestroyFunc, secrets map[string]*secret.Secret, err error) { + return func( + monitor mntr.Monitor, + orbDesiredTree *tree.Tree, + currentTree *tree.Tree, + ) ( + queryFunc operator.QueryFunc, + destroyFunc operator.DestroyFunc, + secrets map[string]*secret.Secret, + existing map[string]*secret.Existing, + migrate bool, + err error, + ) { defer func() { err = errors.Wrapf(err, "building %s failed", orbDesiredTree.Common.Kind) }() orbMonitor := monitor.WithField("kind", "orb") - desiredKind, err := parseDesiredV0(orbDesiredTree) + desiredKind, err := ParseDesiredV0(orbDesiredTree) if err != nil { - return nil, nil, nil, errors.Wrap(err, "parsing desired state failed") + return nil, nil, nil, nil, migrate, errors.Wrap(err, "parsing desired state failed") } orbDesiredTree.Parsed = desiredKind currentTree = &tree.Tree{} @@ -43,18 +57,18 @@ func AdaptFunc(timestamp string, binaryVersion *string, features ...string) oper queryNS, err := namespace.AdaptFuncToEnsure(NamespaceStr) if err != nil { - return nil, nil, nil, err + return nil, nil, nil, nil, migrate, err } - destroyNS, err := namespace.AdaptFuncToDestroy(NamespaceStr) + /*destroyNS, err := namespace.AdaptFuncToDestroy(NamespaceStr) if err != nil { return nil, nil, nil, err - } + }*/ databaseCurrent := &tree.Tree{} operatorLabels := mustDatabaseOperator(binaryVersion) - queryDB, destroyDB, secrets, err := databases.GetQueryAndDestroyFuncs( + queryDB, destroyDB, secrets, existing, migrate, err := databases.GetQueryAndDestroyFuncs( orbMonitor, desiredKind.Database, databaseCurrent, @@ -66,23 +80,28 @@ func AdaptFunc(timestamp string, binaryVersion *string, features ...string) oper desiredKind.Spec.Version, features, ) - if err != nil { - return nil, nil, nil, err - } - queriers := []operator.QueryFunc{ - operator.ResourceQueryToZitadelQuery(queryNS), - queryDB, - } - if desiredKind.Spec.SelfReconciling { - queriers = append(queriers, - operator.EnsureFuncToQueryFunc(Reconcile(monitor, orbDesiredTree)), - ) + return nil, nil, nil, nil, migrate, err } - destroyers := []operator.DestroyFunc{ - operator.ResourceDestroyToZitadelDestroy(destroyNS), - destroyDB, + destroyers := make([]operator.DestroyFunc, 0) + queriers := make([]operator.QueryFunc, 0) + for _, feature := range features { + switch feature { + case "database", backup.Instant, backup.Normal, restore.Instant, clean.Instant: + queriers = append(queriers, + operator.ResourceQueryToZitadelQuery(queryNS), + queryDB, + ) + destroyers = append(destroyers, + destroyDB, + ) + case "operator": + queriers = append(queriers, + operator.ResourceQueryToZitadelQuery(queryNS), + operator.EnsureFuncToQueryFunc(Reconcile(monitor, desiredKind.Spec)), + ) + } } currentTree.Parsed = &DesiredV0{ @@ -105,6 +124,8 @@ func AdaptFunc(timestamp string, binaryVersion *string, features ...string) oper return operator.DestroyersToDestroyFunc(monitor, destroyers)(k8sClient) }, secrets, + existing, + migrate, nil } } diff --git a/operator/database/kinds/orb/backups.go b/operator/database/kinds/orb/backups.go index 023cf3623c..6dd1b03f63 100644 --- a/operator/database/kinds/orb/backups.go +++ b/operator/database/kinds/orb/backups.go @@ -9,7 +9,7 @@ import ( func BackupListFunc() func(monitor mntr.Monitor, desiredTree *tree.Tree) (strings []string, err error) { return func(monitor mntr.Monitor, desiredTree *tree.Tree) (strings []string, err error) { - desiredKind, err := parseDesiredV0(desiredTree) + desiredKind, err := ParseDesiredV0(desiredTree) if err != nil { return nil, errors.Wrap(err, "parsing desired state failed") } diff --git a/operator/database/kinds/orb/desired.go b/operator/database/kinds/orb/desired.go index edeaa6f658..6048714d4b 100644 --- a/operator/database/kinds/orb/desired.go +++ b/operator/database/kinds/orb/desired.go @@ -7,21 +7,25 @@ import ( ) type DesiredV0 struct { - Common *tree.Common `yaml:",inline"` - Spec struct { - Verbose bool - NodeSelector map[string]string `yaml:"nodeSelector,omitempty"` - Tolerations []corev1.Toleration `yaml:"tolerations,omitempty"` - Version string `yaml:"version,omitempty"` - SelfReconciling bool `yaml:"selfReconciling"` - //Use this registry to pull the ZITADEL operator image from - //@default: ghcr.io - CustomImageRegistry string `json:"customImageRegistry,omitempty" yaml:"customImageRegistry,omitempty"` - } + Common *tree.Common `json:",inline" yaml:",inline"` + Spec *Spec `json:"spec" yaml:"spec"` Database *tree.Tree } -func parseDesiredV0(desiredTree *tree.Tree) (*DesiredV0, error) { +// +kubebuilder:object:generate=true +type Spec struct { + Verbose bool `json:"verbose" json:"verbose"` + NodeSelector map[string]string `json:"nodeSelector,omitempty" yaml:"nodeSelector,omitempty"` + Tolerations []corev1.Toleration `json:"tolerations,omitempty" yaml:"tolerations,omitempty"` + Version string `json:"version,omitempty" yaml:"version,omitempty"` + SelfReconciling bool `json:"selfReconciling" yaml:"selfReconciling"` + GitOps bool `json:"gitOps,omitempty" yaml:"gitOps,omitempty"` + //Use this registry to pull the Database operator image from + //@default: ghcr.io + CustomImageRegistry string `json:"customImageRegistry,omitempty" yaml:"customImageRegistry,omitempty"` +} + +func ParseDesiredV0(desiredTree *tree.Tree) (*DesiredV0, error) { desiredKind := &DesiredV0{Common: desiredTree.Common} if err := desiredTree.Original.Decode(desiredKind); err != nil { diff --git a/operator/database/kinds/orb/reconcile.go b/operator/database/kinds/orb/reconcile.go index d5d809b8d3..295f7e4569 100644 --- a/operator/database/kinds/orb/reconcile.go +++ b/operator/database/kinds/orb/reconcile.go @@ -10,38 +10,38 @@ import ( "github.com/pkg/errors" ) -func Reconcile(monitor mntr.Monitor, desiredTree *tree.Tree) operator.EnsureFunc { +func Reconcile( + monitor mntr.Monitor, + spec *Spec, +) operator.EnsureFunc { return func(k8sClient kubernetes.ClientInt) (err error) { - defer func() { - err = errors.Wrapf(err, "building %s failed", desiredTree.Common.Kind) - }() + recMonitor := monitor.WithField("version", spec.Version) - desiredKind, err := parseDesiredV0(desiredTree) - if err != nil { - return errors.Wrap(err, "parsing desired state failed") - } - desiredTree.Parsed = desiredKind - - recMonitor := monitor.WithField("version", desiredKind.Spec.Version) - - if desiredKind.Spec.Version == "" { - err := errors.New("No version set in database.yml") - monitor.Error(err) + if spec.Version == "" { + err := errors.New("No version provided for self-reconciling") + recMonitor.Error(err) return err } - imageRegistry := desiredKind.Spec.CustomImageRegistry + imageRegistry := spec.CustomImageRegistry if imageRegistry == "" { imageRegistry = "ghcr.io" } - if err := zitadelKubernetes.EnsureDatabaseArtifacts(monitor, treelabels.MustForAPI(desiredTree, mustDatabaseOperator(&desiredKind.Spec.Version)), k8sClient, desiredKind.Spec.Version, desiredKind.Spec.NodeSelector, desiredKind.Spec.Tolerations, imageRegistry); err != nil { - recMonitor.Error(errors.Wrap(err, "Failed to deploy database-operator into k8s-cluster")) - return err + if spec.SelfReconciling { + desiredTree := &tree.Tree{ + Common: &tree.Common{ + Kind: "databases.caos.ch/Orb", + Version: "v0", + }, + } + + if err := zitadelKubernetes.EnsureDatabaseArtifacts(monitor, treelabels.MustForAPI(desiredTree, mustDatabaseOperator(&spec.Version)), k8sClient, spec.Version, spec.NodeSelector, spec.Tolerations, imageRegistry, spec.GitOps); err != nil { + recMonitor.Error(errors.Wrap(err, "Failed to deploy database-operator into k8s-cluster")) + return err + } + recMonitor.Info("Applied database-operator") } - - recMonitor.Info("Applied database-operator") - return nil } diff --git a/operator/database/kinds/orb/zz_generated.deepcopy.go b/operator/database/kinds/orb/zz_generated.deepcopy.go new file mode 100644 index 0000000000..bf8af31d1b --- /dev/null +++ b/operator/database/kinds/orb/zz_generated.deepcopy.go @@ -0,0 +1,54 @@ +// +build !ignore_autogenerated + +/* + + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package orb + +import ( + "k8s.io/api/core/v1" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Spec) DeepCopyInto(out *Spec) { + *out = *in + if in.NodeSelector != nil { + in, out := &in.NodeSelector, &out.NodeSelector + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Tolerations != nil { + in, out := &in.Tolerations, &out.Tolerations + *out = make([]v1.Toleration, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Spec. +func (in *Spec) DeepCopy() *Spec { + if in == nil { + return nil + } + out := new(Spec) + in.DeepCopyInto(out) + return out +} diff --git a/operator/database/takeoff.go b/operator/database/takeoff.go index 15c3585eb9..1252dd63fd 100644 --- a/operator/database/takeoff.go +++ b/operator/database/takeoff.go @@ -2,6 +2,7 @@ package database import ( "errors" + "github.com/caos/orbos/mntr" "github.com/caos/orbos/pkg/git" "github.com/caos/orbos/pkg/kubernetes" @@ -25,7 +26,7 @@ func Takeoff(monitor mntr.Monitor, gitClient *git.Client, adapt operator.AdaptFu return } - query, _, _, err := adapt(internalMonitor, treeDesired, treeCurrent) + query, _, _, _, _, err := adapt(internalMonitor, treeDesired, treeCurrent) if err != nil { internalMonitor.Error(err) return diff --git a/operator/secrets/secrets.go b/operator/secrets/secrets.go index 20c41bb7e9..2fb7824d45 100644 --- a/operator/secrets/secrets.go +++ b/operator/secrets/secrets.go @@ -2,16 +2,22 @@ package secrets import ( "errors" - orbdb "github.com/caos/zitadel/operator/database/kinds/orb" + "fmt" "strings" + "github.com/caos/orbos/pkg/kubernetes" + + crddb "github.com/caos/zitadel/operator/api/database" + crdzit "github.com/caos/zitadel/operator/api/zitadel" + orbdb "github.com/caos/zitadel/operator/database/kinds/orb" + orbzit "github.com/caos/zitadel/operator/zitadel/kinds/orb" + "github.com/caos/orbos/mntr" "github.com/caos/orbos/pkg/git" "github.com/caos/orbos/pkg/orb" "github.com/caos/orbos/pkg/secret" "github.com/caos/orbos/pkg/tree" "github.com/caos/zitadel/operator/api" - zitadelOrb "github.com/caos/zitadel/operator/zitadel/kinds/orb" ) const ( @@ -19,79 +25,154 @@ const ( database string = "database" ) -func GetAllSecretsFunc(orb *orb.Orb) func(monitor mntr.Monitor, gitClient *git.Client) (map[string]*secret.Secret, map[string]*tree.Tree, error) { - return func(monitor mntr.Monitor, gitClient *git.Client) (map[string]*secret.Secret, map[string]*tree.Tree, error) { - allSecrets := make(map[string]*secret.Secret, 0) - allTrees := make(map[string]*tree.Tree, 0) - foundZitadel, err := api.ExistsZitadelYml(gitClient) - if err != nil { - return nil, nil, err - } - - if foundZitadel { - zitadelYML, err := api.ReadZitadelYml(gitClient) - if err != nil { - return nil, nil, err - } - allTrees[zitadel] = zitadelYML - _, _, zitadelSecrets, err := zitadelOrb.AdaptFunc(orb, "secret", nil, []string{})(monitor, zitadelYML, &tree.Tree{}) - if err != nil { - return nil, nil, err - } - - if zitadelSecrets != nil && len(zitadelSecrets) > 0 { - secret.AppendSecrets(zitadel, allSecrets, zitadelSecrets) - } - } else { - monitor.Info("no file for zitadel found") - } - - foundDB, err := api.ExistsDatabaseYml(gitClient) - if err != nil { - return nil, nil, err - } - if foundDB { - dbYML, err := api.ReadDatabaseYml(gitClient) - if err != nil { - return nil, nil, err - } - allTrees[database] = dbYML - - _, _, dbSecrets, err := orbdb.AdaptFunc("", nil, "database", "backup")(monitor, dbYML, nil) - if err != nil { - return nil, nil, err - } - if dbSecrets != nil && len(dbSecrets) > 0 { - secret.AppendSecrets(database, allSecrets, dbSecrets) - } - } else { - monitor.Info("no file for database found") - } - return allSecrets, allTrees, nil +func GetAllSecretsFunc( + monitor mntr.Monitor, + printLogs, + gitops bool, + gitClient *git.Client, + k8sClient kubernetes.ClientInt, + orb *orb.Orb, +) func() ( + map[string]*secret.Secret, + map[string]*secret.Existing, + map[string]*tree.Tree, + error, +) { + return func() ( + map[string]*secret.Secret, + map[string]*secret.Existing, + map[string]*tree.Tree, + error, + ) { + return getAllSecrets(monitor, printLogs, gitops, orb, gitClient, k8sClient) } } -func PushFunc() func(monitor mntr.Monitor, gitClient *git.Client, trees map[string]*tree.Tree, path string) error { - return func(monitor mntr.Monitor, gitClient *git.Client, trees map[string]*tree.Tree, path string) error { - operator := "" - if strings.HasPrefix(path, zitadel) { - operator = zitadel - } else if strings.HasPrefix(path, database) { - operator = database - } else { - return errors.New("Operator unknown") - } +func getAllSecrets( + monitor mntr.Monitor, + printLogs, + gitops bool, + orb *orb.Orb, + gitClient *git.Client, + k8sClient kubernetes.ClientInt, +) ( + map[string]*secret.Secret, + map[string]*secret.Existing, + map[string]*tree.Tree, + error, +) { + allSecrets := make(map[string]*secret.Secret, 0) + allExisting := make(map[string]*secret.Existing, 0) + allTrees := make(map[string]*tree.Tree, 0) - desired, found := trees[operator] - if !found { - return errors.New("Operator file not found") - } + if err := secret.GetOperatorSecrets( + monitor, + printLogs, + gitops, + allTrees, + allSecrets, + allExisting, + zitadel, + func() (bool, error) { return api.ExistsZitadelYml(gitClient) }, + func() (t *tree.Tree, err error) { return api.ReadZitadelYml(gitClient) }, + func() (t *tree.Tree, err error) { return crdzit.ReadCrd(k8sClient) }, + func(t *tree.Tree) (map[string]*secret.Secret, map[string]*secret.Existing, bool, error) { + _, _, secrets, existing, migrate, err := orbzit.AdaptFunc(orb, "secret", nil, gitops, []string{})(monitor, t, &tree.Tree{}) + return secrets, existing, migrate, err + }, + ); err != nil { + return nil, nil, nil, err + } - if operator == zitadel { + if err := secret.GetOperatorSecrets( + monitor, + printLogs, + gitops, + allTrees, + allSecrets, + allExisting, + database, + func() (bool, error) { return api.ExistsDatabaseYml(gitClient) }, + func() (t *tree.Tree, err error) { return api.ReadDatabaseYml(gitClient) }, + func() (t *tree.Tree, err error) { return crddb.ReadCrd(k8sClient) }, + func(t *tree.Tree) (map[string]*secret.Secret, map[string]*secret.Existing, bool, error) { + _, _, secrets, existing, migrate, err := orbdb.AdaptFunc("", nil, gitops, "database", "backup")(monitor, t, nil) + return secrets, existing, migrate, err + }, + ); err != nil { + return nil, nil, nil, err + } + + if k8sClient == nil { + allExisting = nil + } + + if len(allSecrets) == 0 && len(allExisting) == 0 { + return nil, nil, nil, errors.New("couldn't find any secrets") + } + + return allSecrets, allExisting, allTrees, nil +} + +func PushFunc( + monitor mntr.Monitor, + gitops bool, + gitClient *git.Client, + k8sClient kubernetes.ClientInt, +) func( + trees map[string]*tree.Tree, + path string, +) error { + return func( + trees map[string]*tree.Tree, + path string, + ) error { + return push(monitor, gitops, gitClient, k8sClient, trees, path) + } +} + +func push( + monitor mntr.Monitor, + gitops bool, + gitClient *git.Client, + k8sClient kubernetes.ClientInt, + trees map[string]*tree.Tree, + path string, +) error { + + var ( + pushGitFunc func(*tree.Tree) error + applyCRDFunc func(*tree.Tree) error + operator string + ) + + if strings.HasPrefix(path, zitadel) { + operator = zitadel + pushGitFunc = func(desired *tree.Tree) error { return api.PushZitadelDesiredFunc(gitClient, desired)(monitor) - } else if operator == database { + } + applyCRDFunc = func(t *tree.Tree) error { + return crdzit.WriteCrd(k8sClient, t) + } + } else if strings.HasPrefix(path, database) { + operator = database + pushGitFunc = func(desired *tree.Tree) error { return api.PushDatabaseDesiredFunc(gitClient, desired)(monitor) } - return errors.New("Operator push function unknown") + applyCRDFunc = func(t *tree.Tree) error { + return crddb.WriteCrd(k8sClient, t) + } + } else { + return errors.New("operator unknown") } + + desired, found := trees[operator] + if !found { + return fmt.Errorf("desired state for %s not found", operator) + } + + if gitops { + return pushGitFunc(desired) + } + return applyCRDFunc(desired) } diff --git a/operator/zitadel/kinds/iam/iam.go b/operator/zitadel/kinds/iam/iam.go index 73ac7bff35..9a203fc14f 100644 --- a/operator/zitadel/kinds/iam/iam.go +++ b/operator/zitadel/kinds/iam/iam.go @@ -3,10 +3,10 @@ package iam import ( "fmt" - "github.com/caos/orbos/pkg/labels" - "github.com/caos/orbos/pkg/orb" + "github.com/caos/zitadel/operator/zitadel/kinds/iam/zitadel/database" "github.com/caos/orbos/mntr" + "github.com/caos/orbos/pkg/labels" "github.com/caos/orbos/pkg/secret" "github.com/caos/orbos/pkg/tree" "github.com/caos/zitadel/operator" @@ -22,7 +22,8 @@ func GetQueryAndDestroyFuncs( currentTree *tree.Tree, nodeselector map[string]string, tolerations []core.Toleration, - orbconfig *orb.Orb, + dbClient database.Client, + namespace string, action string, version *string, features []string, @@ -30,6 +31,8 @@ func GetQueryAndDestroyFuncs( query operator.QueryFunc, destroy operator.DestroyFunc, secrets map[string]*secret.Secret, + existing map[string]*secret.Existing, + migrate bool, err error, ) { @@ -42,8 +45,8 @@ func GetQueryAndDestroyFuncs( switch desiredTree.Common.Kind { case "zitadel.caos.ch/ZITADEL": apiLabels := labels.MustForAPI(operatorLabels, "ZITADEL", desiredTree.Common.Version) - return zitadel.AdaptFunc(apiLabels, nodeselector, tolerations, orbconfig, action, version, features)(monitor, desiredTree, currentTree) + return zitadel.AdaptFunc(apiLabels, nodeselector, tolerations, dbClient, namespace, action, version, features)(monitor, desiredTree, currentTree) default: - return nil, nil, nil, errors.Errorf("unknown iam kind %s", desiredTree.Common.Kind) + return nil, nil, nil, nil, false, errors.Errorf("unknown iam kind %s", desiredTree.Common.Kind) } } diff --git a/operator/zitadel/kinds/iam/zitadel/adapt.go b/operator/zitadel/kinds/iam/zitadel/adapt.go index 71d39e5dc8..98569314d7 100644 --- a/operator/zitadel/kinds/iam/zitadel/adapt.go +++ b/operator/zitadel/kinds/iam/zitadel/adapt.go @@ -4,7 +4,6 @@ import ( "strconv" "github.com/caos/orbos/pkg/labels" - "github.com/caos/orbos/pkg/orb" "github.com/caos/orbos/pkg/secret" "github.com/caos/zitadel/operator/zitadel/kinds/iam/zitadel/database" "github.com/caos/zitadel/operator/zitadel/kinds/iam/zitadel/setup" @@ -13,7 +12,6 @@ import ( "github.com/caos/orbos/mntr" "github.com/caos/orbos/pkg/kubernetes" - "github.com/caos/orbos/pkg/kubernetes/resources/namespace" "github.com/caos/orbos/pkg/tree" "github.com/caos/zitadel/operator" "github.com/caos/zitadel/operator/zitadel/kinds/iam/zitadel/ambassador" @@ -28,7 +26,8 @@ func AdaptFunc( apiLabels *labels.API, nodeselector map[string]string, tolerations []core.Toleration, - orbconfig *orb.Orb, + dbClient database.Client, + namespace string, action string, version *string, features []string, @@ -41,24 +40,25 @@ func AdaptFunc( operator.QueryFunc, operator.DestroyFunc, map[string]*secret.Secret, + map[string]*secret.Existing, + bool, error, ) { - allSecrets := make(map[string]*secret.Secret) internalMonitor := monitor.WithField("kind", "iam") desiredKind, err := parseDesiredV0(desired) if err != nil { - return nil, nil, allSecrets, errors.Wrap(err, "parsing desired state failed") + return nil, nil, nil, nil, false, errors.Wrap(err, "parsing desired state failed") } desired.Parsed = desiredKind - secret.AppendSecrets("", allSecrets, getSecretsMap(desiredKind)) + + allSecrets, allExisting := getSecretsMap(desiredKind) if !monitor.IsVerbose() && desiredKind.Spec.Verbose { internalMonitor.Verbose() } - namespaceStr := "caos-zitadel" // shared elements cmName := "zitadel-vars" secretName := "zitadel-secret" @@ -70,28 +70,12 @@ func AdaptFunc( secretPath := "/secret" //services which are kubernetes resources and are used in the ambassador elements grpcServiceName := "grpc-v1" - var grpcPort uint16 = 80 + grpcPort := 80 httpServiceName := "http-v1" - var httpPort uint16 = 80 + httpPort := 80 uiServiceName := "ui-v1" - var uiPort uint16 = 80 - - // labels := getLabels() - users := getAllUsers(desiredKind) - allZitadelUsers := getZitadelUserList() - dbClient, err := database.NewClient(monitor, orbconfig.URL, orbconfig.Repokey) - if err != nil { - return nil, nil, allSecrets, err - } - - queryNS, err := namespace.AdaptFuncToEnsure(namespaceStr) - if err != nil { - return nil, nil, allSecrets, err - } - destroyNS, err := namespace.AdaptFuncToDestroy(namespaceStr) - if err != nil { - return nil, nil, allSecrets, err - } + uiPort := 80 + usersWithoutPWs := getUserListWithoutPasswords(desiredKind) zitadelComponent := labels.MustForComponent(apiLabels, "ZITADEL") zitadelDeploymentName := labels.MustForName(zitadelComponent, "zitadel") @@ -100,21 +84,21 @@ func AdaptFunc( internalMonitor, zitadelComponent, zitadelPodSelector, - namespaceStr, + namespace, grpcServiceName, - grpcPort, + uint16(grpcPort), httpServiceName, - httpPort, + uint16(httpPort), uiServiceName, - uiPort) + uint16(uiPort)) if err != nil { - return nil, nil, allSecrets, err + return nil, nil, nil, nil, false, err } - queryC, destroyC, getConfigurationHashes, err := configuration.AdaptFunc( + getQueryC, destroyC, getConfigurationHashes, err := configuration.AdaptFunc( internalMonitor, zitadelComponent, - namespaceStr, + namespace, desiredKind.Spec.Configuration, cmName, certPath, @@ -123,12 +107,11 @@ func AdaptFunc( consoleCMName, secretVarsName, secretPasswordName, - users, - services.GetClientIDFunc(namespaceStr, httpServiceName, httpPort), dbClient, + services.GetClientIDFunc(namespace, httpServiceName, httpPort), ) if err != nil { - return nil, nil, allSecrets, err + return nil, nil, nil, nil, false, err } queryDB, err := database.AdaptFunc( @@ -136,28 +119,28 @@ func AdaptFunc( dbClient, ) if err != nil { - return nil, nil, allSecrets, err + return nil, nil, nil, nil, false, err } queryM, destroyM, err := migration.AdaptFunc( internalMonitor, labels.MustForComponent(apiLabels, "database"), - namespaceStr, + namespace, action, secretPasswordName, migrationUser, - allZitadelUsers, + usersWithoutPWs, nodeselector, tolerations, ) if err != nil { - return nil, nil, allSecrets, err + return nil, nil, nil, nil, false, err } - querySetup, destroySetup, err := setup.AdaptFunc( + getQuerySetup, destroySetup, err := setup.AdaptFunc( internalMonitor, zitadelComponent, - namespaceStr, + namespace, action, desiredKind.Spec.NodeSelector, desiredKind.Spec.Tolerations, @@ -170,11 +153,10 @@ func AdaptFunc( consoleCMName, secretVarsName, secretPasswordName, - allZitadelUsers, - migration.GetDoneFunc(monitor, namespaceStr, action), - configuration.GetReadyFunc(monitor, namespaceStr, secretName, secretVarsName, secretPasswordName, cmName, consoleCMName), - getConfigurationHashes, ) + if err != nil { + return nil, nil, nil, nil, false, err + } queryD, destroyD, err := deployment.AdaptFunc( internalMonitor, @@ -182,7 +164,7 @@ func AdaptFunc( zitadelPodSelector, desiredKind.Spec.Force, version, - namespaceStr, + namespace, desiredKind.Spec.ReplicaCount, desiredKind.Spec.Affinity, cmName, @@ -192,64 +174,38 @@ func AdaptFunc( consoleCMName, secretVarsName, secretPasswordName, - allZitadelUsers, desiredKind.Spec.NodeSelector, desiredKind.Spec.Tolerations, desiredKind.Spec.Resources, - migration.GetDoneFunc(monitor, namespaceStr, action), - configuration.GetReadyFunc(monitor, namespaceStr, secretName, secretVarsName, secretPasswordName, cmName, consoleCMName), - setup.GetDoneFunc(monitor, namespaceStr, action), - getConfigurationHashes, + migration.GetDoneFunc(monitor, namespace, action), + configuration.GetReadyFunc(monitor, namespace, secretName, secretVarsName, secretPasswordName, cmName, consoleCMName), + setup.GetDoneFunc(monitor, namespace, action), ) if err != nil { - return nil, nil, allSecrets, err + return nil, nil, nil, nil, false, err } queryAmbassador, destroyAmbassador, err := ambassador.AdaptFunc( internalMonitor, labels.MustForComponent(apiLabels, "apiGateway"), - namespaceStr, - grpcServiceName+"."+namespaceStr+":"+strconv.Itoa(int(grpcPort)), - "http://"+httpServiceName+"."+namespaceStr+":"+strconv.Itoa(int(httpPort)), - "http://"+uiServiceName+"."+namespaceStr, + namespace, + grpcServiceName+"."+namespace+":"+strconv.Itoa(grpcPort), + "http://"+httpServiceName+"."+namespace+":"+strconv.Itoa(httpPort), + "http://"+uiServiceName+"."+namespace, desiredKind.Spec.Configuration.DNS, ) if err != nil { - return nil, nil, allSecrets, err + return nil, nil, nil, nil, false, err } destroyers := make([]operator.DestroyFunc, 0) - queriers := make([]operator.QueryFunc, 0) for _, feature := range features { switch feature { case "migration": - queriers = append(queriers, - queryDB, - //configuration - queryC, - //migration - queryM, - //wait until migration is completed - operator.EnsureFuncToQueryFunc(migration.GetDoneFunc(monitor, namespaceStr, action)), - ) destroyers = append(destroyers, destroyM, ) case "iam": - queriers = append(queriers, - operator.ResourceQueryToZitadelQuery(queryNS), - queryDB, - //configuration - queryC, - //migration - queryM, - //services - queryS, - querySetup, - queryD, - operator.EnsureFuncToQueryFunc(deployment.GetReadyFunc(monitor, namespaceStr, zitadelDeploymentName)), - queryAmbassador, - ) destroyers = append(destroyers, destroyAmbassador, destroyS, @@ -257,24 +213,85 @@ func AdaptFunc( destroyD, destroySetup, destroyC, - operator.ResourceDestroyToZitadelDestroy(destroyNS), - ) - case "scaledown": - queriers = append(queriers, - operator.EnsureFuncToQueryFunc(deployment.GetScaleFunc(monitor, namespaceStr, zitadelDeploymentName)(0)), - ) - case "scaleup": - queriers = append(queriers, - operator.EnsureFuncToQueryFunc(deployment.GetScaleFunc(monitor, namespaceStr, zitadelDeploymentName)(desiredKind.Spec.ReplicaCount)), ) } } return func(k8sClient kubernetes.ClientInt, queried map[string]interface{}) (operator.EnsureFunc, error) { + users, err := getAllUsers(k8sClient, desiredKind) + if err != nil { + return nil, err + } + allZitadelUsers, err := getZitadelUserList(k8sClient, desiredKind) + if err != nil { + return nil, err + } + + queryReadyM := operator.EnsureFuncToQueryFunc(migration.GetDoneFunc(monitor, namespace, action)) + queryC := getQueryC(users) + queryReadyC := operator.EnsureFuncToQueryFunc(configuration.GetReadyFunc(monitor, namespace, secretName, secretVarsName, secretPasswordName, cmName, consoleCMName)) + querySetup := getQuerySetup(allZitadelUsers, getConfigurationHashes) + queryReadySetup := operator.EnsureFuncToQueryFunc(setup.GetDoneFunc(monitor, namespace, action)) + queryD := queryD(allZitadelUsers, getConfigurationHashes) + queryReadyD := operator.EnsureFuncToQueryFunc(deployment.GetReadyFunc(monitor, namespace, zitadelDeploymentName)) + + queriers := make([]operator.QueryFunc, 0) + for _, feature := range features { + switch feature { + case "migration": + queriers = append(queriers, + queryDB, + //configuration + queryC, + queryReadyC, + //migration + queryM, + queryReadyM, + operator.EnsureFuncToQueryFunc(migration.GetCleanupFunc(monitor, namespace, action)), + ) + case "iam": + queriers = append(queriers, + queryDB, + //configuration + queryC, + queryReadyC, + //migration + queryM, + queryReadyM, + //services + queryS, + //setup + querySetup, + queryReadySetup, + //deployment + queryD, + queryReadyD, + //handle change if necessary for clientID + queryC, + queryReadyC, + //again apply deployment if config changed + queryD, + queryReadyD, + //apply ambassador crds after zitadel is ready + queryAmbassador, + ) + case "scaledown": + queriers = append(queriers, + operator.EnsureFuncToQueryFunc(deployment.GetScaleFunc(monitor, namespace, zitadelDeploymentName)(0)), + ) + case "scaleup": + queriers = append(queriers, + operator.EnsureFuncToQueryFunc(deployment.GetScaleFunc(monitor, namespace, zitadelDeploymentName)(desiredKind.Spec.ReplicaCount)), + ) + } + } + return operator.QueriersToEnsureFunc(internalMonitor, true, queriers, k8sClient, queried) }, operator.DestroyersToDestroyFunc(monitor, destroyers), allSecrets, + allExisting, + false, nil } } diff --git a/operator/zitadel/kinds/iam/zitadel/configuration/adapt.go b/operator/zitadel/kinds/iam/zitadel/configuration/adapt.go index 7ca58800cc..cec406bf8a 100644 --- a/operator/zitadel/kinds/iam/zitadel/configuration/adapt.go +++ b/operator/zitadel/kinds/iam/zitadel/configuration/adapt.go @@ -38,20 +38,21 @@ func AdaptFunc( consoleCMName string, secretVarsName string, secretPasswordName string, - necessaryUsers map[string]string, + dbClient database.Client, getClientID func() string, - dbClient database.ClientInt, ) ( - operator.QueryFunc, + func( + necessaryUsers map[string]string, + ) operator.QueryFunc, operator.DestroyFunc, - func(k8sClient kubernetes.ClientInt, queried map[string]interface{}) map[string]string, + func( + k8sClient kubernetes.ClientInt, + queried map[string]interface{}, + necessaryUsers map[string]string, + ) (map[string]string, error), error, ) { internalMonitor := monitor.WithField("component", "configuration") - - literalsSecret := literalsSecret(desired, googleServiceAccountJSONPath, zitadelKeysPath) - literalsSecretVars := literalsSecretVars(desired) - destroyCM, err := configmap.AdaptFuncToDestroy(namespace, cmName) if err != nil { return nil, nil, nil, err @@ -73,7 +74,7 @@ func AdaptFunc( return nil, nil, nil, err } - _, destroyUser, err := users.AdaptFunc(internalMonitor, necessaryUsers, dbClient) + _, destroyUser, err := users.AdaptFunc(internalMonitor, dbClient) if err != nil { return nil, nil, nil, err } @@ -87,71 +88,97 @@ func AdaptFunc( operator.ResourceDestroyToZitadelDestroy(destroySP), } - return func(k8sClient kubernetes.ClientInt, queried map[string]interface{}) (operator.EnsureFunc, error) { - queryUser, _, err := users.AdaptFunc(internalMonitor, necessaryUsers, dbClient) - if err != nil { - return nil, err - } - queryS, err := secret.AdaptFuncToEnsure(namespace, labels.MustForName(componentLabels, secretName), literalsSecret) - if err != nil { - return nil, err - } - querySV, err := secret.AdaptFuncToEnsure(namespace, labels.MustForName(componentLabels, secretVarsName), literalsSecretVars) - if err != nil { - return nil, err - } - querySP, err := secret.AdaptFuncToEnsure(namespace, labels.MustForName(componentLabels, secretPasswordName), necessaryUsers) - if err != nil { - return nil, err - } + return func( + necessaryUsers map[string]string, + ) operator.QueryFunc { + return func(k8sClient kubernetes.ClientInt, queried map[string]interface{}) (operator.EnsureFunc, error) { + literalsSecret, err := literalsSecret(k8sClient, desired, googleServiceAccountJSONPath, zitadelKeysPath) + if err != nil { + return nil, err + } + literalsSecretVars, err := literalsSecretVars(k8sClient, desired) + if err != nil { + return nil, err + } - queryCCM, err := configmap.AdaptFuncToEnsure( - namespace, - consoleCMName, - labels.MustForNameK8SMap(componentLabels, consoleCMName), - literalsConsoleCM( - getClientID(), - desired.DNS, - k8sClient, + queryUser, _, err := users.AdaptFunc(internalMonitor, dbClient) + if err != nil { + return nil, err + } + queryS, err := secret.AdaptFuncToEnsure(namespace, labels.MustForName(componentLabels, secretName), literalsSecret) + if err != nil { + return nil, err + } + querySV, err := secret.AdaptFuncToEnsure(namespace, labels.MustForName(componentLabels, secretVarsName), literalsSecretVars) + if err != nil { + return nil, err + } + querySP, err := secret.AdaptFuncToEnsure(namespace, labels.MustForName(componentLabels, secretPasswordName), necessaryUsers) + if err != nil { + return nil, err + } + + queryCCM, err := configmap.AdaptFuncToEnsure( namespace, consoleCMName, - ), - ) - if err != nil { - return nil, err - } + labels.MustForNameK8SMap(componentLabels, consoleCMName), + literalsConsoleCM( + getClientID(), + desired.DNS, + k8sClient, + namespace, + consoleCMName, + ), + ) + if err != nil { + return nil, err + } - queryCM, err := configmap.AdaptFuncToEnsure( - namespace, - cmName, - labels.MustForNameK8SMap(componentLabels, cmName), - literalsConfigMap( - desired, - necessaryUsers, - certPath, - secretPath, - googleServiceAccountJSONPath, - zitadelKeysPath, - queried, - ), - ) - if err != nil { - return nil, err - } + queryCM, err := configmap.AdaptFuncToEnsure( + namespace, + cmName, + labels.MustForNameK8SMap(componentLabels, cmName), + literalsConfigMap( + desired, + necessaryUsers, + certPath, + secretPath, + googleServiceAccountJSONPath, + zitadelKeysPath, + queried, + ), + ) + if err != nil { + return nil, err + } - queriers := []operator.QueryFunc{ - queryUser, - operator.ResourceQueryToZitadelQuery(queryS), - operator.ResourceQueryToZitadelQuery(queryCCM), - operator.ResourceQueryToZitadelQuery(querySV), - operator.ResourceQueryToZitadelQuery(querySP), - operator.ResourceQueryToZitadelQuery(queryCM), - } + queriers := []operator.QueryFunc{ + queryUser(necessaryUsers), + operator.ResourceQueryToZitadelQuery(queryS), + operator.ResourceQueryToZitadelQuery(queryCCM), + operator.ResourceQueryToZitadelQuery(querySV), + operator.ResourceQueryToZitadelQuery(querySP), + operator.ResourceQueryToZitadelQuery(queryCM), + } - return operator.QueriersToEnsureFunc(internalMonitor, false, queriers, k8sClient, queried) + return operator.QueriersToEnsureFunc(internalMonitor, false, queriers, k8sClient, queried) + } }, operator.DestroyersToDestroyFunc(internalMonitor, destroyers), - func(k8sClient kubernetes.ClientInt, queried map[string]interface{}) map[string]string { + func( + k8sClient kubernetes.ClientInt, + queried map[string]interface{}, + necessaryUsers map[string]string, + ) (map[string]string, error) { + literalsSecret, err := literalsSecret(k8sClient, desired, googleServiceAccountJSONPath, zitadelKeysPath) + if err != nil { + return nil, err + } + literalsSecretVars, err := literalsSecretVars(k8sClient, desired) + if err != nil { + return nil, err + } + return map[string]string{ secretName: getHash(literalsSecret), secretVarsName: getHash(literalsSecretVars), @@ -176,7 +203,7 @@ func AdaptFunc( consoleCMName, ), ), - } + }, nil }, nil } diff --git a/operator/zitadel/kinds/iam/zitadel/configuration/adapt_test.go b/operator/zitadel/kinds/iam/zitadel/configuration/adapt_test.go index ad7cac263f..b3ffa6ac08 100644 --- a/operator/zitadel/kinds/iam/zitadel/configuration/adapt_test.go +++ b/operator/zitadel/kinds/iam/zitadel/configuration/adapt_test.go @@ -38,6 +38,7 @@ func SetConfigMap( } func SetSecretVars( + t *testing.T, k8sClient *kubernetesmock.MockClientInt, namespace string, secretVarsName string, @@ -45,6 +46,8 @@ func SetSecretVars( desired *Configuration, ) { + literalsSV, err := literalsSecretVars(k8sClient, desired) + assert.NoError(t, err) k8sClient.EXPECT().ApplySecret(&corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ Namespace: namespace, @@ -52,7 +55,7 @@ func SetSecretVars( Labels: labels, }, Type: "Opaque", - StringData: literalsSecretVars(desired), + StringData: literalsSV, }).Times(1) } func SetConsoleCM( @@ -76,12 +79,16 @@ func SetConsoleCM( k8sClient.EXPECT().ApplyConfigmap(consoleCM).Times(1) } func SetSecrets( + t *testing.T, k8sClient *kubernetesmock.MockClientInt, namespace string, secretName string, labels map[string]string, desired *Configuration, ) { + literalsS, err := literalsSecret(k8sClient, desired, googleServiceAccountJSONPath, zitadelKeysPath) + assert.NoError(t, err) + k8sClient.EXPECT().ApplySecret(&corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ Namespace: namespace, @@ -89,7 +96,7 @@ func SetSecrets( Labels: labels, }, Type: "Opaque", - StringData: literalsSecret(desired, googleServiceAccountJSONPath, zitadelKeysPath), + StringData: literalsS, }).Times(1) } @@ -114,7 +121,7 @@ func SetSecretPasswords( func TestConfiguration_Adapt(t *testing.T) { k8sClient := kubernetesmock.NewMockClientInt(gomock.NewController(t)) - dbClient := databasemock.NewMockClientInt(gomock.NewController(t)) + dbClient := databasemock.NewMockClient(gomock.NewController(t)) monitor := mntr.Monitor{Fields: map[string]interface{}{"component": "configuration"}} namespace := "test" @@ -162,6 +169,7 @@ func TestConfiguration_Adapt(t *testing.T) { zitadelKeysPath) SetSecretVars( + t, k8sClient, namespace, secretVarsName, @@ -179,6 +187,7 @@ func TestConfiguration_Adapt(t *testing.T) { ) SetSecrets( + t, k8sClient, namespace, secretName, @@ -194,7 +203,7 @@ func TestConfiguration_Adapt(t *testing.T) { users, ) - query, _, _, err := AdaptFunc( + getQuery, _, _, err := AdaptFunc( monitor, componentLabels, namespace, @@ -206,12 +215,11 @@ func TestConfiguration_Adapt(t *testing.T) { consoleCMName, secretVarsName, secretPasswordName, - users, - getClientID, dbClient, + getClientID, ) - assert.NoError(t, err) + query := getQuery(users) ensure, err := query(k8sClient, queried) assert.NoError(t, err) assert.NoError(t, ensure(k8sClient)) @@ -220,7 +228,7 @@ func TestConfiguration_Adapt(t *testing.T) { func TestConfiguration_AdaptFull(t *testing.T) { k8sClient := kubernetesmock.NewMockClientInt(gomock.NewController(t)) - dbClient := databasemock.NewMockClientInt(gomock.NewController(t)) + dbClient := databasemock.NewMockClient(gomock.NewController(t)) monitor := mntr.Monitor{Fields: map[string]interface{}{"component": "configuration"}} namespace := "test2" @@ -268,6 +276,7 @@ func TestConfiguration_AdaptFull(t *testing.T) { zitadelKeysPath) SetSecretVars( + t, k8sClient, namespace, secretVarsName, @@ -285,6 +294,7 @@ func TestConfiguration_AdaptFull(t *testing.T) { ) SetSecrets( + t, k8sClient, namespace, secretName, @@ -300,7 +310,7 @@ func TestConfiguration_AdaptFull(t *testing.T) { users, ) - query, _, _, err := AdaptFunc( + getQuery, _, _, err := AdaptFunc( monitor, componentLabels, namespace, @@ -312,12 +322,12 @@ func TestConfiguration_AdaptFull(t *testing.T) { consoleCMName, secretVarsName, secretPasswordName, - users, - getClientID, dbClient, + getClientID, ) assert.NoError(t, err) + query := getQuery(users) ensure, err := query(k8sClient, queried) assert.NoError(t, err) assert.NoError(t, ensure(k8sClient)) diff --git a/operator/zitadel/kinds/iam/zitadel/configuration/desired.go b/operator/zitadel/kinds/iam/zitadel/configuration/desired.go index 9831d68f32..79d9e182e0 100644 --- a/operator/zitadel/kinds/iam/zitadel/configuration/desired.go +++ b/operator/zitadel/kinds/iam/zitadel/configuration/desired.go @@ -27,52 +27,65 @@ type Subdomains struct { Issuer string `yaml:"issuer"` } type Passwords struct { - Migration *secret.Secret `yaml:"migration"` - Management *secret.Secret `yaml:"management"` - Auth *secret.Secret `yaml:"auth"` - Authz *secret.Secret `yaml:"authz"` - Adminapi *secret.Secret `yaml:"adminapi"` - Notification *secret.Secret `yaml:"notification"` - Eventstore *secret.Secret `yaml:"eventstore"` + Migration *secret.Secret `yaml:"migration"` + Management *secret.Secret `yaml:"management"` + Auth *secret.Secret `yaml:"auth"` + Authz *secret.Secret `yaml:"authz"` + Adminapi *secret.Secret `yaml:"adminapi"` + Notification *secret.Secret `yaml:"notification"` + Eventstore *secret.Secret `yaml:"eventstore"` + ExistingMigration *secret.Existing `yaml:"existingMigration"` + ExistingManagement *secret.Existing `yaml:"existingManagement"` + ExistingAuth *secret.Existing `yaml:"existingAuth"` + ExistingAuthz *secret.Existing `yaml:"existingAuthz"` + ExistingAdminapi *secret.Existing `yaml:"existingAdminapi"` + ExistingNotification *secret.Existing `yaml:"existingNotification"` + ExistingEventstore *secret.Existing `yaml:"existingEventstore"` } type Secrets struct { - Keys *secret.Secret `yaml:"keys,omitempty"` - UserVerificationID string `yaml:"userVerificationID,omitempty"` - OTPVerificationID string `yaml:"otpVerificationID,omitempty"` - OIDCKeysID string `yaml:"oidcKeysID,omitempty"` - CookieID string `yaml:"cookieID,omitempty"` - CSRFID string `yaml:"csrfID,omitempty"` - DomainVerificationID string `yaml:"domainVerificationID,omitempty"` - IDPConfigVerificationID string `yaml:"idpConfigVerificationID,omitempty"` + Keys *secret.Secret `yaml:"keys,omitempty"` + ExistingKeys *secret.Existing `yaml:"existingKeys,omitempty"` + UserVerificationID string `yaml:"userVerificationID,omitempty"` + OTPVerificationID string `yaml:"otpVerificationID,omitempty"` + OIDCKeysID string `yaml:"oidcKeysID,omitempty"` + CookieID string `yaml:"cookieID,omitempty"` + CSRFID string `yaml:"csrfID,omitempty"` + DomainVerificationID string `yaml:"domainVerificationID,omitempty"` + IDPConfigVerificationID string `yaml:"idpConfigVerificationID,omitempty"` } type Notifications struct { - GoogleChatURL *secret.Secret `yaml:"googleChatURL,omitempty"` - Email *Email `yaml:"email,omitempty"` - Twilio *Twilio `yaml:"twilio,omitempty"` + GoogleChatURL *secret.Secret `yaml:"googleChatURL,omitempty"` + ExistingGoogleChatURL *secret.Existing `yaml:"existingGoogleChatURL,omitempty"` + Email *Email `yaml:"email,omitempty"` + Twilio *Twilio `yaml:"twilio,omitempty"` } type Tracing struct { - ServiceAccountJSON *secret.Secret `yaml:"serviceAccountJSON,omitempty"` - ProjectID string `yaml:"projectID,omitempty"` - Fraction string `yaml:"fraction,omitempty"` - Type string `yaml:"type,omitempty"` + ServiceAccountJSON *secret.Secret `yaml:"serviceAccountJSON,omitempty"` + ExistingServiceAccountJSON *secret.Existing `yaml:"existingServiceAccountJSON,omitempty"` + ProjectID string `yaml:"projectID,omitempty"` + Fraction string `yaml:"fraction,omitempty"` + Type string `yaml:"type,omitempty"` } type Twilio struct { - SenderName string `yaml:"senderName,omitempty"` - AuthToken *secret.Secret `yaml:"authToken,omitempty"` - SID *secret.Secret `yaml:"sid,omitempty"` + SenderName string `yaml:"senderName,omitempty"` + AuthToken *secret.Secret `yaml:"authToken,omitempty"` + SID *secret.Secret `yaml:"sid,omitempty"` + ExistingAuthToken *secret.Existing `yaml:"existingAuthToken,omitempty"` + ExistingSID *secret.Existing `yaml:"ExistingSid,omitempty"` } type Email struct { - SMTPHost string `yaml:"smtpHost,omitempty"` - SMTPUser string `yaml:"smtpUser,omitempty"` - SenderAddress string `yaml:"senderAddress,omitempty"` - SenderName string `yaml:"senderName,omitempty"` - TLS bool `yaml:"tls,omitempty"` - AppKey *secret.Secret `yaml:"appKey,omitempty"` + SMTPHost string `yaml:"smtpHost,omitempty"` + SMTPUser string `yaml:"smtpUser,omitempty"` + SenderAddress string `yaml:"senderAddress,omitempty"` + SenderName string `yaml:"senderName,omitempty"` + TLS bool `yaml:"tls,omitempty"` + AppKey *secret.Secret `yaml:"appKey,omitempty"` + ExistingAppKey *secret.Existing `yaml:"existingAppKey,omitempty"` } type Cache struct { diff --git a/operator/zitadel/kinds/iam/zitadel/configuration/literals.go b/operator/zitadel/kinds/iam/zitadel/configuration/literals.go index ca552f45fd..ddfa46d284 100644 --- a/operator/zitadel/kinds/iam/zitadel/configuration/literals.go +++ b/operator/zitadel/kinds/iam/zitadel/configuration/literals.go @@ -2,6 +2,7 @@ package configuration import ( "encoding/json" + "github.com/caos/orbos/pkg/helper" "github.com/caos/orbos/pkg/kubernetes" "github.com/caos/zitadel/operator/zitadel/kinds/iam/zitadel/database" "strconv" @@ -106,38 +107,62 @@ func literalsConfigMap( return literalsConfigMap } -func literalsSecret(desired *Configuration, googleServiceAccountJSONPath, zitadelKeysPath string) map[string]string { +func literalsSecret(k8sClient kubernetes.ClientInt, desired *Configuration, googleServiceAccountJSONPath, zitadelKeysPath string) (map[string]string, error) { literalsSecret := map[string]string{} if desired != nil { - if desired.Tracing != nil && desired.Tracing.ServiceAccountJSON != nil { - literalsSecret[googleServiceAccountJSONPath] = desired.Tracing.ServiceAccountJSON.Value + if desired.Tracing != nil && (desired.Tracing.ServiceAccountJSON != nil || desired.Tracing.ExistingServiceAccountJSON != nil) { + value, err := helper.GetSecretValue(k8sClient, desired.Tracing.ServiceAccountJSON, desired.Tracing.ExistingServiceAccountJSON) + if err != nil { + return nil, err + } + literalsSecret[googleServiceAccountJSONPath] = value } - if desired.Secrets != nil && desired.Secrets.Keys != nil { - literalsSecret[zitadelKeysPath] = desired.Secrets.Keys.Value + if desired.Secrets != nil && (desired.Secrets.Keys != nil || desired.Secrets.ExistingKeys != nil) { + value, err := helper.GetSecretValue(k8sClient, desired.Secrets.Keys, desired.Secrets.ExistingKeys) + if err != nil { + return nil, err + } + literalsSecret[zitadelKeysPath] = value } } - return literalsSecret + return literalsSecret, nil } -func literalsSecretVars(desired *Configuration) map[string]string { +func literalsSecretVars(k8sClient kubernetes.ClientInt, desired *Configuration) (map[string]string, error) { literalsSecretVars := map[string]string{} if desired != nil { if desired.Notifications != nil { - if desired.Notifications.Email.AppKey != nil { - literalsSecretVars["ZITADEL_EMAILAPPKEY"] = desired.Notifications.Email.AppKey.Value + if desired.Notifications.Email.AppKey != nil || desired.Notifications.Email.ExistingAppKey != nil { + value, err := helper.GetSecretValue(k8sClient, desired.Notifications.Email.AppKey, desired.Notifications.Email.ExistingAppKey) + if err != nil { + return nil, err + } + literalsSecretVars["ZITADEL_EMAILAPPKEY"] = value } - if desired.Notifications.GoogleChatURL != nil { - literalsSecretVars["ZITADEL_GOOGLE_CHAT_URL"] = desired.Notifications.GoogleChatURL.Value + if desired.Notifications.GoogleChatURL != nil || desired.Notifications.ExistingGoogleChatURL != nil { + value, err := helper.GetSecretValue(k8sClient, desired.Notifications.GoogleChatURL, desired.Notifications.ExistingGoogleChatURL) + if err != nil { + return nil, err + } + literalsSecretVars["ZITADEL_GOOGLE_CHAT_URL"] = value } - if desired.Notifications.Twilio.AuthToken != nil { - literalsSecretVars["ZITADEL_TWILIO_AUTH_TOKEN"] = desired.Notifications.Twilio.AuthToken.Value + if desired.Notifications.Twilio.AuthToken != nil || desired.Notifications.Twilio.ExistingAuthToken != nil { + value, err := helper.GetSecretValue(k8sClient, desired.Notifications.Twilio.AuthToken, desired.Notifications.Twilio.ExistingAuthToken) + if err != nil { + return nil, err + } + literalsSecretVars["ZITADEL_TWILIO_AUTH_TOKEN"] = value } - if desired.Notifications.Twilio.SID != nil { - literalsSecretVars["ZITADEL_TWILIO_SID"] = desired.Notifications.Twilio.SID.Value + if desired.Notifications.Twilio.SID != nil || desired.Notifications.Twilio.ExistingSID != nil { + value, err := helper.GetSecretValue(k8sClient, desired.Notifications.Twilio.SID, desired.Notifications.Twilio.ExistingSID) + if err != nil { + return nil, err + } + literalsSecretVars["ZITADEL_TWILIO_SID"] = value } } } - return literalsSecretVars + return literalsSecretVars, nil } func literalsConsoleCM( diff --git a/operator/zitadel/kinds/iam/zitadel/configuration/literals_test.go b/operator/zitadel/kinds/iam/zitadel/configuration/literals_test.go index 3c99b45f68..8a774cf013 100644 --- a/operator/zitadel/kinds/iam/zitadel/configuration/literals_test.go +++ b/operator/zitadel/kinds/iam/zitadel/configuration/literals_test.go @@ -1,6 +1,8 @@ package configuration import ( + "testing" + kubernetesmock "github.com/caos/orbos/pkg/kubernetes/mock" "github.com/caos/orbos/pkg/secret" "github.com/caos/zitadel/operator/zitadel/kinds/iam/zitadel/database" @@ -8,7 +10,6 @@ import ( "github.com/stretchr/testify/assert" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "testing" ) var ( @@ -125,6 +126,62 @@ var ( }, ClusterDNS: "cluster", } + desiredFullExisting = &Configuration{ + Tracing: &Tracing{ + ExistingServiceAccountJSON: &secret.Existing{"sajson", "sajson", "sajson"}, + ProjectID: "projectid", + Fraction: "fraction", + Type: "type", + }, + Secrets: &Secrets{ + ExistingKeys: &secret.Existing{"keys", "keys", "keys"}, + UserVerificationID: "userid", + OTPVerificationID: "otpid", + OIDCKeysID: "oidcid", + CookieID: "cookieid", + CSRFID: "csrfid", + DomainVerificationID: "domainid", + IDPConfigVerificationID: "idpid", + }, + Notifications: &Notifications{ + ExistingGoogleChatURL: &secret.Existing{"chat", "chat", "chat"}, + Email: &Email{ + SMTPHost: "smtphost", + SMTPUser: "smtpuser", + SenderAddress: "sender", + SenderName: "sendername", + TLS: true, + ExistingAppKey: &secret.Existing{"appkey", "appkey", "appkey"}, + }, + Twilio: &Twilio{ + SenderName: "sendername", + ExistingAuthToken: &secret.Existing{"migration", "migration", "migration"}, + ExistingSID: &secret.Existing{"sid", "sid", "sid"}, + }, + }, + Passwords: &Passwords{ + ExistingMigration: &secret.Existing{"migration", "migration", "migration"}, + ExistingEventstore: &secret.Existing{"eventstore", "eventstore", "eventstore"}, + ExistingNotification: &secret.Existing{"notification", "notification", "notification"}, + ExistingAuthz: &secret.Existing{"authz", "authz", "authz"}, + ExistingAuth: &secret.Existing{"auth", "auth", "auth"}, + ExistingAdminapi: &secret.Existing{"adminapi", "adminapi", "adminapi"}, + ExistingManagement: &secret.Existing{"management", "management", "management"}, + }, + DebugMode: true, + LogLevel: "debug", + DNS: &DNS{ + Domain: "domain", + TlsSecret: "tls", + Subdomains: &Subdomains{ + Accounts: "accounts", + API: "api", + Console: "console", + Issuer: "issuer", + }, + }, + ClusterDNS: "cluster", + } ) func TestConfiguration_LiteralsConfigMap(t *testing.T) { @@ -281,6 +338,7 @@ func TestConfiguration_LiteralsConfigMapFull(t *testing.T) { } func TestConfiguration_LiteralsSecrets(t *testing.T) { + client := kubernetesmock.NewMockClientInt(gomock.NewController(t)) googleSA := "sajson" zitadelKeyPath := "zitadel" @@ -289,11 +347,13 @@ func TestConfiguration_LiteralsSecrets(t *testing.T) { zitadelKeyPath: "", } - literals := literalsSecret(desiredEmpty, googleSA, zitadelKeyPath) + literals, err := literalsSecret(client, desiredEmpty, googleSA, zitadelKeyPath) + assert.NoError(t, err) assert.EqualValues(t, equals, literals) } func TestConfiguration_LiteralsSecretsFull(t *testing.T) { + client := kubernetesmock.NewMockClientInt(gomock.NewController(t)) googleSA := "sajson" zitadelKeyPath := "zitadel" @@ -302,31 +362,123 @@ func TestConfiguration_LiteralsSecretsFull(t *testing.T) { zitadelKeyPath: "keys", } - literals := literalsSecret(desiredFull, googleSA, zitadelKeyPath) + literals, err := literalsSecret(client, desiredFull, googleSA, zitadelKeyPath) + assert.NoError(t, err) + assert.EqualValues(t, equals, literals) +} + +func TestConfiguration_LiteralsSecretsExisting(t *testing.T) { + client := kubernetesmock.NewMockClientInt(gomock.NewController(t)) + sajson := "sajson" + keys := "keys" + namespace := "caos-system" + client.EXPECT().GetSecret(namespace, desiredFullExisting.Tracing.ExistingServiceAccountJSON.Name).Return(&corev1.Secret{ + StringData: map[string]string{ + desiredFullExisting.Tracing.ExistingServiceAccountJSON.Key: sajson, + }, + Data: map[string][]byte{ + desiredFullExisting.Tracing.ExistingServiceAccountJSON.Key: []byte(sajson), + }, + }, nil) + client.EXPECT().GetSecret(namespace, desiredFullExisting.Secrets.ExistingKeys.Name).Return(&corev1.Secret{ + StringData: map[string]string{ + desiredFullExisting.Secrets.ExistingKeys.Key: keys, + }, + Data: map[string][]byte{ + desiredFullExisting.Secrets.ExistingKeys.Key: []byte(keys), + }, + }, nil) + googleSA := "sajson" + zitadelKeyPath := "zitadel" + + equals := map[string]string{ + googleSA: sajson, + zitadelKeyPath: keys, + } + + literals, err := literalsSecret(client, desiredFullExisting, googleSA, zitadelKeyPath) + assert.NoError(t, err) assert.EqualValues(t, equals, literals) } func TestConfiguration_LiteralsSecretVars(t *testing.T) { + client := kubernetesmock.NewMockClientInt(gomock.NewController(t)) equals := map[string]string{ "ZITADEL_EMAILAPPKEY": "", "ZITADEL_GOOGLE_CHAT_URL": "", "ZITADEL_TWILIO_AUTH_TOKEN": "", "ZITADEL_TWILIO_SID": "", } - literals := literalsSecretVars(desiredEmpty) + literals, err := literalsSecretVars(client, desiredEmpty) + assert.NoError(t, err) assert.EqualValues(t, equals, literals) } func TestConfiguration_LiteralsSecretVarsFull(t *testing.T) { + client := kubernetesmock.NewMockClientInt(gomock.NewController(t)) equals := map[string]string{ "ZITADEL_EMAILAPPKEY": "appkey", "ZITADEL_GOOGLE_CHAT_URL": "chat", "ZITADEL_TWILIO_AUTH_TOKEN": "authtoken", "ZITADEL_TWILIO_SID": "sid", } - literals := literalsSecretVars(desiredFull) + literals, err := literalsSecretVars(client, desiredFull) + assert.NoError(t, err) + assert.EqualValues(t, equals, literals) +} + +func TestConfiguration_LiteralsSecretVarsExisting(t *testing.T) { + client := kubernetesmock.NewMockClientInt(gomock.NewController(t)) + // namespace := "caos-system" + appkey := "appkey" + chat := "chat" + authtoken := "authtoken" + sid := "sid" + /* TODO: incomment!!! + client.EXPECT().GetSecret(namespace, desiredFullExisting.Notifications.Email.ExistingAppKey.Name).Return(&corev1.Secret{ + StringData: map[string]string{ + desiredFullExisting.Notifications.Email.ExistingAppKey.Key: appkey, + }, + Data: map[string][]byte{ + desiredFullExisting.Notifications.Email.ExistingAppKey.Key: []byte(appkey), + }, + }, nil) + client.EXPECT().GetSecret(namespace, desiredFullExisting.Notifications.ExistingGoogleChatURL.Name).Return(&corev1.Secret{ + StringData: map[string]string{ + desiredFullExisting.Notifications.ExistingGoogleChatURL.Key: chat, + }, + Data: map[string][]byte{ + desiredFullExisting.Notifications.ExistingGoogleChatURL.Key: []byte(chat), + }, + }, nil) + client.EXPECT().GetSecret(namespace, desiredFullExisting.Notifications.Twilio.ExistingAuthToken.Name).Return(&corev1.Secret{ + StringData: map[string]string{ + desiredFullExisting.Notifications.Twilio.ExistingAuthToken.Key: authtoken, + }, + Data: map[string][]byte{ + desiredFullExisting.Notifications.Twilio.ExistingAuthToken.Key: []byte(authtoken), + }, + }, nil) + client.EXPECT().GetSecret(namespace, desiredFullExisting.Notifications.Twilio.ExistingSID.Name).Return(&corev1.Secret{ + StringData: map[string]string{ + desiredFullExisting.Notifications.Twilio.ExistingSID.Key: sid, + }, + Data: map[string][]byte{ + desiredFullExisting.Notifications.Twilio.ExistingSID.Key: []byte(sid), + }, + }, nil) + */ + equals := map[string]string{ + "ZITADEL_EMAILAPPKEY": appkey, + "ZITADEL_GOOGLE_CHAT_URL": chat, + "ZITADEL_TWILIO_AUTH_TOKEN": authtoken, + "ZITADEL_TWILIO_SID": sid, + } + literals, err := literalsSecretVars(client, desiredFull) + + assert.NoError(t, err) assert.EqualValues(t, equals, literals) } diff --git a/operator/zitadel/kinds/iam/zitadel/configuration/users/adapt.go b/operator/zitadel/kinds/iam/zitadel/configuration/users/adapt.go index 09f777270a..8b8a50c21d 100644 --- a/operator/zitadel/kinds/iam/zitadel/configuration/users/adapt.go +++ b/operator/zitadel/kinds/iam/zitadel/configuration/users/adapt.go @@ -9,14 +9,14 @@ import ( func AdaptFunc( monitor mntr.Monitor, - users map[string]string, - dbClient database.ClientInt, + dbClient database.Client, ) ( - operator.QueryFunc, + func(users map[string]string) operator.QueryFunc, operator.DestroyFunc, error, ) { internalMonitor := monitor.WithField("component", "db-users") + destroyers := make([]operator.DestroyFunc, 0) destroyers = append(destroyers, func(k8sClient kubernetes.ClientInt) error { @@ -32,35 +32,39 @@ func AdaptFunc( return nil }) - usernames := []string{} - for username := range users { - usernames = append(usernames, username) - } - - return func(k8sClient kubernetes.ClientInt, queried map[string]interface{}) (operator.EnsureFunc, error) { - queriers := make([]operator.QueryFunc, 0) - db, err := database.GetDatabaseInQueried(queried) - if err != nil { - return nil, err - } - - for _, username := range usernames { - ensure := createIfNecessary(monitor, username, db.Users, dbClient) - if ensure != nil { - queriers = append(queriers, operator.EnsureFuncToQueryFunc(ensure)) + return func(users map[string]string) operator.QueryFunc { + return func(k8sClient kubernetes.ClientInt, queried map[string]interface{}) (operator.EnsureFunc, error) { + queriers := make([]operator.QueryFunc, 0) + db, err := database.GetDatabaseInQueried(queried) + if err != nil { + return nil, err } - } - for _, listedUser := range db.Users { - ensure := deleteIfNotRequired(monitor, listedUser, usernames, dbClient) - if ensure != nil { - queriers = append(queriers, operator.EnsureFuncToQueryFunc(ensure)) - } - } - if queriers == nil || len(queriers) == 0 { - return func(k8sClient kubernetes.ClientInt) error { return nil }, nil + usernames := []string{} + for username := range users { + usernames = append(usernames, username) + } + + for _, username := range usernames { + ensure := createIfNecessary(monitor, username, db.Users, dbClient) + if ensure != nil { + queriers = append(queriers, operator.EnsureFuncToQueryFunc(ensure)) + } + } + + for _, listedUser := range db.Users { + ensure := deleteIfNotRequired(monitor, listedUser, usernames, dbClient) + if ensure != nil { + queriers = append(queriers, operator.EnsureFuncToQueryFunc(ensure)) + } + } + + if queriers == nil || len(queriers) == 0 { + return func(k8sClient kubernetes.ClientInt) error { return nil }, nil + } + return operator.QueriersToEnsureFunc(internalMonitor, false, queriers, k8sClient, queried) } - return operator.QueriersToEnsureFunc(internalMonitor, false, queriers, k8sClient, queried) - }, operator.DestroyersToDestroyFunc(internalMonitor, destroyers), + }, + operator.DestroyersToDestroyFunc(internalMonitor, destroyers), nil } diff --git a/operator/zitadel/kinds/iam/zitadel/configuration/users/adapt_test.go b/operator/zitadel/kinds/iam/zitadel/configuration/users/adapt_test.go index 0354c102f0..8e9c69919d 100644 --- a/operator/zitadel/kinds/iam/zitadel/configuration/users/adapt_test.go +++ b/operator/zitadel/kinds/iam/zitadel/configuration/users/adapt_test.go @@ -1,19 +1,20 @@ package users import ( + "testing" + "github.com/caos/orbos/mntr" kubernetesmock "github.com/caos/orbos/pkg/kubernetes/mock" "github.com/caos/zitadel/operator/zitadel/kinds/iam/zitadel/database" databasemock "github.com/caos/zitadel/operator/zitadel/kinds/iam/zitadel/database/mock" "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" - "testing" ) func TestUsers_Adapt_CreateFirst(t *testing.T) { client := kubernetesmock.NewMockClientInt(gomock.NewController(t)) users := map[string]string{"test": "testpw"} - dbClient := databasemock.NewMockClientInt(gomock.NewController(t)) + dbClient := databasemock.NewMockClient(gomock.NewController(t)) monitor := mntr.Monitor{} queried := map[string]interface{}{} @@ -24,8 +25,9 @@ func TestUsers_Adapt_CreateFirst(t *testing.T) { }) dbClient.EXPECT().AddUser(monitor, "test", client) - query, _, err := AdaptFunc(monitor, users, dbClient) + getQuery, _, err := AdaptFunc(monitor, dbClient) assert.NoError(t, err) + query := getQuery(users) ensure, err := query(client, queried) assert.NoError(t, err) err = ensure(client) @@ -35,7 +37,7 @@ func TestUsers_Adapt_CreateFirst(t *testing.T) { func TestUsers_Adapt_DoNothing(t *testing.T) { client := kubernetesmock.NewMockClientInt(gomock.NewController(t)) users := map[string]string{"test": "testpw"} - dbClient := databasemock.NewMockClientInt(gomock.NewController(t)) + dbClient := databasemock.NewMockClient(gomock.NewController(t)) monitor := mntr.Monitor{} queried := map[string]interface{}{} @@ -45,8 +47,9 @@ func TestUsers_Adapt_DoNothing(t *testing.T) { Users: []string{"test"}, }) - query, _, err := AdaptFunc(monitor, users, dbClient) + getQuery, _, err := AdaptFunc(monitor, dbClient) assert.NoError(t, err) + query := getQuery(users) ensure, err := query(client, queried) assert.NoError(t, err) assert.NotNil(t, ensure) @@ -56,7 +59,7 @@ func TestUsers_Adapt_DoNothing(t *testing.T) { func TestUsers_Adapt_Add(t *testing.T) { client := kubernetesmock.NewMockClientInt(gomock.NewController(t)) users := map[string]string{"test": "testpw", "test2": "testpw"} - dbClient := databasemock.NewMockClientInt(gomock.NewController(t)) + dbClient := databasemock.NewMockClient(gomock.NewController(t)) monitor := mntr.Monitor{} queried := map[string]interface{}{} @@ -67,8 +70,9 @@ func TestUsers_Adapt_Add(t *testing.T) { }) dbClient.EXPECT().AddUser(monitor, "test2", client) - query, _, err := AdaptFunc(monitor, users, dbClient) + getQuery, _, err := AdaptFunc(monitor, dbClient) assert.NoError(t, err) + query := getQuery(users) ensure, err := query(client, queried) assert.NoError(t, err) err = ensure(client) @@ -78,7 +82,7 @@ func TestUsers_Adapt_Add(t *testing.T) { func TestUsers_Adapt_Delete(t *testing.T) { client := kubernetesmock.NewMockClientInt(gomock.NewController(t)) users := map[string]string{"test": "testpw", "test2": "testpw"} - dbClient := databasemock.NewMockClientInt(gomock.NewController(t)) + dbClient := databasemock.NewMockClient(gomock.NewController(t)) monitor := mntr.Monitor{} queried := map[string]interface{}{} @@ -90,8 +94,9 @@ func TestUsers_Adapt_Delete(t *testing.T) { dbClient.EXPECT().DeleteUser(monitor, "test3", client) - query, _, err := AdaptFunc(monitor, users, dbClient) + getQuery, _, err := AdaptFunc(monitor, dbClient) assert.NoError(t, err) + query := getQuery(users) ensure, err := query(client, queried) err = ensure(client) assert.NoError(t, err) @@ -100,7 +105,7 @@ func TestUsers_Adapt_Delete(t *testing.T) { func TestUsers_Adapt_DeleteMultiple(t *testing.T) { client := kubernetesmock.NewMockClientInt(gomock.NewController(t)) users := map[string]string{} - dbClient := databasemock.NewMockClientInt(gomock.NewController(t)) + dbClient := databasemock.NewMockClient(gomock.NewController(t)) monitor := mntr.Monitor{} queried := map[string]interface{}{} @@ -114,8 +119,9 @@ func TestUsers_Adapt_DeleteMultiple(t *testing.T) { dbClient.EXPECT().DeleteUser(monitor, "test2", client) dbClient.EXPECT().DeleteUser(monitor, "test3", client) - query, _, err := AdaptFunc(monitor, users, dbClient) + getQuery, _, err := AdaptFunc(monitor, dbClient) assert.NoError(t, err) + query := getQuery(users) ensure, err := query(client, queried) err = ensure(client) assert.NoError(t, err) diff --git a/operator/zitadel/kinds/iam/zitadel/configuration/users/users.go b/operator/zitadel/kinds/iam/zitadel/configuration/users/users.go index f6cca79751..e2672059ba 100644 --- a/operator/zitadel/kinds/iam/zitadel/configuration/users/users.go +++ b/operator/zitadel/kinds/iam/zitadel/configuration/users/users.go @@ -7,7 +7,7 @@ import ( "github.com/caos/zitadel/operator/zitadel/kinds/iam/zitadel/database" ) -func createIfNecessary(monitor mntr.Monitor, user string, list []string, dbClient database.ClientInt) operator.EnsureFunc { +func createIfNecessary(monitor mntr.Monitor, user string, list []string, dbClient database.Client) operator.EnsureFunc { existing := false for _, listedUser := range list { if listedUser == user { @@ -23,7 +23,7 @@ func createIfNecessary(monitor mntr.Monitor, user string, list []string, dbClien return nil } -func deleteIfNotRequired(monitor mntr.Monitor, listedUser string, list []string, dbClient database.ClientInt) operator.EnsureFunc { +func deleteIfNotRequired(monitor mntr.Monitor, listedUser string, list []string, dbClient database.Client) operator.EnsureFunc { required := false for _, user := range list { if user == listedUser { diff --git a/operator/zitadel/kinds/iam/zitadel/configuration/users/users_test.go b/operator/zitadel/kinds/iam/zitadel/configuration/users/users_test.go index c0f9afd70e..badc762d8b 100644 --- a/operator/zitadel/kinds/iam/zitadel/configuration/users/users_test.go +++ b/operator/zitadel/kinds/iam/zitadel/configuration/users/users_test.go @@ -1,19 +1,20 @@ package users import ( + "testing" + "github.com/caos/orbos/mntr" kubernetesmock "github.com/caos/orbos/pkg/kubernetes/mock" databasemock "github.com/caos/zitadel/operator/zitadel/kinds/iam/zitadel/database/mock" "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" - "testing" ) func TestUsers_CreateIfNecessary(t *testing.T) { users := []string{} monitor := mntr.Monitor{} user := "test" - dbClient := databasemock.NewMockClientInt(gomock.NewController(t)) + dbClient := databasemock.NewMockClient(gomock.NewController(t)) k8sClient := kubernetesmock.NewMockClientInt(gomock.NewController(t)) dbClient.EXPECT().AddUser(monitor, user, k8sClient) @@ -38,7 +39,7 @@ func TestUsers_DeleteIfNotRequired(t *testing.T) { users := []string{} monitor := mntr.Monitor{} user := "test" - dbClient := databasemock.NewMockClientInt(gomock.NewController(t)) + dbClient := databasemock.NewMockClient(gomock.NewController(t)) k8sClient := kubernetesmock.NewMockClientInt(gomock.NewController(t)) dbClient.EXPECT().DeleteUser(monitor, user, k8sClient) diff --git a/operator/zitadel/kinds/iam/zitadel/database/adapt.go b/operator/zitadel/kinds/iam/zitadel/database/adapt.go index 961d785bc0..711e9d8d80 100644 --- a/operator/zitadel/kinds/iam/zitadel/database/adapt.go +++ b/operator/zitadel/kinds/iam/zitadel/database/adapt.go @@ -8,7 +8,7 @@ import ( func AdaptFunc( monitor mntr.Monitor, - dbClient ClientInt, + dbClient Client, ) ( operator.QueryFunc, error, diff --git a/operator/zitadel/kinds/iam/zitadel/database/adapt_test.go b/operator/zitadel/kinds/iam/zitadel/database/adapt_test.go index 5f9df1959c..bb5cdd71fc 100644 --- a/operator/zitadel/kinds/iam/zitadel/database/adapt_test.go +++ b/operator/zitadel/kinds/iam/zitadel/database/adapt_test.go @@ -2,16 +2,17 @@ package database import ( "errors" + "testing" + "github.com/caos/orbos/mntr" kubernetesmock "github.com/caos/orbos/pkg/kubernetes/mock" databasemock "github.com/caos/zitadel/operator/zitadel/kinds/iam/zitadel/database/mock" "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" - "testing" ) func TestDatabase_Adapt(t *testing.T) { - dbClient := databasemock.NewMockClientInt(gomock.NewController(t)) + dbClient := databasemock.NewMockClient(gomock.NewController(t)) k8sClient := kubernetesmock.NewMockClientInt(gomock.NewController(t)) host := "host" port := "port" @@ -41,7 +42,7 @@ func TestDatabase_Adapt(t *testing.T) { } func TestDatabase_Adapt2(t *testing.T) { - dbClient := databasemock.NewMockClientInt(gomock.NewController(t)) + dbClient := databasemock.NewMockClient(gomock.NewController(t)) k8sClient := kubernetesmock.NewMockClientInt(gomock.NewController(t)) host := "host2" port := "port2" @@ -71,7 +72,7 @@ func TestDatabase_Adapt2(t *testing.T) { } func TestDatabase_AdaptFailConnection(t *testing.T) { - dbClient := databasemock.NewMockClientInt(gomock.NewController(t)) + dbClient := databasemock.NewMockClient(gomock.NewController(t)) k8sClient := kubernetesmock.NewMockClientInt(gomock.NewController(t)) monitor := mntr.Monitor{} @@ -95,7 +96,7 @@ func TestDatabase_AdaptFailConnection(t *testing.T) { } func TestDatabase_AdaptFailUsers(t *testing.T) { - dbClient := databasemock.NewMockClientInt(gomock.NewController(t)) + dbClient := databasemock.NewMockClient(gomock.NewController(t)) k8sClient := kubernetesmock.NewMockClientInt(gomock.NewController(t)) host := "host" port := "port" diff --git a/operator/zitadel/kinds/iam/zitadel/database/client.go b/operator/zitadel/kinds/iam/zitadel/database/client.go index 6568b27984..3b5cad3cef 100644 --- a/operator/zitadel/kinds/iam/zitadel/database/client.go +++ b/operator/zitadel/kinds/iam/zitadel/database/client.go @@ -9,27 +9,28 @@ import ( "github.com/caos/zitadel/pkg/databases" ) -var _ ClientInt = (*Client)(nil) +var _ Client = (*GitOpsClient)(nil) +var _ Client = (*CrdClient)(nil) -type ClientInt interface { +type Client interface { GetConnectionInfo(monitor mntr.Monitor, k8sClient kubernetes.ClientInt) (string, string, error) DeleteUser(monitor mntr.Monitor, user string, k8sClient kubernetes.ClientInt) error AddUser(monitor mntr.Monitor, user string, k8sClient kubernetes.ClientInt) error ListUsers(monitor mntr.Monitor, k8sClient kubernetes.ClientInt) ([]string, error) } -type Client struct { +type GitOpsClient struct { Monitor mntr.Monitor gitClient *git.Client } -func NewClient(monitor mntr.Monitor, repoURL, repoKey string) (*Client, error) { +func NewGitOpsClient(monitor mntr.Monitor, repoURL, repoKey string) (*GitOpsClient, error) { gitClient, err := newGit(monitor, repoURL, repoKey) if err != nil { return nil, err } - return &Client{ + return &GitOpsClient{ Monitor: monitor, gitClient: gitClient, }, nil @@ -47,10 +48,27 @@ func newGit(monitor mntr.Monitor, repoURL string, repoKey string) (*git.Client, return gitClient, nil } -func (c *Client) GetConnectionInfo(monitor mntr.Monitor, k8sClient kubernetes.ClientInt) (string, string, error) { - return databases.GetConnectionInfo( +func (c *GitOpsClient) GetConnectionInfo(monitor mntr.Monitor, k8sClient kubernetes.ClientInt) (string, string, error) { + return databases.GitOpsGetConnectionInfo( monitor, k8sClient, c.gitClient, ) } + +type CrdClient struct { + Monitor mntr.Monitor +} + +func NewCrdClient(monitor mntr.Monitor) *CrdClient { + return &CrdClient{ + Monitor: monitor, + } +} + +func (c *CrdClient) GetConnectionInfo(monitor mntr.Monitor, k8sClient kubernetes.ClientInt) (string, string, error) { + return databases.CrdGetConnectionInfo( + monitor, + k8sClient, + ) +} diff --git a/operator/zitadel/kinds/iam/zitadel/database/mock/client.mock.go b/operator/zitadel/kinds/iam/zitadel/database/mock/client.mock.go index f54866378f..9bf593bec7 100644 --- a/operator/zitadel/kinds/iam/zitadel/database/mock/client.mock.go +++ b/operator/zitadel/kinds/iam/zitadel/database/mock/client.mock.go @@ -11,31 +11,31 @@ import ( reflect "reflect" ) -// MockClientInt is a mock of ClientInt interface -type MockClientInt struct { +// MockClient is a mock of Client interface +type MockClient struct { ctrl *gomock.Controller - recorder *MockClientIntMockRecorder + recorder *MockClientMockRecorder } -// MockClientIntMockRecorder is the mock recorder for MockClientInt -type MockClientIntMockRecorder struct { - mock *MockClientInt +// MockClientMockRecorder is the mock recorder for MockClient +type MockClientMockRecorder struct { + mock *MockClient } -// NewMockClientInt creates a new mock instance -func NewMockClientInt(ctrl *gomock.Controller) *MockClientInt { - mock := &MockClientInt{ctrl: ctrl} - mock.recorder = &MockClientIntMockRecorder{mock} +// NewMockClient creates a new mock instance +func NewMockClient(ctrl *gomock.Controller) *MockClient { + mock := &MockClient{ctrl: ctrl} + mock.recorder = &MockClientMockRecorder{mock} return mock } // EXPECT returns an object that allows the caller to indicate expected use -func (m *MockClientInt) EXPECT() *MockClientIntMockRecorder { +func (m *MockClient) EXPECT() *MockClientMockRecorder { return m.recorder } // GetConnectionInfo mocks base method -func (m *MockClientInt) GetConnectionInfo(monitor mntr.Monitor, k8sClient kubernetes.ClientInt) (string, string, error) { +func (m *MockClient) GetConnectionInfo(monitor mntr.Monitor, k8sClient kubernetes.ClientInt) (string, string, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetConnectionInfo", monitor, k8sClient) ret0, _ := ret[0].(string) @@ -45,13 +45,13 @@ func (m *MockClientInt) GetConnectionInfo(monitor mntr.Monitor, k8sClient kubern } // GetConnectionInfo indicates an expected call of GetConnectionInfo -func (mr *MockClientIntMockRecorder) GetConnectionInfo(monitor, k8sClient interface{}) *gomock.Call { +func (mr *MockClientMockRecorder) GetConnectionInfo(monitor, k8sClient interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetConnectionInfo", reflect.TypeOf((*MockClientInt)(nil).GetConnectionInfo), monitor, k8sClient) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetConnectionInfo", reflect.TypeOf((*MockClient)(nil).GetConnectionInfo), monitor, k8sClient) } // DeleteUser mocks base method -func (m *MockClientInt) DeleteUser(monitor mntr.Monitor, user string, k8sClient kubernetes.ClientInt) error { +func (m *MockClient) DeleteUser(monitor mntr.Monitor, user string, k8sClient kubernetes.ClientInt) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "DeleteUser", monitor, user, k8sClient) ret0, _ := ret[0].(error) @@ -59,13 +59,13 @@ func (m *MockClientInt) DeleteUser(monitor mntr.Monitor, user string, k8sClient } // DeleteUser indicates an expected call of DeleteUser -func (mr *MockClientIntMockRecorder) DeleteUser(monitor, user, k8sClient interface{}) *gomock.Call { +func (mr *MockClientMockRecorder) DeleteUser(monitor, user, k8sClient interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteUser", reflect.TypeOf((*MockClientInt)(nil).DeleteUser), monitor, user, k8sClient) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteUser", reflect.TypeOf((*MockClient)(nil).DeleteUser), monitor, user, k8sClient) } // AddUser mocks base method -func (m *MockClientInt) AddUser(monitor mntr.Monitor, user string, k8sClient kubernetes.ClientInt) error { +func (m *MockClient) AddUser(monitor mntr.Monitor, user string, k8sClient kubernetes.ClientInt) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "AddUser", monitor, user, k8sClient) ret0, _ := ret[0].(error) @@ -73,13 +73,13 @@ func (m *MockClientInt) AddUser(monitor mntr.Monitor, user string, k8sClient kub } // AddUser indicates an expected call of AddUser -func (mr *MockClientIntMockRecorder) AddUser(monitor, user, k8sClient interface{}) *gomock.Call { +func (mr *MockClientMockRecorder) AddUser(monitor, user, k8sClient interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddUser", reflect.TypeOf((*MockClientInt)(nil).AddUser), monitor, user, k8sClient) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddUser", reflect.TypeOf((*MockClient)(nil).AddUser), monitor, user, k8sClient) } // ListUsers mocks base method -func (m *MockClientInt) ListUsers(monitor mntr.Monitor, k8sClient kubernetes.ClientInt) ([]string, error) { +func (m *MockClient) ListUsers(monitor mntr.Monitor, k8sClient kubernetes.ClientInt) ([]string, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "ListUsers", monitor, k8sClient) ret0, _ := ret[0].([]string) @@ -88,7 +88,7 @@ func (m *MockClientInt) ListUsers(monitor mntr.Monitor, k8sClient kubernetes.Cli } // ListUsers indicates an expected call of ListUsers -func (mr *MockClientIntMockRecorder) ListUsers(monitor, k8sClient interface{}) *gomock.Call { +func (mr *MockClientMockRecorder) ListUsers(monitor, k8sClient interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListUsers", reflect.TypeOf((*MockClientInt)(nil).ListUsers), monitor, k8sClient) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListUsers", reflect.TypeOf((*MockClient)(nil).ListUsers), monitor, k8sClient) } diff --git a/operator/zitadel/kinds/iam/zitadel/database/user.go b/operator/zitadel/kinds/iam/zitadel/database/user.go index f736efbf39..ab1118e603 100644 --- a/operator/zitadel/kinds/iam/zitadel/database/user.go +++ b/operator/zitadel/kinds/iam/zitadel/database/user.go @@ -6,8 +6,8 @@ import ( "github.com/caos/zitadel/pkg/databases" ) -func (c *Client) DeleteUser(monitor mntr.Monitor, user string, k8sClient kubernetes.ClientInt) error { - return databases.DeleteUser( +func (c *GitOpsClient) DeleteUser(monitor mntr.Monitor, user string, k8sClient kubernetes.ClientInt) error { + return databases.GitOpsDeleteUser( monitor, user, k8sClient, @@ -15,8 +15,8 @@ func (c *Client) DeleteUser(monitor mntr.Monitor, user string, k8sClient kuberne ) } -func (c *Client) AddUser(monitor mntr.Monitor, user string, k8sClient kubernetes.ClientInt) error { - return databases.AddUser( +func (c *GitOpsClient) AddUser(monitor mntr.Monitor, user string, k8sClient kubernetes.ClientInt) error { + return databases.GitOpsAddUser( monitor, user, k8sClient, @@ -24,10 +24,33 @@ func (c *Client) AddUser(monitor mntr.Monitor, user string, k8sClient kubernetes ) } -func (c *Client) ListUsers(monitor mntr.Monitor, k8sClient kubernetes.ClientInt) ([]string, error) { - return databases.ListUsers( +func (c *GitOpsClient) ListUsers(monitor mntr.Monitor, k8sClient kubernetes.ClientInt) ([]string, error) { + return databases.GitOpsListUsers( monitor, k8sClient, c.gitClient, ) } + +func (c *CrdClient) DeleteUser(monitor mntr.Monitor, user string, k8sClient kubernetes.ClientInt) error { + return databases.CrdDeleteUser( + monitor, + user, + k8sClient, + ) +} + +func (c *CrdClient) AddUser(monitor mntr.Monitor, user string, k8sClient kubernetes.ClientInt) error { + return databases.CrdAddUser( + monitor, + user, + k8sClient, + ) +} + +func (c *CrdClient) ListUsers(monitor mntr.Monitor, k8sClient kubernetes.ClientInt) ([]string, error) { + return databases.CrdListUsers( + monitor, + k8sClient, + ) +} diff --git a/operator/zitadel/kinds/iam/zitadel/deployment/adapt.go b/operator/zitadel/kinds/iam/zitadel/deployment/adapt.go index 3dfa1a8c75..deca8e4ee3 100644 --- a/operator/zitadel/kinds/iam/zitadel/deployment/adapt.go +++ b/operator/zitadel/kinds/iam/zitadel/deployment/adapt.go @@ -41,16 +41,17 @@ func AdaptFunc( consoleCMName string, secretVarsName string, secretPasswordsName string, - users []string, nodeSelector map[string]string, tolerations []corev1.Toleration, resources *k8s.Resources, migrationDone operator.EnsureFunc, configurationDone operator.EnsureFunc, setupDone operator.EnsureFunc, - getConfigurationHashes func(k8sClient kubernetes.ClientInt, queried map[string]interface{}) map[string]string, ) ( - operator.QueryFunc, + func( + necessaryUsers map[string]string, + getConfigurationHashes func(k8sClient kubernetes.ClientInt, queried map[string]interface{}, necessaryUsers map[string]string) (map[string]string, error), + ) operator.QueryFunc, operator.DestroyFunc, error, ) { @@ -64,52 +65,65 @@ func AdaptFunc( operator.ResourceDestroyToZitadelDestroy(destroy), } - return func(k8sClient kubernetes.ClientInt, queried map[string]interface{}) (operator.EnsureFunc, error) { - - deploymentDef := deploymentDef( - nameLabels, - namespace, - replicaCount, - podSelector, - nodeSelector, - tolerations, - affinity, - users, - version, - resources, - cmName, - certPath, - secretName, - secretPath, - consoleCMName, - secretVarsName, - secretPasswordsName, - ) - - hashes := getConfigurationHashes(k8sClient, queried) - if hashes != nil && len(hashes) != 0 { - for k, v := range hashes { - deploymentDef.Annotations[k] = v - deploymentDef.Spec.Template.Annotations[k] = v + return func( + necessaryUsers map[string]string, + getConfigurationHashes func(k8sClient kubernetes.ClientInt, queried map[string]interface{}, necessaryUsers map[string]string) (map[string]string, error), + ) operator.QueryFunc { + return func(k8sClient kubernetes.ClientInt, queried map[string]interface{}) (operator.EnsureFunc, error) { + users := make([]string, 0) + for user := range necessaryUsers { + users = append(users, user) } - } - query, err := deployment.AdaptFuncToEnsure(deploymentDef, force) - if err != nil { - return nil, err - } + deploymentDef := deploymentDef( + nameLabels, + namespace, + replicaCount, + podSelector, + nodeSelector, + tolerations, + affinity, + users, + version, + resources, + cmName, + certPath, + secretName, + secretPath, + consoleCMName, + secretVarsName, + secretPasswordsName, + ) - queriers := []operator.QueryFunc{ - operator.EnsureFuncToQueryFunc(migrationDone), - operator.EnsureFuncToQueryFunc(configurationDone), - operator.EnsureFuncToQueryFunc(setupDone), - operator.ResourceQueryToZitadelQuery(query), - } + hashes, err := getConfigurationHashes(k8sClient, queried, necessaryUsers) + if err != nil { + return nil, err + } + if hashes != nil && len(hashes) != 0 { + for k, v := range hashes { + deploymentDef.Annotations[k] = v + deploymentDef.Spec.Template.Annotations[k] = v + } + } - return operator.QueriersToEnsureFunc(internalMonitor, false, queriers, k8sClient, queried) + query, err := deployment.AdaptFuncToEnsure(deploymentDef, force) + if err != nil { + return nil, err + } + + queriers := []operator.QueryFunc{ + operator.EnsureFuncToQueryFunc(migrationDone), + operator.EnsureFuncToQueryFunc(configurationDone), + operator.EnsureFuncToQueryFunc(setupDone), + operator.ResourceQueryToZitadelQuery(query), + } + + return operator.QueriersToEnsureFunc(internalMonitor, false, queriers, k8sClient, queried) + } }, operator.DestroyersToDestroyFunc(internalMonitor, destroyers), nil + } func deploymentDef(nameLabels *labels.Name, namespace string, replicaCount int, podSelector *labels.Selector, nodeSelector map[string]string, tolerations []corev1.Toleration, affinity *k8s.Affinity, users []string, version *string, resources *k8s.Resources, cmName string, certPath string, secretName string, secretPath string, consoleCMName string, secretVarsName string, secretPasswordsName string) *appsv1.Deployment { diff --git a/operator/zitadel/kinds/iam/zitadel/deployment/adapt_test.go b/operator/zitadel/kinds/iam/zitadel/deployment/adapt_test.go index 9be75176d4..24e3b164ef 100644 --- a/operator/zitadel/kinds/iam/zitadel/deployment/adapt_test.go +++ b/operator/zitadel/kinds/iam/zitadel/deployment/adapt_test.go @@ -32,7 +32,11 @@ func TestDeployment_Adapt(t *testing.T) { secretName := "testSecret" consoleCMName := "testConsoleCM" cmName := "testCM" - users := []string{"test"} + usersMap := map[string]string{"test": "test"} + users := []string{} + for _, user := range usersMap { + users = append(users, user) + } annotations := map[string]string{"testHash": "test"} k8sClient := kubernetesmock.NewMockClientInt(gomock.NewController(t)) @@ -115,8 +119,8 @@ func TestDeployment_Adapt(t *testing.T) { } k8sClient.EXPECT().ApplyDeployment(deploymentDef, false).Times(1) - getConfigurationHashes := func(k8sClient kubernetes.ClientInt, queried map[string]interface{}) map[string]string { - return map[string]string{"testHash": "test"} + getConfigurationHashes := func(k8sClient kubernetes.ClientInt, queried map[string]interface{}, necessaryUsers map[string]string) (map[string]string, error) { + return map[string]string{"testHash": "test"}, nil } migrationDone := func(k8sClient kubernetes.ClientInt) error { return nil @@ -128,7 +132,7 @@ func TestDeployment_Adapt(t *testing.T) { return nil } - query, _, err := AdaptFunc( + getQuery, _, err := AdaptFunc( monitor, mocklabels.Name, mocklabels.ClosedNameSelector, @@ -144,17 +148,16 @@ func TestDeployment_Adapt(t *testing.T) { consoleCMName, secretVarsName, secretPasswordsName, - users, nodeSelector, nil, resources, migrationDone, configurationDone, setupDone, - getConfigurationHashes, ) assert.NoError(t, err) queried := map[string]interface{}{} + query := getQuery(usersMap, getConfigurationHashes) ensure, err := query(k8sClient, queried) assert.NoError(t, err) assert.NoError(t, ensure(k8sClient)) diff --git a/operator/zitadel/kinds/iam/zitadel/deployment/container.go b/operator/zitadel/kinds/iam/zitadel/deployment/container.go index 97aa8d8ede..ee60a15cbc 100644 --- a/operator/zitadel/kinds/iam/zitadel/deployment/container.go +++ b/operator/zitadel/kinds/iam/zitadel/deployment/container.go @@ -1,6 +1,7 @@ package deployment import ( + "sort" "strings" "github.com/caos/orbos/pkg/kubernetes/k8s" @@ -63,6 +64,7 @@ func GetContainer( }}, } + sort.Strings(users) for _, user := range users { envVars = append(envVars, corev1.EnvVar{ Name: "CR_" + strings.ToUpper(user) + "_PASSWORD", @@ -92,7 +94,7 @@ func GetContainer( }, Name: containerName, Image: zitadelImage + ":" + version, - ImagePullPolicy: "IfNotPresent", + ImagePullPolicy: corev1.PullIfNotPresent, Ports: []corev1.ContainerPort{ {Name: "grpc", ContainerPort: 50001}, {Name: "http", ContainerPort: 50002}, @@ -127,5 +129,7 @@ func GetContainer( PeriodSeconds: 5, FailureThreshold: 2, }, + TerminationMessagePolicy: "File", + TerminationMessagePath: "/dev/termination-log", } } diff --git a/operator/zitadel/kinds/iam/zitadel/deployment/container_test.go b/operator/zitadel/kinds/iam/zitadel/deployment/container_test.go index 37e7e20013..93860cf868 100644 --- a/operator/zitadel/kinds/iam/zitadel/deployment/container_test.go +++ b/operator/zitadel/kinds/iam/zitadel/deployment/container_test.go @@ -95,7 +95,7 @@ func TestDeployment_GetContainer(t *testing.T) { }, Name: containerName, Image: zitadelImage + ":" + version, - ImagePullPolicy: "IfNotPresent", + ImagePullPolicy: corev1.PullIfNotPresent, Ports: []corev1.ContainerPort{ {Name: "grpc", ContainerPort: 50001}, {Name: "http", ContainerPort: 50002}, @@ -130,6 +130,8 @@ func TestDeployment_GetContainer(t *testing.T) { PeriodSeconds: 5, FailureThreshold: 2, }, + TerminationMessagePolicy: "File", + TerminationMessagePath: "/dev/termination-log", } container := GetContainer( diff --git a/operator/zitadel/kinds/iam/zitadel/deployment/initcontainer.go b/operator/zitadel/kinds/iam/zitadel/deployment/initcontainer.go index 818a58fd17..d6de06f701 100644 --- a/operator/zitadel/kinds/iam/zitadel/deployment/initcontainer.go +++ b/operator/zitadel/kinds/iam/zitadel/deployment/initcontainer.go @@ -2,6 +2,7 @@ package deployment import ( corev1 "k8s.io/api/core/v1" + "sort" "strconv" "strings" ) @@ -24,6 +25,8 @@ func GetInitContainer( } copySecrets := append([]string{}, "cp "+certMountPath+"/client_root/ca.crt "+certTempMountPath+"/ca.crt") + + sort.Strings(users) for _, user := range users { userReplaced := strings.ReplaceAll(user, "_", "-") internalName := "client-" + userReplaced @@ -43,10 +46,13 @@ func GetInitContainer( ) return corev1.Container{ - Name: "fix-permissions", - Image: "alpine:3.11", - Command: []string{"/bin/sh", "-c"}, - Args: []string{strings.Join(initCommands, " && ")}, - VolumeMounts: initVolumeMounts, + Name: "fix-permissions", + Image: "alpine:3.11", + Command: []string{"/bin/sh", "-c"}, + Args: []string{strings.Join(initCommands, " && ")}, + VolumeMounts: initVolumeMounts, + TerminationMessagePolicy: "File", + TerminationMessagePath: "/dev/termination-log", + ImagePullPolicy: corev1.PullIfNotPresent, } } diff --git a/operator/zitadel/kinds/iam/zitadel/deployment/initcontainer_test.go b/operator/zitadel/kinds/iam/zitadel/deployment/initcontainer_test.go index 95581703b2..b913cd8372 100644 --- a/operator/zitadel/kinds/iam/zitadel/deployment/initcontainer_test.go +++ b/operator/zitadel/kinds/iam/zitadel/deployment/initcontainer_test.go @@ -25,11 +25,14 @@ func TestDeployment_GetInitContainer(t *testing.T) { } equals := corev1.Container{ - Name: "fix-permissions", - Image: "alpine:3.11", - Command: []string{"/bin/sh", "-c"}, - Args: []string{strings.Join(initCommands, " && ")}, - VolumeMounts: initVolumeMounts, + Name: "fix-permissions", + Image: "alpine:3.11", + Command: []string{"/bin/sh", "-c"}, + Args: []string{strings.Join(initCommands, " && ")}, + VolumeMounts: initVolumeMounts, + ImagePullPolicy: corev1.PullIfNotPresent, + TerminationMessagePolicy: "File", + TerminationMessagePath: "/dev/termination-log", } init := GetInitContainer(rootSecret, dbSecrets, users, RunAsUser) @@ -55,11 +58,14 @@ func TestDeployment_GetInitContainer1(t *testing.T) { } equals := corev1.Container{ - Name: "fix-permissions", - Image: "alpine:3.11", - Command: []string{"/bin/sh", "-c"}, - Args: []string{strings.Join(initCommands, " && ")}, - VolumeMounts: initVolumeMounts, + Name: "fix-permissions", + Image: "alpine:3.11", + Command: []string{"/bin/sh", "-c"}, + Args: []string{strings.Join(initCommands, " && ")}, + VolumeMounts: initVolumeMounts, + TerminationMessagePolicy: "File", + TerminationMessagePath: "/dev/termination-log", + ImagePullPolicy: corev1.PullIfNotPresent, } init := GetInitContainer(rootSecret, dbSecrets, users, RunAsUser) @@ -88,11 +94,14 @@ func TestDeployment_GetInitContainer2(t *testing.T) { } equals := corev1.Container{ - Name: "fix-permissions", - Image: "alpine:3.11", - Command: []string{"/bin/sh", "-c"}, - Args: []string{strings.Join(initCommands, " && ")}, - VolumeMounts: initVolumeMounts, + Name: "fix-permissions", + Image: "alpine:3.11", + Command: []string{"/bin/sh", "-c"}, + Args: []string{strings.Join(initCommands, " && ")}, + VolumeMounts: initVolumeMounts, + ImagePullPolicy: corev1.PullIfNotPresent, + TerminationMessagePolicy: "File", + TerminationMessagePath: "/dev/termination-log", } init := GetInitContainer(rootSecret, dbSecrets, users, RunAsUser) diff --git a/operator/zitadel/kinds/iam/zitadel/deployment/volumes.go b/operator/zitadel/kinds/iam/zitadel/deployment/volumes.go index a567c67a58..716bac43de 100644 --- a/operator/zitadel/kinds/iam/zitadel/deployment/volumes.go +++ b/operator/zitadel/kinds/iam/zitadel/deployment/volumes.go @@ -3,6 +3,7 @@ package deployment import ( "github.com/caos/zitadel/operator/helpers" corev1 "k8s.io/api/core/v1" + "sort" "strings" ) @@ -16,7 +17,8 @@ func GetVolumes( Name: secretName, VolumeSource: corev1.VolumeSource{ Secret: &corev1.SecretVolumeSource{ - SecretName: secretName, + SecretName: secretName, + DefaultMode: helpers.PointerInt32(420), }, }, }, { @@ -31,7 +33,8 @@ func GetVolumes( Name: secretPasswordsName, VolumeSource: corev1.VolumeSource{ Secret: &corev1.SecretVolumeSource{ - SecretName: secretPasswordsName, + SecretName: secretPasswordsName, + DefaultMode: helpers.PointerInt32(384), }, }, }, { @@ -39,6 +42,7 @@ func GetVolumes( VolumeSource: corev1.VolumeSource{ ConfigMap: &corev1.ConfigMapVolumeSource{ LocalObjectReference: corev1.LocalObjectReference{Name: consoleCMName}, + DefaultMode: helpers.PointerInt32(420), }, }, }, { @@ -56,6 +60,7 @@ func userVolumes( ) []corev1.Volume { volumes := make([]corev1.Volume, 0) + sort.Strings(users) for _, user := range users { userReplaced := strings.ReplaceAll(user, "_", "-") internalName := "client-" + userReplaced diff --git a/operator/zitadel/kinds/iam/zitadel/deployment/volumes_test.go b/operator/zitadel/kinds/iam/zitadel/deployment/volumes_test.go index b189ad2ff3..f636e38140 100644 --- a/operator/zitadel/kinds/iam/zitadel/deployment/volumes_test.go +++ b/operator/zitadel/kinds/iam/zitadel/deployment/volumes_test.go @@ -17,7 +17,8 @@ func TestDeployment_Volumes(t *testing.T) { Name: secretName, VolumeSource: corev1.VolumeSource{ Secret: &corev1.SecretVolumeSource{ - SecretName: secretName, + SecretName: secretName, + DefaultMode: helpers.PointerInt32(420), }, }, }, { @@ -32,7 +33,8 @@ func TestDeployment_Volumes(t *testing.T) { Name: secretPasswordsName, VolumeSource: corev1.VolumeSource{ Secret: &corev1.SecretVolumeSource{ - SecretName: secretPasswordsName, + SecretName: secretPasswordsName, + DefaultMode: helpers.PointerInt32(384), }, }, }, { @@ -40,6 +42,7 @@ func TestDeployment_Volumes(t *testing.T) { VolumeSource: corev1.VolumeSource{ ConfigMap: &corev1.ConfigMapVolumeSource{ LocalObjectReference: corev1.LocalObjectReference{Name: consoleCMName}, + DefaultMode: helpers.PointerInt32(420), }, }, }, { diff --git a/operator/zitadel/kinds/iam/zitadel/migration/adapt.go b/operator/zitadel/kinds/iam/zitadel/migration/adapt.go index fd1a81dd32..d8ce50b23e 100644 --- a/operator/zitadel/kinds/iam/zitadel/migration/adapt.go +++ b/operator/zitadel/kinds/iam/zitadel/migration/adapt.go @@ -4,14 +4,13 @@ import ( "crypto/sha512" "encoding/base64" "encoding/json" + "github.com/pkg/errors" + "github.com/rakyll/statik/fs" "os" "path/filepath" "regexp" "sort" - "github.com/pkg/errors" - "github.com/rakyll/statik/fs" - "github.com/caos/orbos/mntr" "github.com/caos/orbos/pkg/kubernetes" "github.com/caos/orbos/pkg/kubernetes/resources/configmap" @@ -102,10 +101,9 @@ func AdaptFunc( }, }, Spec: corev1.PodSpec{ - NodeSelector: nodeselector, - Tolerations: tolerations, - SecurityContext: &corev1.PodSecurityContext{}, - InitContainers: getPreContainer(dbHost, dbPort, migrationUser, secretPasswordName), + NodeSelector: nodeselector, + Tolerations: tolerations, + InitContainers: getPreContainer(dbHost, dbPort, migrationUser, secretPasswordName), Containers: []corev1.Container{ getMigrationContainer(dbHost, dbPort, migrationUser, secretPasswordName, users), }, diff --git a/operator/zitadel/kinds/iam/zitadel/migration/adapt_test.go b/operator/zitadel/kinds/iam/zitadel/migration/adapt_test.go index 11b22df4cf..fbdadaa1ad 100644 --- a/operator/zitadel/kinds/iam/zitadel/migration/adapt_test.go +++ b/operator/zitadel/kinds/iam/zitadel/migration/adapt_test.go @@ -97,10 +97,9 @@ func TestMigration_AdaptFunc(t *testing.T) { }, }, Spec: corev1.PodSpec{ - NodeSelector: nodeselector, - Tolerations: tolerations, - SecurityContext: &corev1.PodSecurityContext{}, - InitContainers: getPreContainer(dbHost, dbPort, migrationUser, secretPasswordName), + NodeSelector: nodeselector, + Tolerations: tolerations, + InitContainers: getPreContainer(dbHost, dbPort, migrationUser, secretPasswordName), Containers: []corev1.Container{ getMigrationContainer(dbHost, dbPort, migrationUser, secretPasswordName, users), }, diff --git a/operator/zitadel/kinds/iam/zitadel/secrets.go b/operator/zitadel/kinds/iam/zitadel/secrets.go index 5f0cc2a457..8796febc22 100644 --- a/operator/zitadel/kinds/iam/zitadel/secrets.go +++ b/operator/zitadel/kinds/iam/zitadel/secrets.go @@ -2,48 +2,104 @@ package zitadel import ( "github.com/caos/orbos/pkg/secret" + "github.com/caos/zitadel/operator/zitadel/kinds/iam/zitadel/configuration" ) -func getSecretsMap(desiredKind *DesiredV0) map[string]*secret.Secret { - secrets := map[string]*secret.Secret{} +func getSecretsMap(desiredKind *DesiredV0) ( + map[string]*secret.Secret, + map[string]*secret.Existing, +) { - if desiredKind.Spec != nil && desiredKind.Spec.Configuration != nil { - conf := desiredKind.Spec.Configuration - if conf.Tracing != nil { - if conf.Tracing.ServiceAccountJSON == nil { - conf.Tracing.ServiceAccountJSON = &secret.Secret{} - } - secrets["tracingserviceaccountjson"] = conf.Tracing.ServiceAccountJSON - } + var ( + secrets = map[string]*secret.Secret{} + existing = map[string]*secret.Existing{} + ) - if conf.Secrets != nil { - if conf.Secrets.Keys == nil { - conf.Secrets.Keys = &secret.Secret{} - } - secrets["keys"] = conf.Secrets.Keys - } - - if conf.Notifications != nil { - if conf.Notifications.GoogleChatURL == nil { - conf.Notifications.GoogleChatURL = &secret.Secret{} - } - secrets["googlechaturl"] = conf.Notifications.GoogleChatURL - - if conf.Notifications.Twilio.SID == nil { - conf.Notifications.Twilio.SID = &secret.Secret{} - } - secrets["twiliosid"] = conf.Notifications.Twilio.SID - - if conf.Notifications.Twilio.AuthToken == nil { - conf.Notifications.Twilio.AuthToken = &secret.Secret{} - } - secrets["twilioauthtoken"] = conf.Notifications.Twilio.AuthToken - - if conf.Notifications.Email.AppKey == nil { - conf.Notifications.Email.AppKey = &secret.Secret{} - } - secrets["emailappkey"] = conf.Notifications.Email.AppKey - } + if desiredKind.Spec == nil { + desiredKind.Spec = &Spec{} } - return secrets + + if desiredKind.Spec.Configuration == nil { + desiredKind.Spec.Configuration = &configuration.Configuration{} + } + + conf := desiredKind.Spec.Configuration + + if conf.Tracing == nil { + conf.Tracing = &configuration.Tracing{} + } + if conf.Tracing.ServiceAccountJSON == nil { + conf.Tracing.ServiceAccountJSON = &secret.Secret{} + } + if conf.Tracing.ExistingServiceAccountJSON == nil { + conf.Tracing.ExistingServiceAccountJSON = &secret.Existing{} + } + sakey := "tracingserviceaccountjson" + secrets[sakey] = conf.Tracing.ServiceAccountJSON + existing[sakey] = conf.Tracing.ExistingServiceAccountJSON + + if conf.Secrets == nil { + conf.Secrets = &configuration.Secrets{} + } + + if conf.Secrets.Keys == nil { + conf.Secrets.Keys = &secret.Secret{} + } + if conf.Secrets.ExistingKeys == nil { + conf.Secrets.ExistingKeys = &secret.Existing{} + } + keysKey := "keys" + secrets[keysKey] = conf.Secrets.Keys + existing[keysKey] = conf.Secrets.ExistingKeys + + if conf.Notifications == nil { + conf.Notifications = &configuration.Notifications{} + } + + if conf.Notifications.GoogleChatURL == nil { + conf.Notifications.GoogleChatURL = &secret.Secret{} + } + if conf.Notifications.ExistingGoogleChatURL == nil { + conf.Notifications.ExistingGoogleChatURL = &secret.Existing{} + } + gchatkey := "googlechaturl" + secrets[gchatkey] = conf.Notifications.GoogleChatURL + existing[gchatkey] = conf.Notifications.ExistingGoogleChatURL + + if conf.Notifications.Twilio == nil { + conf.Notifications.Twilio = &configuration.Twilio{} + } + if conf.Notifications.Twilio.SID == nil { + conf.Notifications.Twilio.SID = &secret.Secret{} + } + if conf.Notifications.Twilio.ExistingSID == nil { + conf.Notifications.Twilio.ExistingSID = &secret.Existing{} + } + twilKey := "twiliosid" + secrets[twilKey] = conf.Notifications.Twilio.SID + existing[twilKey] = conf.Notifications.Twilio.ExistingSID + + if conf.Notifications.Twilio.AuthToken == nil { + conf.Notifications.Twilio.AuthToken = &secret.Secret{} + } + if conf.Notifications.Twilio.ExistingAuthToken == nil { + conf.Notifications.Twilio.ExistingAuthToken = &secret.Existing{} + } + twilOAuthKey := "twilioauthtoken" + secrets[twilOAuthKey] = conf.Notifications.Twilio.AuthToken + existing[twilOAuthKey] = conf.Notifications.Twilio.ExistingAuthToken + + if conf.Notifications.Email == nil { + conf.Notifications.Email = &configuration.Email{} + } + if conf.Notifications.Email.AppKey == nil { + conf.Notifications.Email.AppKey = &secret.Secret{} + } + if conf.Notifications.Email.ExistingAppKey == nil { + conf.Notifications.Email.ExistingAppKey = &secret.Existing{} + } + mailKey := "emailappkey" + secrets[mailKey] = conf.Notifications.Email.AppKey + existing[mailKey] = conf.Notifications.Email.ExistingAppKey + return secrets, existing } diff --git a/operator/zitadel/kinds/iam/zitadel/services/adapt_test.go b/operator/zitadel/kinds/iam/zitadel/services/adapt_test.go index da51583962..4cf2f225d9 100644 --- a/operator/zitadel/kinds/iam/zitadel/services/adapt_test.go +++ b/operator/zitadel/kinds/iam/zitadel/services/adapt_test.go @@ -20,13 +20,13 @@ func GetExpectedService( zitadelPodSelector *labels.Selector, grpcPortName string, grpcServiceName *labels.Name, - grpcPort uint16, + grpcPort int, httpPortName string, httpServiceName *labels.Name, - httpPort uint16, + httpPort int, uiPortName string, uiServiceName *labels.Name, - uiPort uint16, + uiPort int, ) []*corev1.Service { grpcPorts := []corev1.ServicePort{{ @@ -123,11 +123,13 @@ func TestServices_AdaptEnsure1(t *testing.T) { namespace := "test" grpcPortName := "grpc" grpcServiceName := "grpc" + grpcPort := 1 httpPortName := "http" httpServiceName := "http" + httpPort := 2 uiPortName := "ui" uiServiceName := "ui" - var grpcPort, httpPort, uiPort uint16 = 1, 2, 3 + uiPort := 3 componentLabels, podSelectorLabels, nameLabels := serviceLabels(grpcServiceName, httpServiceName, uiServiceName) @@ -153,11 +155,11 @@ func TestServices_AdaptEnsure1(t *testing.T) { podSelectorLabels, namespace, grpcServiceName, - grpcPort, + uint16(grpcPort), httpServiceName, - httpPort, + uint16(httpPort), uiServiceName, - uiPort, + uint16(uiPort), ) assert.NilError(t, err) @@ -172,11 +174,13 @@ func TestServices_AdaptEnsure2(t *testing.T) { namespace := "test0" grpcPortName := "grpc" grpcServiceName := "grpc1" + grpcPort := 11 httpPortName := "http" httpServiceName := "http2" + httpPort := 22 uiPortName := "ui" uiServiceName := "ui3" - var grpcPort, httpPort, uiPort uint16 = 11, 22, 33 + uiPort := 33 componentLabels, podSelectorLabels, nameLabels := serviceLabels(grpcServiceName, httpServiceName, uiServiceName) @@ -203,11 +207,11 @@ func TestServices_AdaptEnsure2(t *testing.T) { podSelectorLabels, namespace, grpcServiceName, - grpcPort, + uint16(grpcPort), httpServiceName, - httpPort, + uint16(httpPort), uiServiceName, - uiPort) + uint16(uiPort)) assert.NilError(t, err) ensure, err := query(client, nil) @@ -221,11 +225,13 @@ func TestServices_AdaptEnsure3(t *testing.T) { namespace := "test00" grpcPortName := "grpc" grpcServiceName := "grpc11" + grpcPort := 111 httpPortName := "http" httpServiceName := "http22" + httpPort := 222 uiPortName := "ui" uiServiceName := "ui33" - var grpcPort, httpPort, uiPort uint16 = 111, 222, 333 + uiPort := 333 componentLabels, podSelectorLabels, nameLabels := serviceLabels(grpcServiceName, httpServiceName, uiServiceName) @@ -252,11 +258,11 @@ func TestServices_AdaptEnsure3(t *testing.T) { podSelectorLabels, namespace, grpcServiceName, - grpcPort, + uint16(grpcPort), httpServiceName, - httpPort, + uint16(httpPort), uiServiceName, - uiPort) + uint16(uiPort)) assert.NilError(t, err) ensure, err := query(client, nil) @@ -270,11 +276,13 @@ func TestServices_AdaptDestroy1(t *testing.T) { namespace := "test" grpcPortName := "grpc" grpcServiceName := "grpc" + grpcPort := 1 httpPortName := "http" httpServiceName := "http" + httpPort := 2 uiPortName := "ui" uiServiceName := "ui" - var grpcPort, httpPort, uiPort uint16 = 1, 2, 3 + uiPort := 3 componentLabels, podSelectorLabels, nameLabels := serviceLabels(grpcServiceName, httpServiceName, uiServiceName) @@ -301,11 +309,11 @@ func TestServices_AdaptDestroy1(t *testing.T) { podSelectorLabels, namespace, grpcServiceName, - grpcPort, + uint16(grpcPort), httpServiceName, - httpPort, + uint16(httpPort), uiServiceName, - uiPort) + uint16(uiPort)) assert.NilError(t, err) assert.NilError(t, destroy(client)) @@ -317,11 +325,13 @@ func TestServices_AdaptDestroy2(t *testing.T) { namespace := "test0" grpcPortName := "grpc" grpcServiceName := "grpc1" + grpcPort := 11 httpPortName := "http" httpServiceName := "http2" + httpPort := 22 uiPortName := "ui" uiServiceName := "ui3" - var grpcPort, httpPort, uiPort uint16 = 11, 22, 33 + uiPort := 33 componentLabels, podSelectorLabels, nameLabels := serviceLabels(grpcServiceName, httpServiceName, uiServiceName) @@ -348,11 +358,11 @@ func TestServices_AdaptDestroy2(t *testing.T) { podSelectorLabels, namespace, grpcServiceName, - grpcPort, + uint16(grpcPort), httpServiceName, - httpPort, + uint16(httpPort), uiServiceName, - uiPort) + uint16(uiPort)) assert.NilError(t, err) assert.NilError(t, destroy(client)) @@ -364,11 +374,13 @@ func TestServices_AdaptDestroy3(t *testing.T) { namespace := "test00" grpcPortName := "grpc" grpcServiceName := "grpc11" + grpcPort := 111 httpPortName := "http" httpServiceName := "http22" + httpPort := 222 uiPortName := "ui" uiServiceName := "ui33" - var grpcPort, httpPort, uiPort uint16 = 111, 222, 333 + uiPort := 333 componentLabels, podSelectorLabels, nameLabels := serviceLabels(grpcServiceName, httpServiceName, uiServiceName) @@ -395,11 +407,11 @@ func TestServices_AdaptDestroy3(t *testing.T) { podSelectorLabels, namespace, grpcServiceName, - grpcPort, + uint16(grpcPort), httpServiceName, - httpPort, + uint16(httpPort), uiServiceName, - uiPort) + uint16(uiPort)) assert.NilError(t, err) assert.NilError(t, destroy(client)) diff --git a/operator/zitadel/kinds/iam/zitadel/services/clientid.go b/operator/zitadel/kinds/iam/zitadel/services/clientid.go index b7fce9f33f..c64057a1bf 100644 --- a/operator/zitadel/kinds/iam/zitadel/services/clientid.go +++ b/operator/zitadel/kinds/iam/zitadel/services/clientid.go @@ -10,10 +10,10 @@ import ( func GetClientIDFunc( namespace string, httpServiceName string, - httpPort uint16, + httpPort int, ) func() string { return func() string { - resp, err := http.Get("http://" + httpServiceName + "." + namespace + ":" + strconv.Itoa(int(httpPort)) + "/clientID") + resp, err := http.Get("http://" + httpServiceName + "." + namespace + ":" + strconv.Itoa(httpPort) + "/clientID") if err != nil || resp.StatusCode >= 400 { return "" } diff --git a/operator/zitadel/kinds/iam/zitadel/setup/adapt.go b/operator/zitadel/kinds/iam/zitadel/setup/adapt.go index d72b7760a0..ae0f581d17 100644 --- a/operator/zitadel/kinds/iam/zitadel/setup/adapt.go +++ b/operator/zitadel/kinds/iam/zitadel/setup/adapt.go @@ -1,8 +1,6 @@ package setup import ( - "time" - "github.com/caos/orbos/mntr" "github.com/caos/orbos/pkg/kubernetes" "github.com/caos/orbos/pkg/kubernetes/k8s" @@ -21,7 +19,6 @@ const ( containerName = "zitadel" rootSecret = "client-root" dbSecrets = "db-secrets" - timeout = 300 * time.Second ) func AdaptFunc( @@ -40,12 +37,11 @@ func AdaptFunc( consoleCMName string, secretVarsName string, secretPasswordsName string, - users []string, - migrationDone operator.EnsureFunc, - configurationDone operator.EnsureFunc, - getConfigurationHashes func(k8sClient kubernetes.ClientInt, queried map[string]interface{}) map[string]string, ) ( - operator.QueryFunc, + func( + necessaryUsers map[string]string, + getConfigurationHashes func(k8sClient kubernetes.ClientInt, queried map[string]interface{}, necessaryUsers map[string]string) (map[string]string, error), + ) operator.QueryFunc, operator.DestroyFunc, error, ) { @@ -63,49 +59,60 @@ func AdaptFunc( operator.ResourceDestroyToZitadelDestroy(destroyJ), } - return func(k8sClient kubernetes.ClientInt, queried map[string]interface{}) (operator.EnsureFunc, error) { - - jobDef := jobDef( - nameLabels, - users, - version, - resources, - cmName, - certPath, - secretName, - secretPath, - consoleCMName, - secretVarsName, - secretPasswordsName, - namespace, - componentLabels, - nodeselector, - tolerations, - ) - - hashes := getConfigurationHashes(k8sClient, queried) - if hashes != nil && len(hashes) != 0 { - for k, v := range hashes { - jobDef.Annotations[k] = v - jobDef.Spec.Template.Annotations[k] = v + return func( + necessaryUsers map[string]string, + getConfigurationHashes func(k8sClient kubernetes.ClientInt, queried map[string]interface{}, necessaryUsers map[string]string) (map[string]string, error), + ) operator.QueryFunc { + return func(k8sClient kubernetes.ClientInt, queried map[string]interface{}) (operator.EnsureFunc, error) { + users := make([]string, 0) + for user := range necessaryUsers { + users = append(users, user) } - } - query, err := job.AdaptFuncToEnsure(jobDef) - if err != nil { - return nil, err - } + jobDef := jobDef( + nameLabels, + users, + version, + resources, + cmName, + certPath, + secretName, + secretPath, + consoleCMName, + secretVarsName, + secretPasswordsName, + namespace, + componentLabels, + nodeselector, + tolerations, + ) - queriers := []operator.QueryFunc{ - operator.EnsureFuncToQueryFunc(migrationDone), - operator.EnsureFuncToQueryFunc(configurationDone), - operator.ResourceQueryToZitadelQuery(query), - } + hashes, err := getConfigurationHashes(k8sClient, queried, necessaryUsers) + if err != nil { + return nil, err + } + if hashes != nil && len(hashes) != 0 { + for k, v := range hashes { + jobDef.Annotations[k] = v + jobDef.Spec.Template.Annotations[k] = v + } + } - return operator.QueriersToEnsureFunc(internalMonitor, false, queriers, k8sClient, queried) + query, err := job.AdaptFuncToEnsure(jobDef) + if err != nil { + return nil, err + } + + queriers := []operator.QueryFunc{ + operator.ResourceQueryToZitadelQuery(query), + } + + return operator.QueriersToEnsureFunc(internalMonitor, false, queriers, k8sClient, queried) + } }, operator.DestroyersToDestroyFunc(internalMonitor, destroyers), nil + } func jobDef(name *labels.Name, users []string, version *string, resources *k8s.Resources, cmName string, certPath string, secretName string, secretPath string, consoleCMName string, secretVarsName string, secretPasswordsName string, namespace string, componentLabels *labels.Component, nodeselector map[string]string, tolerations []corev1.Toleration) *batchv1.Job { @@ -152,11 +159,10 @@ func jobDef(name *labels.Name, users []string, version *string, resources *k8s.R Annotations: map[string]string{}, }, Spec: corev1.PodSpec{ - NodeSelector: nodeselector, - Tolerations: tolerations, - InitContainers: initContainers, - Containers: containers, - SecurityContext: &corev1.PodSecurityContext{}, + NodeSelector: nodeselector, + Tolerations: tolerations, + InitContainers: initContainers, + Containers: containers, RestartPolicy: "Never", DNSPolicy: "ClusterFirst", diff --git a/operator/zitadel/kinds/iam/zitadel/setup/adapt_test.go b/operator/zitadel/kinds/iam/zitadel/setup/adapt_test.go index faec7f4ef4..6e13654c8e 100644 --- a/operator/zitadel/kinds/iam/zitadel/setup/adapt_test.go +++ b/operator/zitadel/kinds/iam/zitadel/setup/adapt_test.go @@ -27,7 +27,11 @@ func TestSetup_AdaptFunc(t *testing.T) { client := kubernetesmock.NewMockClientInt(gomock.NewController(t)) namespace := "test" reason := "test" - users := []string{"test"} + usersMap := map[string]string{"test": "test"} + users := []string{} + for _, user := range usersMap { + users = append(users, user) + } nodeselector := map[string]string{"test": "test"} tolerations := []corev1.Toleration{} dbHost := "test" @@ -91,11 +95,10 @@ func TestSetup_AdaptFunc(t *testing.T) { Annotations: annotations, }, Spec: corev1.PodSpec{ - NodeSelector: nodeselector, - Tolerations: tolerations, - InitContainers: initContainers, - Containers: containers, - SecurityContext: &corev1.PodSecurityContext{}, + NodeSelector: nodeselector, + Tolerations: tolerations, + InitContainers: initContainers, + Containers: containers, RestartPolicy: "Never", DNSPolicy: "ClusterFirst", @@ -110,17 +113,11 @@ func TestSetup_AdaptFunc(t *testing.T) { client.EXPECT().ApplyJob(jobDef).Times(1) client.EXPECT().GetJob(namespace, getJobName(reason)).Times(1).Return(nil, macherrs.NewNotFound(schema.GroupResource{"batch", "jobs"}, jobNamePrefix+reason)) - getConfigurationHashes := func(k8sClient kubernetes.ClientInt, queried map[string]interface{}) map[string]string { - return map[string]string{"testHash": "test"} - } - migrationDone := func(k8sClient kubernetes.ClientInt) error { - return nil - } - configurationDone := func(k8sClient kubernetes.ClientInt) error { - return nil + getConfigurationHashes := func(k8sClient kubernetes.ClientInt, queried map[string]interface{}, necessaryUsers map[string]string) (map[string]string, error) { + return map[string]string{"testHash": "test"}, nil } - query, _, err := AdaptFunc( + getQuery, _, err := AdaptFunc( monitor, componentLabels, namespace, @@ -136,10 +133,6 @@ func TestSetup_AdaptFunc(t *testing.T) { consoleCMName, secretVarsName, secretPasswordsName, - users, - migrationDone, - configurationDone, - getConfigurationHashes, ) queried := map[string]interface{}{} @@ -149,6 +142,7 @@ func TestSetup_AdaptFunc(t *testing.T) { }) assert.NoError(t, err) + query := getQuery(usersMap, getConfigurationHashes) ensure, err := query(client, queried) assert.NoError(t, err) assert.NoError(t, ensure(client)) diff --git a/operator/zitadel/kinds/iam/zitadel/setup/done.go b/operator/zitadel/kinds/iam/zitadel/setup/done.go index b0a27a1554..2278db0064 100644 --- a/operator/zitadel/kinds/iam/zitadel/setup/done.go +++ b/operator/zitadel/kinds/iam/zitadel/setup/done.go @@ -5,6 +5,11 @@ import ( "github.com/caos/orbos/pkg/kubernetes" "github.com/caos/zitadel/operator" "github.com/pkg/errors" + "time" +) + +const ( + timeout = 20 * time.Minute ) func GetDoneFunc( diff --git a/operator/zitadel/kinds/iam/zitadel/users.go b/operator/zitadel/kinds/iam/zitadel/users.go index bc405e544b..7521d012fa 100644 --- a/operator/zitadel/kinds/iam/zitadel/users.go +++ b/operator/zitadel/kinds/iam/zitadel/users.go @@ -1,83 +1,106 @@ package zitadel import ( + "github.com/caos/orbos/pkg/helper" + "github.com/caos/orbos/pkg/kubernetes" + "github.com/caos/orbos/pkg/secret" "sort" "github.com/caos/zitadel/operator/zitadel/kinds/iam/zitadel/configuration" ) -const migrationUser = "flyway" +const ( + migrationUser = "flyway" + mgmtUser = "management" + adminUser = "adminapi" + authUser = "auth" + authzUser = "authz" + notUser = "notification" + esUser = "eventstore" +) -func getAllUsers(desired *DesiredV0) map[string]string { +func getUserListWithoutPasswords(desired *DesiredV0) []string { + userpw, _ := getAllUsers(nil, desired) + users := make([]string, 0) + for user := range userpw { + users = append(users, user) + } + + sort.Slice(users, func(i, j int) bool { + return users[i] < users[j] + }) + return users +} + +func getAllUsers(k8sClient kubernetes.ClientInt, desired *DesiredV0) (map[string]string, error) { passwords := &configuration.Passwords{} if desired != nil && desired.Spec != nil && desired.Spec.Configuration != nil && desired.Spec.Configuration.Passwords != nil { passwords = desired.Spec.Configuration.Passwords } users := make(map[string]string, 0) - migrationPassword := migrationUser - if passwords.Migration != nil { - migrationPassword = passwords.Migration.Value + if err := fillInUserPassword(k8sClient, migrationUser, passwords.Migration, passwords.ExistingMigration, users); err != nil { + return nil, err } - users[migrationUser] = migrationPassword - - mgmtUser := "management" - mgmtPassword := mgmtUser - if passwords != nil && passwords.Management != nil { - mgmtPassword = passwords.Management.Value + if err := fillInUserPassword(k8sClient, mgmtUser, passwords.Management, passwords.ExistingManagement, users); err != nil { + return nil, err } - users[mgmtUser] = mgmtPassword - - adminUser := "adminapi" - adminPassword := adminUser - if passwords != nil && passwords.Adminapi != nil { - adminPassword = passwords.Adminapi.Value + if err := fillInUserPassword(k8sClient, adminUser, passwords.Adminapi, passwords.ExistingAdminapi, users); err != nil { + return nil, err } - users[adminUser] = adminPassword - - authUser := "auth" - authPassword := authUser - if passwords != nil && passwords.Auth != nil { - authPassword = passwords.Auth.Value + if err := fillInUserPassword(k8sClient, authUser, passwords.Auth, passwords.ExistingAuth, users); err != nil { + return nil, err } - users[authUser] = authPassword - - authzUser := "authz" - authzPassword := authzUser - if passwords != nil && passwords.Authz != nil { - authzPassword = passwords.Authz.Value + if err := fillInUserPassword(k8sClient, authzUser, passwords.Authz, passwords.ExistingAuthz, users); err != nil { + return nil, err } - users[authzUser] = authzPassword - - notUser := "notification" - notPassword := notUser - if passwords != nil && passwords.Notification != nil { - notPassword = passwords.Notification.Value + if err := fillInUserPassword(k8sClient, notUser, passwords.Notification, passwords.ExistingNotification, users); err != nil { + return nil, err } - users[notUser] = notPassword - - esUser := "eventstore" - esPassword := esUser - if passwords != nil && passwords.Eventstore != nil { - esPassword = passwords.Eventstore.Value + if err := fillInUserPassword(k8sClient, esUser, passwords.Eventstore, passwords.ExistingEventstore, users); err != nil { + return nil, err } - users[esUser] = esPassword - return users + return users, nil } -func getZitadelUserList() []string { - allUsersMap := getAllUsers(nil) +func fillInUserPassword( + k8sClient kubernetes.ClientInt, + user string, + secret *secret.Secret, + existing *secret.Existing, + userpw map[string]string, +) error { + if k8sClient == nil { + userpw[user] = user + return nil + } - allZitadelUsers := make([]string, 0) - for k := range allUsersMap { + pw, err := helper.GetSecretValue(k8sClient, secret, existing) + if err != nil { + return err + } + if pw != "" { + userpw[user] = pw + } else { + userpw[user] = user + } + + return nil +} + +func getZitadelUserList(k8sClient kubernetes.ClientInt, desired *DesiredV0) (map[string]string, error) { + allUsersMap, err := getAllUsers(k8sClient, desired) + if err != nil { + return nil, err + } + + allZitadelUsers := make(map[string]string, 0) + for k, v := range allUsersMap { if k != migrationUser { - allZitadelUsers = append(allZitadelUsers, k) + allZitadelUsers[k] = v } } - sort.Slice(allZitadelUsers, func(i, j int) bool { - return allZitadelUsers[i] < allZitadelUsers[j] - }) - return allZitadelUsers + return allZitadelUsers, nil } diff --git a/operator/zitadel/kinds/orb/adapt.go b/operator/zitadel/kinds/orb/adapt.go index b1b15e40ef..df84879e45 100644 --- a/operator/zitadel/kinds/orb/adapt.go +++ b/operator/zitadel/kinds/orb/adapt.go @@ -3,18 +3,25 @@ package orb import ( "github.com/caos/orbos/mntr" "github.com/caos/orbos/pkg/kubernetes" + "github.com/caos/orbos/pkg/kubernetes/resources/namespace" "github.com/caos/orbos/pkg/orb" "github.com/caos/orbos/pkg/secret" "github.com/caos/orbos/pkg/tree" "github.com/caos/zitadel/operator" "github.com/caos/zitadel/operator/zitadel/kinds/iam" + zitadeldb "github.com/caos/zitadel/operator/zitadel/kinds/iam/zitadel/database" "github.com/pkg/errors" ) +const ( + namespaceName = "caos-zitadel" +) + func AdaptFunc( orbconfig *orb.Orb, action string, binaryVersion *string, + gitops bool, features []string, ) operator.AdaptFunc { return func( @@ -25,6 +32,8 @@ func AdaptFunc( queryFunc operator.QueryFunc, destroyFunc operator.DestroyFunc, allSecrets map[string]*secret.Secret, + allExisting map[string]*secret.Existing, + migrate bool, err error, ) { defer func() { @@ -32,12 +41,13 @@ func AdaptFunc( }() allSecrets = make(map[string]*secret.Secret) + allExisting = make(map[string]*secret.Existing) orbMonitor := monitor.WithField("kind", "orb") - desiredKind, err := parseDesiredV0(desiredTree) + desiredKind, err := ParseDesiredV0(desiredTree) if err != nil { - return nil, nil, allSecrets, errors.Wrap(err, "parsing desired state failed") + return nil, nil, nil, nil, false, errors.Wrap(err, "parsing desired state failed") } desiredTree.Parsed = desiredKind currentTree = &tree.Tree{} @@ -46,35 +56,64 @@ func AdaptFunc( orbMonitor = orbMonitor.Verbose() } + var dbClient zitadeldb.Client + if gitops { + dbClientT, err := zitadeldb.NewGitOpsClient(monitor, orbconfig.URL, orbconfig.Repokey) + if err != nil { + monitor.Error(err) + return nil, nil, nil, nil, false, err + } + dbClient = dbClientT + } else { + dbClient = zitadeldb.NewCrdClient(monitor) + } + operatorLabels := mustZITADELOperator(binaryVersion) + queryNS, err := namespace.AdaptFuncToEnsure(namespaceName) + if err != nil { + return nil, nil, nil, nil, false, err + } + /*destroyNS, err := namespace.AdaptFuncToDestroy(namespaceName) + if err != nil { + return nil, nil, allSecrets, err + }*/ + iamCurrent := &tree.Tree{} - queryIAM, destroyIAM, zitadelSecrets, err := iam.GetQueryAndDestroyFuncs( + queryIAM, destroyIAM, zitadelSecrets, zitadelExisting, migrateIAM, err := iam.GetQueryAndDestroyFuncs( orbMonitor, operatorLabels, desiredKind.IAM, iamCurrent, desiredKind.Spec.NodeSelector, desiredKind.Spec.Tolerations, - orbconfig, + dbClient, + namespaceName, action, &desiredKind.Spec.Version, features, ) if err != nil { - return nil, nil, allSecrets, err + return nil, nil, nil, nil, false, err } - secret.AppendSecrets("", allSecrets, zitadelSecrets) + migrate = migrate || migrateIAM + secret.AppendSecrets("", allSecrets, zitadelSecrets, allExisting, zitadelExisting) destroyers := make([]operator.DestroyFunc, 0) queriers := make([]operator.QueryFunc, 0) for _, feature := range features { switch feature { case "iam", "migration", "scaleup", "scaledown": - queriers = append(queriers, queryIAM) + queriers = append(queriers, + operator.ResourceQueryToZitadelQuery(queryNS), + queryIAM, + ) destroyers = append(destroyers, destroyIAM) case "operator": - queriers = append(queriers, operator.EnsureFuncToQueryFunc(Reconcile(monitor, desiredTree, false))) + queriers = append(queriers, + operator.ResourceQueryToZitadelQuery(queryNS), + operator.EnsureFuncToQueryFunc(Reconcile(monitor, desiredKind.Spec)), + ) } } @@ -96,6 +135,8 @@ func AdaptFunc( return operator.DestroyersToDestroyFunc(monitor, destroyers)(k8sClient) }, allSecrets, + allExisting, + migrate, nil } } diff --git a/operator/zitadel/kinds/orb/desired.go b/operator/zitadel/kinds/orb/desired.go index 0c390d756c..5af706a5dd 100644 --- a/operator/zitadel/kinds/orb/desired.go +++ b/operator/zitadel/kinds/orb/desired.go @@ -8,20 +8,24 @@ import ( type DesiredV0 struct { Common *tree.Common `yaml:",inline"` - Spec struct { - Verbose bool - NodeSelector map[string]string `yaml:"nodeSelector,omitempty"` - Tolerations []corev1.Toleration `yaml:"tolerations,omitempty"` - Version string `yaml:"version,omitempty"` - SelfReconciling bool `yaml:"selfReconciling"` - //Use this registry to pull the database operator image from - //@default: ghcr.io - CustomImageRegistry string `json:"customImageRegistry,omitempty" yaml:"customImageRegistry,omitempty"` - } - IAM *tree.Tree + Spec *Spec `json:"spec" yaml:"spec"` + IAM *tree.Tree `json:"iam" yaml:"iam"` } -func parseDesiredV0(desiredTree *tree.Tree) (*DesiredV0, error) { +// +kubebuilder:object:generate=true +type Spec struct { + Verbose bool `json:"verbose" yaml:"verbose"` + NodeSelector map[string]string `json:"nodeSelector,omitempty" yaml:"nodeSelector,omitempty"` + Tolerations []corev1.Toleration `json:"tolerations,omitempty" yaml:"tolerations,omitempty"` + Version string `json:"version,omitempty" yaml:"version,omitempty"` + SelfReconciling bool `json:"selfReconciling" yaml:"selfReconciling"` + GitOps bool `json:"gitops,omitempty" yaml:"gitops,omitempty"` + //Use this registry to pull the zitadel operator image from + //@default: ghcr.io + CustomImageRegistry string `json:"customImageRegistry,omitempty" yaml:"customImageRegistry,omitempty"` +} + +func ParseDesiredV0(desiredTree *tree.Tree) (*DesiredV0, error) { desiredKind := &DesiredV0{Common: desiredTree.Common} if err := desiredTree.Original.Decode(desiredKind); err != nil { diff --git a/operator/zitadel/kinds/orb/reconcile.go b/operator/zitadel/kinds/orb/reconcile.go index 67ba21edfd..977afa2496 100644 --- a/operator/zitadel/kinds/orb/reconcile.go +++ b/operator/zitadel/kinds/orb/reconcile.go @@ -10,37 +10,36 @@ import ( "github.com/pkg/errors" ) -func Reconcile(monitor mntr.Monitor, desiredTree *tree.Tree, takeoff bool) operator.EnsureFunc { +func Reconcile( + monitor mntr.Monitor, + spec *Spec, +) operator.EnsureFunc { return func(k8sClient kubernetes2.ClientInt) (err error) { - defer func() { - err = errors.Wrapf(err, "building %s failed", desiredTree.Common.Kind) - }() + recMonitor := monitor.WithField("version", spec.Version) - desiredKind, err := parseDesiredV0(desiredTree) - if err != nil { - return errors.Wrap(err, "parsing desired state failed") - } - desiredTree.Parsed = desiredKind - - recMonitor := monitor.WithField("version", desiredKind.Spec.Version) - - if desiredKind.Spec.Version == "" { - err := errors.New("No version set in zitadel.yml") + if spec.Version == "" { + err := errors.New("No version provided for self-reconciling") recMonitor.Error(err) return err } - imageRegistry := desiredKind.Spec.CustomImageRegistry + imageRegistry := spec.CustomImageRegistry if imageRegistry == "" { imageRegistry = "ghcr.io" } - if takeoff || desiredKind.Spec.SelfReconciling { - if err := kubernetes.EnsureZitadelOperatorArtifacts(monitor, treelabels.MustForAPI(desiredTree, mustZITADELOperator(&desiredKind.Spec.Version)), k8sClient, desiredKind.Spec.Version, desiredKind.Spec.NodeSelector, desiredKind.Spec.Tolerations, imageRegistry); err != nil { + if spec.SelfReconciling { + desiredTree := &tree.Tree{ + Common: &tree.Common{ + Kind: "zitadel.caos.ch/Orb", + Version: "v0", + }, + } + + if err := kubernetes.EnsureZitadelOperatorArtifacts(monitor, treelabels.MustForAPI(desiredTree, mustZITADELOperator(&spec.Version)), k8sClient, spec.Version, spec.NodeSelector, spec.Tolerations, imageRegistry, spec.GitOps); err != nil { recMonitor.Error(errors.Wrap(err, "Failed to deploy zitadel-operator into k8s-cluster")) return err } - recMonitor.Info("Applied zitadel-operator") } return nil diff --git a/operator/zitadel/kinds/orb/zz_generated.deepcopy.go b/operator/zitadel/kinds/orb/zz_generated.deepcopy.go new file mode 100644 index 0000000000..16633db568 --- /dev/null +++ b/operator/zitadel/kinds/orb/zz_generated.deepcopy.go @@ -0,0 +1,54 @@ +// +build !ignore_autogenerated + +/* + + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package orb + +import ( + v1 "k8s.io/api/core/v1" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Spec) DeepCopyInto(out *Spec) { + *out = *in + if in.NodeSelector != nil { + in, out := &in.NodeSelector, &out.NodeSelector + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Tolerations != nil { + in, out := &in.Tolerations, &out.Tolerations + *out = make([]v1.Toleration, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Spec. +func (in *Spec) DeepCopy() *Spec { + if in == nil { + return nil + } + out := new(Spec) + in.DeepCopyInto(out) + return out +} diff --git a/operator/zitadel/takeoff.go b/operator/zitadel/takeoff.go index d9a9c65c89..ba06d0b23b 100644 --- a/operator/zitadel/takeoff.go +++ b/operator/zitadel/takeoff.go @@ -2,6 +2,7 @@ package zitadel import ( "errors" + "github.com/caos/zitadel/operator" "github.com/caos/orbos/mntr" @@ -10,7 +11,12 @@ import ( "github.com/caos/orbos/pkg/tree" ) -func Takeoff(monitor mntr.Monitor, gitClient *git.Client, adapt operator.AdaptFunc, k8sClient *kubernetes.Client) func() error { +func Takeoff( + monitor mntr.Monitor, + gitClient *git.Client, + adapt operator.AdaptFunc, + k8sClient *kubernetes.Client, +) func() error { return func() error { internalMonitor := monitor.WithField("operator", "zitadel") internalMonitor.Info("Takeoff") @@ -26,7 +32,7 @@ func Takeoff(monitor mntr.Monitor, gitClient *git.Client, adapt operator.AdaptFu return err } - query, _, _, err := adapt(internalMonitor, treeDesired, treeCurrent) + query, _, _, _, _, err := adapt(internalMonitor, treeDesired, treeCurrent) if err != nil { internalMonitor.Error(err) return err diff --git a/pkg/databases/backup.go b/pkg/databases/backup.go index 44f6ce5e9f..3b8cb5f5ce 100644 --- a/pkg/databases/backup.go +++ b/pkg/databases/backup.go @@ -22,7 +22,7 @@ func InstantBackup( } current := &tree.Tree{} - query, _, _, err := orbdb.AdaptFunc(name, nil, "instantbackup")(monitor, desired, current) + query, _, _, _, _, err := orbdb.AdaptFunc(name, nil, false, "instantbackup")(monitor, desired, current) if err != nil { monitor.Error(err) return err diff --git a/pkg/databases/clear.go b/pkg/databases/clear.go index 38f59170a2..67917eb1a3 100644 --- a/pkg/databases/clear.go +++ b/pkg/databases/clear.go @@ -23,7 +23,7 @@ func Clear( } current := &tree.Tree{} - query, _, _, err := orbdb.AdaptFunc("", nil, "clean")(monitor, desired, current) + query, _, _, _, _, err := orbdb.AdaptFunc("", nil, false, "clean")(monitor, desired, current) if err != nil { monitor.Error(err) return err diff --git a/pkg/databases/connection.go b/pkg/databases/connection.go index 96c45a0da6..daec720b78 100644 --- a/pkg/databases/connection.go +++ b/pkg/databases/connection.go @@ -6,11 +6,24 @@ import ( "github.com/caos/orbos/pkg/kubernetes" "github.com/caos/orbos/pkg/tree" "github.com/caos/zitadel/operator/api" + "github.com/caos/zitadel/operator/api/database" coredb "github.com/caos/zitadel/operator/database/kinds/databases/core" orbdb "github.com/caos/zitadel/operator/database/kinds/orb" ) -func GetConnectionInfo( +func CrdGetConnectionInfo( + monitor mntr.Monitor, + k8sClient kubernetes.ClientInt, +) (string, string, error) { + desired, err := database.ReadCrd(k8sClient) + if err != nil { + return "", "", err + } + + return getConnectionInfo(monitor, k8sClient, desired) +} + +func GitOpsGetConnectionInfo( monitor mntr.Monitor, k8sClient kubernetes.ClientInt, gitClient *git.Client, @@ -20,9 +33,18 @@ func GetConnectionInfo( monitor.Error(err) return "", "", err } + + return getConnectionInfo(monitor, k8sClient, desired) +} + +func getConnectionInfo( + monitor mntr.Monitor, + k8sClient kubernetes.ClientInt, + desired *tree.Tree, +) (string, string, error) { current := &tree.Tree{} - query, _, _, err := orbdb.AdaptFunc("", nil)(monitor, desired, current) + query, _, _, _, _, err := orbdb.AdaptFunc("", nil, false, "database")(monitor, desired, current) if err != nil { return "", "", err } diff --git a/pkg/databases/restore.go b/pkg/databases/restore.go index 388562f3b7..44386a0d91 100644 --- a/pkg/databases/restore.go +++ b/pkg/databases/restore.go @@ -24,7 +24,7 @@ func Restore( } current := &tree.Tree{} - query, _, _, err := orbdb.AdaptFunc(name, nil, "restore")(monitor, desired, current) + query, _, _, _, _, err := orbdb.AdaptFunc(name, nil, false, "restore")(monitor, desired, current) if err != nil { monitor.Error(err) return err diff --git a/pkg/databases/user.go b/pkg/databases/user.go index f7883cd406..0d5ddd79d4 100644 --- a/pkg/databases/user.go +++ b/pkg/databases/user.go @@ -6,11 +6,25 @@ import ( "github.com/caos/orbos/pkg/kubernetes" "github.com/caos/orbos/pkg/tree" "github.com/caos/zitadel/operator/api" + "github.com/caos/zitadel/operator/api/database" coredb "github.com/caos/zitadel/operator/database/kinds/databases/core" orbdb "github.com/caos/zitadel/operator/database/kinds/orb" ) -func ListUsers( +func CrdListUsers( + monitor mntr.Monitor, + k8sClient kubernetes.ClientInt, +) ([]string, error) { + desired, err := database.ReadCrd(k8sClient) + if err != nil { + monitor.Error(err) + return nil, err + } + + return listUsers(monitor, k8sClient, desired) +} + +func GitOpsListUsers( monitor mntr.Monitor, k8sClient kubernetes.ClientInt, gitClient *git.Client, @@ -20,9 +34,18 @@ func ListUsers( monitor.Error(err) return nil, err } + + return listUsers(monitor, k8sClient, desired) +} + +func listUsers( + monitor mntr.Monitor, + k8sClient kubernetes.ClientInt, + desired *tree.Tree, +) ([]string, error) { current := &tree.Tree{} - query, _, _, err := orbdb.AdaptFunc("", nil)(monitor, desired, current) + query, _, _, _, _, err := orbdb.AdaptFunc("", nil, false, "database")(monitor, desired, current) if err != nil { return nil, err } @@ -52,7 +75,20 @@ func ListUsers( return users, nil } -func AddUser( +func CrdAddUser( + monitor mntr.Monitor, + user string, + k8sClient kubernetes.ClientInt, +) error { + desired, err := database.ReadCrd(k8sClient) + if err != nil { + monitor.Error(err) + return err + } + return addUser(monitor, user, k8sClient, desired) +} + +func GitOpsAddUser( monitor mntr.Monitor, user string, k8sClient kubernetes.ClientInt, @@ -63,9 +99,18 @@ func AddUser( monitor.Error(err) return err } + return addUser(monitor, user, k8sClient, desired) +} + +func addUser( + monitor mntr.Monitor, + user string, + k8sClient kubernetes.ClientInt, + desired *tree.Tree, +) error { current := &tree.Tree{} - query, _, _, err := orbdb.AdaptFunc("", nil)(monitor, desired, current) + query, _, _, _, _, err := orbdb.AdaptFunc("", nil, false, "database")(monitor, desired, current) if err != nil { return err } @@ -91,7 +136,7 @@ func AddUser( return ensureUser(k8sClient) } -func DeleteUser( +func GitOpsDeleteUser( monitor mntr.Monitor, user string, k8sClient kubernetes.ClientInt, @@ -102,9 +147,33 @@ func DeleteUser( monitor.Error(err) return err } + + return deleteUser(monitor, user, k8sClient, desired) +} + +func CrdDeleteUser( + monitor mntr.Monitor, + user string, + k8sClient kubernetes.ClientInt, +) error { + desired, err := database.ReadCrd(k8sClient) + if err != nil { + monitor.Error(err) + return err + } + + return deleteUser(monitor, user, k8sClient, desired) +} + +func deleteUser( + monitor mntr.Monitor, + user string, + k8sClient kubernetes.ClientInt, + desired *tree.Tree, +) error { current := &tree.Tree{} - query, _, _, err := orbdb.AdaptFunc("", nil)(monitor, desired, current) + query, _, _, _, _, err := orbdb.AdaptFunc("", nil, false, "database")(monitor, desired, current) if err != nil { return err } diff --git a/pkg/kubernetes/artifacts.go b/pkg/kubernetes/artifacts.go index 748399d742..f12e3ba417 100644 --- a/pkg/kubernetes/artifacts.go +++ b/pkg/kubernetes/artifacts.go @@ -3,6 +3,9 @@ package kubernetes import ( "fmt" + "gopkg.in/yaml.v3" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "github.com/caos/orbos/mntr" "github.com/caos/orbos/pkg/kubernetes" "github.com/caos/orbos/pkg/labels" @@ -21,6 +24,7 @@ func EnsureZitadelOperatorArtifacts( nodeselector map[string]string, tolerations []core.Toleration, imageRegistry string, + gitops bool, ) error { monitor.WithFields(map[string]interface{}{ @@ -78,6 +82,174 @@ func EnsureZitadelOperatorArtifacts( return err } + if !gitops { + crd := `apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.2.2 + creationTimestamp: null + name: zitadels.caos.ch +spec: + group: caos.ch + names: + kind: Zitadel + listKind: ZitadelList + plural: zitadels + singular: zitadel + scope: "" + validation: + openAPIV3Schema: + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + properties: + iam: + type: object + kind: + type: string + spec: + properties: + customImageRegistry: + description: 'Use this registry to pull the zitadel operator image + from @default: ghcr.io' + type: string + databaseCrd: + properties: + name: + type: string + namespace: + type: string + type: object + gitops: + type: boolean + nodeSelector: + additionalProperties: + type: string + type: object + selfReconciling: + type: boolean + tolerations: + items: + description: The pod this Toleration is attached to tolerates + any taint that matches the triple using the + matching operator . + properties: + effect: + description: Effect indicates the taint effect to match. Empty + means match all taint effects. When specified, allowed values + are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: Key is the taint key that the toleration applies + to. Empty means match all taint keys. If the key is empty, + operator must be Exists; this combination means to match + all values and all keys. + type: string + operator: + description: Operator represents a key's relationship to the + value. Valid operators are Exists and Equal. Defaults to + Equal. Exists is equivalent to wildcard for value, so that + a pod can tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: TolerationSeconds represents the period of time + the toleration (which must be of effect NoExecute, otherwise + this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do + not evict). Zero and negative values will be treated as + 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: Value is the taint value the toleration matches + to. If the operator is Exists, the value should be empty, + otherwise just a regular string. + type: string + type: object + type: array + verbose: + type: boolean + version: + type: string + required: + - selfReconciling + - verbose + type: object + version: + type: string + required: + - iam + - kind + - spec + - version + type: object + status: + type: object + type: object + version: v1 + versions: + - name: v1 + served: true + storage: true +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: []` + + crdDefinition := &unstructured.Unstructured{} + if err := yaml.Unmarshal([]byte(crd), &crdDefinition.Object); err != nil { + return err + } + + if err := client.ApplyCRDResource( + crdDefinition, + ); err != nil { + return err + } + monitor.WithFields(map[string]interface{}{ + "version": version, + }).Debug("Database Operator crd ensured") + } + + var ( + cmd = []string{"/zitadelctl", "operator"} + volumes []core.Volume + volumeMounts []core.VolumeMount + ) + + if gitops { + cmd = append(cmd, "--gitops", "-f", "/secrets/orbconfig") + volumes = []core.Volume{{ + Name: "orbconfig", + VolumeSource: core.VolumeSource{ + Secret: &core.SecretVolumeSource{ + SecretName: "caos", + }, + }, + }} + volumeMounts = []core.VolumeMount{{ + Name: "orbconfig", + ReadOnly: true, + MountPath: "/secrets", + }} + } else { + cmd = append(cmd, "--kubeconfig", "") + } + deployment := &apps.Deployment{ ObjectMeta: mach.ObjectMeta{ Name: nameLabels.Name(), @@ -99,18 +271,14 @@ func EnsureZitadelOperatorArtifacts( Name: "zitadel", ImagePullPolicy: core.PullIfNotPresent, Image: fmt.Sprintf("%s/caos/zitadel-operator:%s", imageRegistry, version), - Command: []string{"/zitadelctl", "operator", "-f", "/secrets/orbconfig"}, + Command: cmd, Args: []string{}, Ports: []core.ContainerPort{{ Name: "metrics", ContainerPort: 2112, Protocol: "TCP", }}, - VolumeMounts: []core.VolumeMount{{ - Name: "orbconfig", - ReadOnly: true, - MountPath: "/secrets", - }}, + VolumeMounts: volumeMounts, Resources: core.ResourceRequirements{ Limits: core.ResourceList{ "cpu": resource.MustParse("500m"), @@ -122,16 +290,9 @@ func EnsureZitadelOperatorArtifacts( }, }, }}, - NodeSelector: nodeselector, - Tolerations: tolerations, - Volumes: []core.Volume{{ - Name: "orbconfig", - VolumeSource: core.VolumeSource{ - Secret: &core.SecretVolumeSource{ - SecretName: "caos", - }, - }, - }}, + NodeSelector: nodeselector, + Tolerations: tolerations, + Volumes: volumes, TerminationGracePeriodSeconds: int64Ptr(10), }, }, @@ -170,7 +331,8 @@ func EnsureDatabaseArtifacts( version string, nodeselector map[string]string, tolerations []core.Toleration, - imageRegistry string) error { + imageRegistry string, + gitops bool) error { monitor.WithFields(map[string]interface{}{ "database": version, @@ -227,6 +389,167 @@ func EnsureDatabaseArtifacts( return err } + if !gitops { + crd := `apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.2.2 + creationTimestamp: null + name: databases.caos.ch +spec: + group: caos.ch + names: + kind: Database + listKind: DatabaseList + plural: databases + singular: database + scope: "" + validation: + openAPIV3Schema: + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + properties: + database: + type: object + kind: + type: string + spec: + properties: + customImageRegistry: + description: 'Use this registry to pull the Database operator image + from @default: ghcr.io' + type: string + gitOps: + type: boolean + nodeSelector: + additionalProperties: + type: string + type: object + selfReconciling: + type: boolean + tolerations: + items: + description: The pod this Toleration is attached to tolerates + any taint that matches the triple using the + matching operator . + properties: + effect: + description: Effect indicates the taint effect to match. Empty + means match all taint effects. When specified, allowed values + are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: Key is the taint key that the toleration applies + to. Empty means match all taint keys. If the key is empty, + operator must be Exists; this combination means to match + all values and all keys. + type: string + operator: + description: Operator represents a key's relationship to the + value. Valid operators are Exists and Equal. Defaults to + Equal. Exists is equivalent to wildcard for value, so that + a pod can tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: TolerationSeconds represents the period of time + the toleration (which must be of effect NoExecute, otherwise + this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do + not evict). Zero and negative values will be treated as + 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: Value is the taint value the toleration matches + to. If the operator is Exists, the value should be empty, + otherwise just a regular string. + type: string + type: object + type: array + verbose: + type: boolean + version: + type: string + required: + - selfReconciling + - verbose + type: object + version: + type: string + required: + - database + - kind + - spec + - version + type: object + status: + type: object + type: object + version: v1 + versions: + - name: v1 + served: true + storage: true +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: []` + + crdDefinition := &unstructured.Unstructured{} + if err := yaml.Unmarshal([]byte(crd), &crdDefinition.Object); err != nil { + return err + } + + if err := client.ApplyCRDResource( + crdDefinition, + ); err != nil { + return err + } + monitor.WithFields(map[string]interface{}{ + "version": version, + }).Debug("Database Operator crd ensured") + } + + var ( + cmd = []string{"/zitadelctl", "database"} + volumes []core.Volume + volumeMounts []core.VolumeMount + ) + + if gitops { + cmd = append(cmd, "--gitops", "-f", "/secrets/orbconfig") + volumes = []core.Volume{{ + Name: "orbconfig", + VolumeSource: core.VolumeSource{ + Secret: &core.SecretVolumeSource{ + SecretName: "caos", + }, + }, + }} + volumeMounts = []core.VolumeMount{{ + Name: "orbconfig", + ReadOnly: true, + MountPath: "/secrets", + }} + } else { + cmd = append(cmd, "--kubeconfig", "") + } + deployment := &apps.Deployment{ ObjectMeta: mach.ObjectMeta{ Name: "database-operator", @@ -248,18 +571,14 @@ func EnsureDatabaseArtifacts( Name: "database", ImagePullPolicy: core.PullIfNotPresent, Image: fmt.Sprintf("%s/caos/zitadel-operator:%s", imageRegistry, version), - Command: []string{"/zitadelctl", "database", "-f", "/secrets/orbconfig"}, + Command: cmd, Args: []string{}, Ports: []core.ContainerPort{{ Name: "metrics", ContainerPort: 2112, Protocol: "TCP", }}, - VolumeMounts: []core.VolumeMount{{ - Name: "orbconfig", - ReadOnly: true, - MountPath: "/secrets", - }}, + VolumeMounts: volumeMounts, Resources: core.ResourceRequirements{ Limits: core.ResourceList{ "cpu": resource.MustParse("500m"), @@ -271,16 +590,9 @@ func EnsureDatabaseArtifacts( }, }, }}, - NodeSelector: nodeselector, - Tolerations: tolerations, - Volumes: []core.Volume{{ - Name: "orbconfig", - VolumeSource: core.VolumeSource{ - Secret: &core.SecretVolumeSource{ - SecretName: "caos", - }, - }, - }}, + NodeSelector: nodeselector, + Tolerations: tolerations, + Volumes: volumes, TerminationGracePeriodSeconds: int64Ptr(10), }, }, diff --git a/scripts/generateCrd.sh b/scripts/generateCrd.sh new file mode 100755 index 0000000000..1c14a569c6 --- /dev/null +++ b/scripts/generateCrd.sh @@ -0,0 +1,3 @@ +controller-gen object:headerFile="hack/boilerplate.go.txt" paths="./..." + +controller-gen "crd:trivialVersions=true" crd paths="./..." output:crd:artifacts:config=test diff --git a/scripts/operator-debug.sh b/scripts/operator-debug.sh deleted file mode 100755 index c3faf7afc6..0000000000 --- a/scripts/operator-debug.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -set -e - -./build/operator/prebuild.sh "./migrations" - -go build -gcflags "all=-N -l" -o /tmp/zitadeloperator-debug ./cmd/operator-debug -dlv exec --api-version 2 --headless --listen 127.0.0.1:2345 /tmp/zitadeloperator-debug -- "$@"