From 8badcd4b979fc6fb517f6c7984e0182a4a865097 Mon Sep 17 00:00:00 2001 From: Vegar Sechmann Molvig Date: Fri, 12 Apr 2024 16:11:18 +0200 Subject: [PATCH 1/3] Start implementing sqluser controller - needs tests Co-authored-by: sindrerh2 Co-authored-by: Morten Lied Johansen --- cmd/main.go | 7 + go.mod | 79 ++---- go.sum | 163 +++--------- internal/controller/common.go | 31 +++ internal/controller/sqlsslcert_controller.go | 20 +- internal/controller/sqluser_controller.go | 248 ++++++++++++++++++ .../controller/sqluser_controller_test.go | 248 ++++++++++++++++++ 7 files changed, 598 insertions(+), 198 deletions(-) create mode 100644 internal/controller/common.go create mode 100644 internal/controller/sqluser_controller.go create mode 100644 internal/controller/sqluser_controller_test.go diff --git a/cmd/main.go b/cmd/main.go index 28d009e..35559e3 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -99,6 +99,13 @@ func main() { setupLog.Error(err, "unable to create controller", "controller", "SQLSSLCert") os.Exit(1) } + if err = (&controller.SQLUserReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "SQLUser") + os.Exit(1) + } //+kubebuilder:scaffold:builder if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { diff --git a/go.mod b/go.mod index 6b66683..4423f8d 100644 --- a/go.mod +++ b/go.mod @@ -13,14 +13,16 @@ replace github.com/GoogleCloudPlatform/k8s-config-connector/mockgcp => ./invalid require ( github.com/GoogleCloudPlatform/k8s-config-connector v1.115.0 + github.com/go-logr/logr v1.4.1 github.com/golangci/golangci-lint v1.57.2 + github.com/nais/liberator v0.0.0-20240412093323-c3d6aeb3b6d3 github.com/onsi/ginkgo/v2 v2.17.1 github.com/onsi/gomega v1.32.0 github.com/prometheus/client_golang v1.19.0 k8s.io/api v0.29.3 - k8s.io/apiextensions-apiserver v0.29.3 k8s.io/apimachinery v0.29.3 k8s.io/client-go v0.29.3 + k8s.io/utils v0.0.0-20240310230437-4693a0247e57 sigs.k8s.io/controller-runtime v0.17.3 sigs.k8s.io/controller-runtime/tools/setup-envtest v0.0.0-20240405143037-c25fe2f5ca0f ) @@ -37,19 +39,15 @@ require ( github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 // indirect github.com/GaijinEntertainment/go-exhaustruct/v3 v3.2.0 // indirect github.com/Masterminds/semver v1.5.0 // indirect - github.com/NYTimes/gziphandler v1.1.1 // indirect github.com/OpenPeeDeeP/depguard/v2 v2.2.0 // indirect github.com/alecthomas/go-check-sumtype v0.1.4 // indirect github.com/alexkohler/nakedret/v2 v2.0.4 // indirect github.com/alexkohler/prealloc v1.0.0 // indirect github.com/alingse/asasalint v0.0.11 // indirect - github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df // indirect - github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a // indirect github.com/ashanbrown/forbidigo v1.6.0 // indirect github.com/ashanbrown/makezero v1.1.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bkielbasa/cyclop v1.2.1 // indirect - github.com/blang/semver/v4 v4.0.0 // indirect github.com/blizzy78/varnamelen v0.8.0 // indirect github.com/bombsimon/wsl/v4 v4.2.1 // indirect github.com/breml/bidichk v0.2.7 // indirect @@ -58,16 +56,13 @@ require ( github.com/butuzov/mirror v1.1.0 // indirect github.com/catenacyber/perfsprint v0.7.1 // indirect github.com/ccojocar/zxcvbn-go v1.0.2 // indirect - github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/charithe/durationcheck v0.0.10 // indirect github.com/chavacava/garif v0.1.0 // indirect github.com/ckaznocha/intrange v0.1.1 // indirect - github.com/coreos/go-semver v0.3.1 // indirect - github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/curioswitch/go-reassign v0.2.0 // indirect github.com/daixiang0/gci v0.12.3 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/denis-tingaikin/go-header v0.5.0 // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/ettle/strcase v0.2.0 // indirect @@ -75,14 +70,11 @@ require ( github.com/evanphx/json-patch/v5 v5.8.0 // indirect github.com/fatih/color v1.16.0 // indirect github.com/fatih/structtag v1.2.0 // indirect - github.com/felixge/httpsnoop v1.0.4 // indirect github.com/firefart/nonamedreturns v1.0.4 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/fzipp/gocyclo v0.6.0 // indirect github.com/ghostiam/protogetter v0.3.5 // indirect github.com/go-critic/go-critic v0.11.2 // indirect - github.com/go-logr/logr v1.4.1 // indirect - github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/zapr v1.3.0 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect @@ -108,24 +100,20 @@ require ( github.com/golangci/plugin-module-register v0.1.1 // indirect github.com/golangci/revgrep v0.5.2 // indirect github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed // indirect - github.com/google/cel-go v0.17.7 // indirect github.com/google/gnostic-models v0.6.8 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/pprof v0.0.0-20210804190019-f964ff605595 // indirect github.com/google/uuid v1.6.0 // indirect github.com/gordonklaus/ineffassign v0.1.0 // indirect - github.com/gorilla/websocket v1.5.0 // indirect github.com/gostaticanalysis/analysisutil v0.7.1 // indirect github.com/gostaticanalysis/comment v1.4.2 // indirect github.com/gostaticanalysis/forcetypeassert v0.1.0 // indirect github.com/gostaticanalysis/nilerr v0.1.1 // indirect - github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect github.com/hashicorp/go-version v1.6.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/hexops/gotextdiff v1.0.3 // indirect - github.com/imdario/mergo v0.3.15 // indirect + github.com/imdario/mergo v0.3.16 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jgautheron/goconst v1.7.1 // indirect github.com/jingyugao/rowserrcheck v1.1.1 // indirect @@ -145,7 +133,7 @@ require ( github.com/leonklingele/grouper v1.1.1 // indirect github.com/lufeee/execinquery v1.2.1 // indirect github.com/macabu/inamedparam v0.1.3 // indirect - github.com/magiconair/properties v1.8.6 // indirect + github.com/magiconair/properties v1.8.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/maratori/testableexamples v1.0.0 // indirect github.com/maratori/testpackage v1.1.1 // indirect @@ -153,25 +141,22 @@ require ( github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.9 // indirect - github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect github.com/mgechev/revive v1.3.7 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/hashstructure v1.1.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect - github.com/moby/spdystream v0.2.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/moricho/tparallel v0.3.1 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect github.com/nakabonne/nestif v0.3.1 // indirect github.com/nishanths/exhaustive v0.12.0 // indirect github.com/nishanths/predeclared v0.2.2 // indirect github.com/nunnatsa/ginkgolinter v0.16.2 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect - github.com/pelletier/go-toml v1.9.5 // indirect github.com/pelletier/go-toml/v2 v2.2.0 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/polyfloyd/go-errorlint v1.4.8 // indirect github.com/prometheus/client_model v0.5.0 // indirect github.com/prometheus/common v0.48.0 // indirect @@ -182,6 +167,8 @@ require ( github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 // indirect github.com/ryancurrah/gomodguard v1.3.1 // indirect github.com/ryanrolds/sqlclosecheck v0.5.1 // indirect + github.com/sagikazarmark/locafero v0.4.0 // indirect + github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/sanposhiho/wastedassign/v2 v2.0.7 // indirect github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 // indirect github.com/sashamelentyev/interfacebloat v1.1.0 // indirect @@ -192,19 +179,18 @@ require ( github.com/sivchari/containedctx v1.0.3 // indirect github.com/sivchari/tenv v1.7.1 // indirect github.com/sonatard/noctx v0.0.2 // indirect + github.com/sourcegraph/conc v0.3.0 // indirect github.com/sourcegraph/go-diff v0.7.0 // indirect github.com/spf13/afero v1.11.0 // indirect - github.com/spf13/cast v1.5.0 // indirect + github.com/spf13/cast v1.6.0 // indirect github.com/spf13/cobra v1.8.0 // indirect - github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/spf13/viper v1.12.0 // indirect + github.com/spf13/viper v1.18.2 // indirect github.com/ssgreg/nlreturn/v2 v2.2.1 // indirect github.com/stbenjam/no-sprintf-host-port v0.1.1 // indirect - github.com/stoewer/go-strcase v1.2.0 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/stretchr/testify v1.9.0 // indirect - github.com/subosito/gotenv v1.4.1 // indirect + github.com/subosito/gotenv v1.6.0 // indirect github.com/t-yuki/gocover-cobertura v0.0.0-20180217150009-aaee18c8195c // indirect github.com/tdakkota/asciicheck v0.2.0 // indirect github.com/tetafro/godot v1.4.16 // indirect @@ -222,55 +208,34 @@ require ( gitlab.com/bosi/decorder v0.4.1 // indirect go-simpler.org/musttag v0.9.0 // indirect go-simpler.org/sloglint v0.5.0 // indirect - go.etcd.io/etcd/api/v3 v3.5.10 // indirect - go.etcd.io/etcd/client/pkg/v3 v3.5.10 // indirect - go.etcd.io/etcd/client/v3 v3.5.10 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 // indirect - go.opentelemetry.io/otel v1.22.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0 // indirect - go.opentelemetry.io/otel/metric v1.22.0 // indirect - go.opentelemetry.io/otel/sdk v1.19.0 // indirect - go.opentelemetry.io/otel/trace v1.22.0 // indirect - go.opentelemetry.io/proto/otlp v1.0.0 // indirect go.uber.org/automaxprocs v1.5.3 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect - golang.org/x/crypto v0.21.0 // indirect golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc // indirect golang.org/x/exp/typeparams v0.0.0-20240314144324-c7f7c6466f7f // indirect - golang.org/x/mod v0.16.0 // indirect - golang.org/x/net v0.22.0 // indirect + golang.org/x/mod v0.17.0 // indirect + golang.org/x/net v0.24.0 // indirect golang.org/x/oauth2 v0.16.0 // indirect - golang.org/x/sync v0.6.0 // indirect - golang.org/x/sys v0.18.0 // indirect - golang.org/x/term v0.18.0 // indirect + golang.org/x/sync v0.7.0 // indirect + golang.org/x/sys v0.19.0 // indirect + golang.org/x/term v0.19.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.5.0 // indirect - golang.org/x/tools v0.19.0 // indirect + golang.org/x/tools v0.20.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect google.golang.org/appengine v1.6.8 // indirect - google.golang.org/genproto v0.0.0-20240116215550-a9fa1716bcac // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac // indirect - google.golang.org/grpc v1.61.0 // indirect google.golang.org/protobuf v1.33.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect - gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect honnef.co/go/tools v0.4.7 // indirect - k8s.io/apiserver v0.29.3 // indirect + k8s.io/apiextensions-apiserver v0.29.3 // indirect k8s.io/component-base v0.29.3 // indirect - k8s.io/klog/v2 v2.110.1 // indirect - k8s.io/kms v0.29.3 // indirect + k8s.io/klog/v2 v2.120.1 // indirect k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 // indirect - k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect mvdan.cc/gofumpt v0.6.0 // indirect mvdan.cc/unparam v0.0.0-20240104100049-c549a3470d14 // indirect - sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.28.0 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect sigs.k8s.io/yaml v1.4.0 // indirect diff --git a/go.sum b/go.sum index b8ebccc..8d454d6 100644 --- a/go.sum +++ b/go.sum @@ -57,8 +57,6 @@ github.com/GoogleCloudPlatform/k8s-config-connector v1.115.0 h1:TXrr4LCw+gr4FKgZ github.com/GoogleCloudPlatform/k8s-config-connector v1.115.0/go.mod h1:5WJhUhJ3proxdCHxwdC/iIev8Jiap4rGnkFF8R9e6yA= github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= -github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= -github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= github.com/OpenPeeDeeP/depguard/v2 v2.2.0 h1:vDfG60vDtIuf0MEOhmLlLLSzqaRM8EMcgJPdp74zmpA= github.com/OpenPeeDeeP/depguard/v2 v2.2.0/go.mod h1:CIzddKRvLBC4Au5aYP/i3nyaWQ+ClszLIuVocRiCYFQ= github.com/alecthomas/assert/v2 v2.2.2 h1:Z/iVC0xZfWTaFNE6bA3z07T86hd45Xe2eLt6WVy2bbk= @@ -78,10 +76,6 @@ github.com/alexkohler/prealloc v1.0.0 h1:Hbq0/3fJPQhNkN0dR95AVrr6R7tou91y0uHG5pO github.com/alexkohler/prealloc v1.0.0/go.mod h1:VetnK3dIgFBBKmg0YnD9F9x6Icjd+9cvfHR56wJVlKE= github.com/alingse/asasalint v0.0.11 h1:SFwnQXJ49Kx/1GghOFz1XGqHYKp21Kq1nHad/0WQRnw= github.com/alingse/asasalint v0.0.11/go.mod h1:nCaoMhw7a9kSJObvQyVzNTPBDbNpdocqrSP7t/cW5+I= -github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df h1:7RFfzj4SSt6nnvCPbCqijJi1nWCd+TqAT3bYCStRC18= -github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM= -github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA= -github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/ashanbrown/forbidigo v1.6.0 h1:D3aewfM37Yb3pxHujIPSpTf6oQk9sc9WZi8gerOIVIY= github.com/ashanbrown/forbidigo v1.6.0/go.mod h1:Y8j9jy9ZYAEHXdu723cUlraTqbzjKF1MUyfOKL+AjcU= github.com/ashanbrown/makezero v1.1.1 h1:iCQ87C0V0vSyO+M9E/FZYbu65auqH0lnsOkf5FcB28s= @@ -92,9 +86,6 @@ 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/bkielbasa/cyclop v1.2.1 h1:AeF71HZDob1P2/pRm1so9cd1alZnrpyc4q2uP2l0gJY= github.com/bkielbasa/cyclop v1.2.1/go.mod h1:K/dT/M0FPAiYjBgQGau7tz+3TMh4FWAEqlMhzFWCrgM= -github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= -github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= -github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/blizzy78/varnamelen v0.8.0 h1:oqSblyuQvFsW1hbBHh1zfwrKe3kcSj0rnXkKzsQ089M= github.com/blizzy78/varnamelen v0.8.0/go.mod h1:V9TzQZ4fLJ1DSrjVDfl89H7aMnTvKkApdHeyESmyR7k= github.com/bombsimon/wsl/v4 v4.2.1 h1:Cxg6u+XDWff75SIFFmNsqnIOgob+Q9hG6y/ioKbRFiM= @@ -111,9 +102,6 @@ github.com/catenacyber/perfsprint v0.7.1 h1:PGW5G/Kxn+YrN04cRAZKC+ZuvlVwolYMrIyy github.com/catenacyber/perfsprint v0.7.1/go.mod h1:/wclWYompEyjUD2FuIIDVKNkqz7IgBIWXIH3V0Zol50= github.com/ccojocar/zxcvbn-go v1.0.2 h1:na/czXU8RrhXO4EZme6eQJLR4PzcGsahsBOAwU6I3Vg= github.com/ccojocar/zxcvbn-go v1.0.2/go.mod h1:g1qkXtUSvHP8lhHp5GrSmTz6uWALGRMQdw6Qnz/hi60= -github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= -github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= -github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -130,10 +118,6 @@ github.com/ckaznocha/intrange v0.1.1 h1:gHe4LfqCspWkh8KpJFs20fJz3XRHFBFUV9yI7Itu github.com/ckaznocha/intrange v0.1.1/go.mod h1:RWffCw/vKBwHeOEwWdCikAtY0q4gGt8VhJZEEA5n+RE= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4= -github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec= -github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= -github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/curioswitch/go-reassign v0.2.0 h1:G9UZyOcpk/d7Gd6mqYgd8XYWFMw/znxwGDUstnC9DIo= @@ -141,8 +125,9 @@ github.com/curioswitch/go-reassign v0.2.0/go.mod h1:x6OpXuWvgfQaMGks2BZybTngWjT8 github.com/daixiang0/gci v0.12.3 h1:yOZI7VAxAGPQmkb1eqt5g/11SUlwoat1fSblGLmdiQc= github.com/daixiang0/gci v0.12.3/go.mod h1:xtHP9N7AHdNvtRNfcx9gwTDfw7FRJx4bZUsiEfiNNAI= 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/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/denis-tingaikin/go-header v0.5.0 h1:SRdnP5ZKvcO9KKRP1KJrhFR3RrlGuD+42t4429eC9k8= github.com/denis-tingaikin/go-header v0.5.0/go.mod h1:mMenU5bWrok6Wl2UsZjy+1okegmwQ3UgWl4V1D8gjlY= github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= @@ -161,8 +146,6 @@ github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4= github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= -github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= -github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/firefart/nonamedreturns v1.0.4 h1:abzI1p7mAEPYuR4A+VLKn4eNDOycjYo2phmY9sfv40Y= github.com/firefart/nonamedreturns v1.0.4/go.mod h1:TDhe/tjI1BXo48CmYbUduTV7BdIga8MAO/xbKdcVsGI= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= @@ -184,12 +167,8 @@ github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vb github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= -github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= -github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= @@ -226,7 +205,6 @@ github.com/go-xmlfmt/xmlfmt v1.1.2 h1:Nea7b4icn8s57fTx1M5AI4qQT5HEM3rVUO8MuE6g80 github.com/go-xmlfmt/xmlfmt v1.1.2/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -279,8 +257,6 @@ github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed h1:IURFTjxeTfNF github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed/go.mod h1:XLXN8bNw4CGRPaqgl3bv/lhz7bsGPh4/xSaMTbo2vkQ= 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/cel-go v0.17.7 h1:6ebJFzu1xO2n7TLtN+UBqShGBhlD85bhvglh5DpcfqQ= -github.com/google/cel-go v0.17.7/go.mod h1:HXZKzB0LXqer5lHHgfWAnlYwJaQBDKMjxjulNQzhwhY= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -319,9 +295,6 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/gordonklaus/ineffassign v0.1.0 h1:y2Gd/9I7MdY1oEIt+n+rowjBNDcLQq3RsH5hwJd0f9s= github.com/gordonklaus/ineffassign v0.1.0/go.mod h1:Qcp2HIAYhR7mNUVSIxZww3Guk4it82ghYcEXIAk+QT0= -github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gostaticanalysis/analysisutil v0.7.1 h1:ZMCjoue3DtDWQ5WyU16YbjbQEQ3VuzwxALrpYd+HeKk= github.com/gostaticanalysis/analysisutil v0.7.1/go.mod h1:v21E3hY37WKMGSnbsw2S/ojApNWb6C1//mXO48CXbVc= github.com/gostaticanalysis/comment v1.4.1/go.mod h1:ih6ZxzTHLdadaiSnF5WY3dxUoXfXAlTaRzuaNDlSado= @@ -334,11 +307,6 @@ github.com/gostaticanalysis/nilerr v0.1.1/go.mod h1:wZYb6YI5YAxxq0i1+VJbY0s2YONW github.com/gostaticanalysis/testutil v0.3.1-0.20210208050101-bfb5c8eec0e4/go.mod h1:D+FIZ+7OahH3ePw/izIEeH5I06eKs1IKI4Xr64/Am3M= github.com/gostaticanalysis/testutil v0.4.0 h1:nhdCmubdmDF6VEatUNjgUZBJKWRqugoISdUv3PPQgHY= github.com/gostaticanalysis/testutil v0.4.0/go.mod h1:bLIoPefWXrRi/ssLFWX1dx7Repi5x3CuviD3dgAZaBU= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg= github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= @@ -350,8 +318,8 @@ github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUq github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= 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.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM= -github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= +github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= +github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jgautheron/goconst v1.7.1 h1:VpdAG7Ca7yvvJk5n8dMwQhfEZJh95kl/Hl9S1OI5Jkk= @@ -411,8 +379,8 @@ github.com/lufeee/execinquery v1.2.1 h1:hf0Ems4SHcUGBxpGN7Jz78z1ppVkP/837ZlETPCE github.com/lufeee/execinquery v1.2.1/go.mod h1:EC7DrEKView09ocscGHC+apXMIaorh4xqSxS/dy8SbM= github.com/macabu/inamedparam v0.1.3 h1:2tk/phHkMlEL/1GNe/Yf6kkR/hkcUdAEY3L0hjYV1Mk= github.com/macabu/inamedparam v0.1.3/go.mod h1:93FLICAIk/quk7eaPPQvbzihUdn/QkGDwIZEoLtpH6I= -github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= -github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/maratori/testableexamples v1.0.0 h1:dU5alXRrD8WKSjOUnmJZuzdxWOEQ57+7s93SLMxb2vI= @@ -431,16 +399,14 @@ github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= -github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= github.com/mgechev/revive v1.3.7 h1:502QY0vQGe9KtYJ9FpxMz9rL+Fc/P13CI5POL4uHCcE= github.com/mgechev/revive v1.3.7/go.mod h1:RJ16jUbF0OWC3co/+XTxmFNgEpUPwnnA0BRllX2aDNA= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/hashstructure v1.1.0 h1:P6P1hdjqAAknpY/M1CGipelZgp+4y9ja9kmUZPXP+H0= +github.com/mitchellh/hashstructure v1.1.0/go.mod h1:xUDAozZz0Wmdiufv0uyhnHkUTN6/6d8ulp4AwfLKrmA= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= -github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/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= @@ -454,8 +420,8 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= -github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/nais/liberator v0.0.0-20240412093323-c3d6aeb3b6d3 h1:7MP0yYPgNv40K08+hIE2Hq0P52CfcbkbPcwj8lxcQlA= +github.com/nais/liberator v0.0.0-20240412093323-c3d6aeb3b6d3/go.mod h1:nicVzoCtO4JpW73Vo6/HWRWOLI09EcgoPk4ixei6tfI= github.com/nakabonne/nestif v0.3.1 h1:wm28nZjhQY5HyYPx+weN3Q65k6ilSBxDb8v5S81B81U= github.com/nakabonne/nestif v0.3.1/go.mod h1:9EtoZochLn5iUprVDmDjqGKPofoUEBL8U4Ngq6aY7OE= github.com/nishanths/exhaustive v0.12.0 h1:vIY9sALmw6T/yxiASewa4TQcFsVYZQQRUQJhKRf3Swg= @@ -477,16 +443,15 @@ github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJ github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= -github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= -github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml/v2 v2.2.0 h1:QLgLl2yMN7N+ruc31VynXs1vhMZa7CeHHejIeBAsoHo= github.com/pelletier/go-toml/v2 v2.2.0/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/polyfloyd/go-errorlint v1.4.8 h1:jiEjKDH33ouFktyez7sckv6pHWif9B7SuS8cutDXFHw= github.com/polyfloyd/go-errorlint v1.4.8/go.mod h1:NNCxFcFjZcw3xNjVdCchERkEM6Oz7wta2XJVxRftwO4= github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= @@ -496,8 +461,6 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk= -github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA= github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU= github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= @@ -510,8 +473,6 @@ github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM= -github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY= github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE= github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= @@ -537,6 +498,10 @@ github.com/ryancurrah/gomodguard v1.3.1 h1:fH+fUg+ngsQO0ruZXXHnA/2aNllWA1whly4a6 github.com/ryancurrah/gomodguard v1.3.1/go.mod h1:DGFHzEhi6iJ0oIDfMuo3TgrS+L9gZvrEfmjjuelnRU0= github.com/ryanrolds/sqlclosecheck v0.5.1 h1:dibWW826u0P8jNLsLN+En7+RqWWTYrjCB9fJfSfdyCU= github.com/ryanrolds/sqlclosecheck v0.5.1/go.mod h1:2g3dUjoS6AL4huFdv6wn55WpLIDjY7ZgUR4J8HOO/XQ= +github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= +github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= +github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= +github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= github.com/sanposhiho/wastedassign/v2 v2.0.7 h1:J+6nrY4VW+gC9xFzUc+XjPD3g3wF3je/NsJFwFK7Uxc= github.com/sanposhiho/wastedassign/v2 v2.0.7/go.mod h1:KyZ0MWTwxxBmfwn33zh3k1dmsbF2ud9pAAGfoLfjhtI= github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4= @@ -562,26 +527,24 @@ github.com/sivchari/tenv v1.7.1 h1:PSpuD4bu6fSmtWMxSGWcvqUUgIn7k3yOJhOIzVWn8Ak= github.com/sivchari/tenv v1.7.1/go.mod h1:64yStXKSOxDfX47NlhVwND4dHwfZDdbp2Lyl018Icvg= github.com/sonatard/noctx v0.0.2 h1:L7Dz4De2zDQhW8S0t+KUjY0MAQJd6SgVwhzNIc4ok00= github.com/sonatard/noctx v0.0.2/go.mod h1:kzFz+CzWSjQ2OzIm46uJZoXuBpa2+0y3T36U18dWqIo= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= github.com/sourcegraph/go-diff v0.7.0 h1:9uLlrd5T46OXs5qpp8L/MTltk0zikUGi0sNNyCpA8G0= github.com/sourcegraph/go-diff v0.7.0/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs= github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= -github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= -github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= +github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= -github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= -github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag 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.12.0 h1:CZ7eSOd3kZoaYDLbXnmzgQI5RlciuXBMA+18HwHRfZQ= -github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiuKtSI= +github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ= +github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= github.com/ssgreg/nlreturn/v2 v2.2.1 h1:X4XDI7jstt3ySqGU86YGAURbxw3oTDPK9sPEi6YEwQ0= github.com/ssgreg/nlreturn/v2 v2.2.1/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRkkxBiELzh2I= github.com/stbenjam/no-sprintf-host-port v0.1.1 h1:tYugd/yrm1O0dV+ThCbaKZh195Dfm07ysF0U6JQXczc= github.com/stbenjam/no-sprintf-host-port v0.1.1/go.mod h1:TLhvtIvONRzdmkFiio4O8LHsN9N74I+PhRquPsxpL0I= -github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU= -github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= @@ -600,8 +563,8 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs= -github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/t-yuki/gocover-cobertura v0.0.0-20180217150009-aaee18c8195c h1:+aPplBwWcHBo6q9xrfWdMrT9o4kltkmmvpemgIjep/8= github.com/t-yuki/gocover-cobertura v0.0.0-20180217150009-aaee18c8195c/go.mod h1:SbErYREK7xXdsRiigaQiQkI9McGRzYMvlKYaP3Nimdk= github.com/tdakkota/asciicheck v0.2.0 h1:o8jvnUANo0qXtnslk2d3nMKTFNlOnJjRrNcj0j9qkHM= @@ -649,35 +612,11 @@ go-simpler.org/musttag v0.9.0 h1:Dzt6/tyP9ONr5g9h9P3cnYWCxeBFRkd0uJL/w+1Mxos= go-simpler.org/musttag v0.9.0/go.mod h1:gA9nThnalvNSKpEoyp3Ko4/vCX2xTpqKoUtNqXOnVR4= go-simpler.org/sloglint v0.5.0 h1:2YCcd+YMuYpuqthCgubcF5lBSjb6berc5VMOYUHKrpY= go-simpler.org/sloglint v0.5.0/go.mod h1:EUknX5s8iXqf18KQxKnaBHUPVriiPnOrPjjJcsaTcSQ= -go.etcd.io/etcd/api/v3 v3.5.10 h1:szRajuUUbLyppkhs9K6BRtjY37l66XQQmw7oZRANE4k= -go.etcd.io/etcd/api/v3 v3.5.10/go.mod h1:TidfmT4Uycad3NM/o25fG3J07odo4GBB9hoxaodFCtI= -go.etcd.io/etcd/client/pkg/v3 v3.5.10 h1:kfYIdQftBnbAq8pUWFXfpuuxFSKzlmM5cSn76JByiT0= -go.etcd.io/etcd/client/pkg/v3 v3.5.10/go.mod h1:DYivfIviIuQ8+/lCq4vcxuseg2P2XbHygkKwFo9fc8U= -go.etcd.io/etcd/client/v3 v3.5.10 h1:W9TXNZ+oB3MCd/8UjxHTWK5J9Nquw9fQBLJd5ne5/Ao= -go.etcd.io/etcd/client/v3 v3.5.10/go.mod h1:RVeBnDz2PUEZqTpgqwAtUd8nAPf5kjyFyND7P1VkOKc= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0 h1:UNQQKPfTDe1J81ViolILjTKPr9WetKW6uei2hFgJmFs= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0/go.mod h1:r9vWsPS/3AQItv3OSlEJ/E4mbrhUbbw18meOjArPtKQ= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 h1:sv9kVfal0MK0wBMCOGr+HeJm9v803BkJxGrk2au7j08= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0/go.mod h1:SK2UL73Zy1quvRPonmOmRDiWk1KBV3LyIeeIxcEApWw= -go.opentelemetry.io/otel v1.22.0 h1:xS7Ku+7yTFvDfDraDIJVpw7XPyuHlB9MCiqqX5mcJ6Y= -go.opentelemetry.io/otel v1.22.0/go.mod h1:eoV4iAi3Ea8LkAEI9+GFT44O6T/D0GWAVFyZVCC6pMI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 h1:Mne5On7VWdx7omSrSSZvM4Kw7cS7NQkOOmLcgscI51U= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0/go.mod h1:IPtUMKL4O3tH5y+iXVyAXqpAwMuzC1IrxVS81rummfE= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0 h1:3d+S281UTjM+AbF31XSOYn1qXn3BgIdWl8HNEpx08Jk= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0/go.mod h1:0+KuTDyKL4gjKCF75pHOX4wuzYDUZYfAQdSu43o+Z2I= -go.opentelemetry.io/otel/metric v1.22.0 h1:lypMQnGyJYeuYPhOM/bgjbFM6WE44W1/T45er4d8Hhg= -go.opentelemetry.io/otel/metric v1.22.0/go.mod h1:evJGjVpZv0mQ5QBRJoBF64yMuOf4xCWdXjK8pzFvliY= -go.opentelemetry.io/otel/sdk v1.19.0 h1:6USY6zH+L8uMH8L3t1enZPR3WFEmSTADlqldyHtJi3o= -go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A= -go.opentelemetry.io/otel/trace v1.22.0 h1:Hg6pPujv0XG9QaVbGOBVHunyuLcCC3jN7WEhPx83XD0= -go.opentelemetry.io/otel/trace v1.22.0/go.mod h1:RbbHXVqKES9QhzZq/fE5UnOSILqRt40a21sPw2He1xo= -go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= -go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8= go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -694,8 +633,6 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= -golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -740,8 +677,8 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91 golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic= -golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -780,8 +717,8 @@ golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= -golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= 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-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -803,8 +740,8 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= -golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -858,16 +795,16 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= -golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= +golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= +golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 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= @@ -949,8 +886,8 @@ golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw= -golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc= +golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY= +golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1010,12 +947,6 @@ google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7Fc google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20240116215550-a9fa1716bcac h1:ZL/Teoy/ZGnzyrqK/Optxxp2pmVh+fmJ97slxSRyzUg= -google.golang.org/genproto v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:+Rvu7ElI+aLzyDQhpHMFMMltsD6m7nqpuWDd2CwJw3k= -google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe h1:0poefMBYvYbs7g5UkjS6HcxBPaTRAmznle9jnxYoAI8= -google.golang.org/genproto/googleapis/api v0.0.0-20240125205218-1f4bbc51befe/go.mod h1:4jWUdICTdgc3Ibxmr8nAJiiLHwQBY0UI0XZcEMaFKaA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac h1:nUQEQmH/csSvFECKYRv6HWEyypysidKl2I6Qpsglq/0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:daQN87bsDqDoe316QbbvX60nMoJQa4r6Ds0ZuoAe5yA= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -1028,8 +959,6 @@ google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKa google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.61.0 h1:TOvOcuXn30kRao+gfcvsebNEa5iZIiLkisYEkf7R7o0= -google.golang.org/grpc v1.61.0/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -1055,8 +984,6 @@ 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.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= -gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -1079,28 +1006,20 @@ honnef.co/go/tools v0.4.7 h1:9MDAWxMoSnB6QoSqiVr7P5mtkT9pOc1kSxchzPCnqJs= honnef.co/go/tools v0.4.7/go.mod h1:+rnGS1THNh8zMwnd2oVOTL9QF6vmfyG6ZXBULae2uc0= k8s.io/api v0.29.3 h1:2ORfZ7+bGC3YJqGpV0KSDDEVf8hdGQ6A03/50vj8pmw= k8s.io/api v0.29.3/go.mod h1:y2yg2NTyHUUkIoTC+phinTnEa3KFM6RZ3szxt014a80= -k8s.io/apiextensions-apiserver v0.29.2 h1:UK3xB5lOWSnhaCk0RFZ0LUacPZz9RY4wi/yt2Iu+btg= -k8s.io/apiextensions-apiserver v0.29.2/go.mod h1:aLfYjpA5p3OwtqNXQFkhJ56TB+spV8Gc4wfMhUA3/b8= k8s.io/apiextensions-apiserver v0.29.3 h1:9HF+EtZaVpFjStakF4yVufnXGPRppWFEQ87qnO91YeI= k8s.io/apiextensions-apiserver v0.29.3/go.mod h1:po0XiY5scnpJfFizNGo6puNU6Fq6D70UJY2Cb2KwAVc= k8s.io/apimachinery v0.29.3 h1:2tbx+5L7RNvqJjn7RIuIKu9XTsIZ9Z5wX2G22XAa5EU= k8s.io/apimachinery v0.29.3/go.mod h1:hx/S4V2PNW4OMg3WizRrHutyB5la0iCUbZym+W0EQIU= -k8s.io/apiserver v0.29.3 h1:xR7ELlJ/BZSr2n4CnD3lfA4gzFivh0wwfNfz9L0WZcE= -k8s.io/apiserver v0.29.3/go.mod h1:hrvXlwfRulbMbBgmWRQlFru2b/JySDpmzvQwwk4GUOs= k8s.io/client-go v0.29.3 h1:R/zaZbEAxqComZ9FHeQwOh3Y1ZUs7FaHKZdQtIc2WZg= k8s.io/client-go v0.29.3/go.mod h1:tkDisCvgPfiRpxGnOORfkljmS+UrW+WtXAy2fTvXJB0= -k8s.io/component-base v0.29.2 h1:lpiLyuvPA9yV1aQwGLENYyK7n/8t6l3nn3zAtFTJYe8= -k8s.io/component-base v0.29.2/go.mod h1:BfB3SLrefbZXiBfbM+2H1dlat21Uewg/5qtKOl8degM= k8s.io/component-base v0.29.3 h1:Oq9/nddUxlnrCuuR2K/jp6aflVvc0uDvxMzAWxnGzAo= k8s.io/component-base v0.29.3/go.mod h1:Yuj33XXjuOk2BAaHsIGHhCKZQAgYKhqIxIjIr2UXYio= -k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0= -k8s.io/klog/v2 v2.110.1/go.mod h1:YGtd1984u+GgbuZ7e08/yBuAfKLSO0+uR1Fhi6ExXjo= -k8s.io/kms v0.29.3 h1:ReljsAUhYlm2spdT4yXmY+9a8x8dc/OT4mXvwQPPteQ= -k8s.io/kms v0.29.3/go.mod h1:TBGbJKpRUMk59neTMDMddjIDL+D4HuFUbpuiuzmOPg0= +k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= +k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00 h1:aVUu9fTY98ivBPKR9Y5w/AuzbMm96cd3YHRTU83I780= k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00/go.mod h1:AsvuZPBlUDVuCdzJ87iajxtXuR9oktsTctW/R9wwouA= -k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= -k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/utils v0.0.0-20240310230437-4693a0247e57 h1:gbqbevonBh57eILzModw6mrkbwM0gQBEuevE/AaBsHY= +k8s.io/utils v0.0.0-20240310230437-4693a0247e57/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= mvdan.cc/gofumpt v0.6.0 h1:G3QvahNDmpD+Aek/bNOLrFR2XC6ZAdo62dZu65gmwGo= mvdan.cc/gofumpt v0.6.0/go.mod h1:4L0wf+kgIPZtcCWXynNS2e6bhmj73umwnuXSZarixzA= mvdan.cc/unparam v0.0.0-20240104100049-c549a3470d14 h1:zCr3iRRgdk5eIikZNDphGcM6KGVTx3Yu+/Uu9Es254w= @@ -1108,8 +1027,6 @@ mvdan.cc/unparam v0.0.0-20240104100049-c549a3470d14/go.mod h1:ZzZjEpJDOmx8TdVU6u 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.28.0 h1:TgtAeesdhpm2SGwkQasmbeqDo8th5wOBA5h/AjTKA4I= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.28.0/go.mod h1:VHVDI/KrK4fjnV61bE2g3sA7tiETLn8sooImelsCx3Y= sigs.k8s.io/controller-runtime v0.17.3 h1:65QmN7r3FWgTxDMz9fvGnO1kbf2nu+acg9p2R9oYYYk= sigs.k8s.io/controller-runtime v0.17.3/go.mod h1:N0jpP5Lo7lMTF9aL56Z/B2oWBJjey6StQM0jRbKQXtY= sigs.k8s.io/controller-runtime/tools/setup-envtest v0.0.0-20240405143037-c25fe2f5ca0f h1:3gr+fQrs1ez+O5Qsf9MbwPas9WDo5olxuGk7E8x4hO4= diff --git a/internal/controller/common.go b/internal/controller/common.go new file mode 100644 index 0000000..2b64a98 --- /dev/null +++ b/internal/controller/common.go @@ -0,0 +1,31 @@ +package controller + +import ( + "errors" + "fmt" +) + +const ( + deploymentCorrelationIdKey = "nais.io/deploymentCorrelationID" + managedByKey = "app.kubernetes.io/managed-by" + typeKey = "type" + appKey = "app" + teamKey = "team" + + sqeletorFqdnId = "sqeletor.nais.io" +) + +var ( + errTemporaryFailure = errors.New("temporary failure") + errPermanentFailure = errors.New("permanent failure") + errNotManaged = fmt.Errorf("not managed by controller: %w", errPermanentFailure) + errMultipleOwners = fmt.Errorf("multiple owners: %w", errPermanentFailure) +) + +func temporaryFailureError(err error) error { + return fmt.Errorf("%w: %w", errTemporaryFailure, err) +} + +func permanentFailureError(err error) error { + return fmt.Errorf("%w: %w", errPermanentFailure, err) +} diff --git a/internal/controller/sqlsslcert_controller.go b/internal/controller/sqlsslcert_controller.go index 941c806..08fda5a 100644 --- a/internal/controller/sqlsslcert_controller.go +++ b/internal/controller/sqlsslcert_controller.go @@ -21,17 +21,9 @@ import ( ) const ( - deploymentCorrelationIdKey = "nais.io/deploymentCorrelationID" - managedByKey = "app.kubernetes.io/managed-by" - typeKey = "type" - appKey = "app" - teamKey = "team" - certKey = "cert.pem" privateKeyKey = "private-key.pem" serverCaCertKey = "server-ca-cert.pem" - - sqeletorFqdnId = "sqeletor.nais.io" ) var ( @@ -40,11 +32,7 @@ var ( Help: "Number of requeues for SQLSSLCert", }) - errTemporaryFailure = errors.New("temporary failure") - errPermanentFailure = errors.New("permanent failure") - errNotManaged = fmt.Errorf("not managed by controller: %w", errPermanentFailure) - errOwnedByOtherCert = fmt.Errorf("owned by other cert: %w", errPermanentFailure) - errMultipleOwners = fmt.Errorf("multiple owners: %w", errPermanentFailure) + errOwnedByOther = fmt.Errorf("owned by other cert: %w", errPermanentFailure) ) func init() { @@ -134,7 +122,7 @@ func (r *SQLSSLCertReconciler) reconcileSQLSSLCert(ctx context.Context, req ctrl if secret.OwnerReferences[0].APIVersion != ownerReference.APIVersion || secret.OwnerReferences[0].Kind != ownerReference.Kind || secret.OwnerReferences[0].Name != ownerReference.Name { - return fmt.Errorf("secret %s in namespace %s has different owner reference: %w", secret.Name, secret.Namespace, errOwnedByOtherCert) + return fmt.Errorf("secret %s in namespace %s has different owner reference: %w", secret.Name, secret.Namespace, errOwnedByOther) } secret.Labels[typeKey] = sqeletorFqdnId @@ -167,7 +155,3 @@ func (r *SQLSSLCertReconciler) SetupWithManager(mgr ctrl.Manager) error { For(&v1beta1.SQLSSLCert{}). Complete(r) } - -func temporaryFailureError(err error) error { - return fmt.Errorf("%w: %w", errTemporaryFailure, err) -} diff --git a/internal/controller/sqluser_controller.go b/internal/controller/sqluser_controller.go new file mode 100644 index 0000000..e8b6db3 --- /dev/null +++ b/internal/controller/sqluser_controller.go @@ -0,0 +1,248 @@ +package controller + +import ( + "context" + "crypto/rand" + "encoding/base64" + "errors" + "fmt" + "net" + "net/url" + "path/filepath" + "time" + + nais_io_v1alpha1 "github.com/nais/liberator/pkg/apis/nais.io/v1alpha1" + "github.com/prometheus/client_golang/prometheus" + core_v1 "k8s.io/api/core/v1" + meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "sigs.k8s.io/controller-runtime/pkg/metrics" + + "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/clients/generated/apis/sql/v1beta1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" +) + +const () + +var ( + userRequeuesMetric = prometheus.NewCounter(prometheus.CounterOpts{ + Name: "sqluser_requeues", + Help: "Number of requeues for SQLUser", + }) + + errOwnedByOtherUser = fmt.Errorf("owned by other user: %w", errPermanentFailure) +) + +func init() { + metrics.Registry.MustRegister(requeuesMetric) +} + +// SQLUserReconciler reconciles a SQLUser object +type SQLUserReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +func (r *SQLUserReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + logger := log.FromContext(ctx) + logger.Info("Reconciling SQLUser") + + err := r.reconcileSQLUser(ctx, req) + if errors.Is(err, errTemporaryFailure) { + userRequeuesMetric.Inc() + logger.Error(err, "requeueing after temporary failure") + return ctrl.Result{ + RequeueAfter: time.Minute, + }, nil + } + return ctrl.Result{}, err +} + +func validateSecretKeyRef(sqlUser *v1beta1.SQLUser) error { + if sqlUser.Spec.Password == nil || + sqlUser.Spec.Password.ValueFrom == nil || + sqlUser.Spec.Password.ValueFrom.SecretKeyRef == nil || + sqlUser.Spec.Password.ValueFrom.SecretKeyRef.Key == "" || + sqlUser.Spec.Password.ValueFrom.SecretKeyRef.Name == "" { + return fmt.Errorf("password secret ref not properly set") + } + return nil +} + +func validateOwnership(ownerReference meta_v1.OwnerReference, secret *core_v1.Secret) error { + // if we don't manage this resource, error out + if secret.Labels[managedByKey] != sqeletorFqdnId { + return fmt.Errorf("secret %s in namespace %s is not managed by us: %w", secret.Name, secret.Namespace, errNotManaged) + } + + if len(secret.OwnerReferences) > 1 { + return fmt.Errorf("secret %s in namespace %s has multiple owner references: %w", secret.Name, secret.Namespace, errMultipleOwners) + } + + if secret.OwnerReferences[0].APIVersion != ownerReference.APIVersion || + secret.OwnerReferences[0].Kind != ownerReference.Kind || + secret.OwnerReferences[0].Name != ownerReference.Name { + return fmt.Errorf("secret %s in namespace %s has different owner reference: %w", secret.Name, secret.Namespace, errOwnedByOther) + } + + return nil +} + +func (r *SQLUserReconciler) getInstancePrivateIP(ctx context.Context, key types.NamespacedName) (string, error) { + sqlInstance := &v1beta1.SQLInstance{} + if err := r.Client.Get(ctx, key, sqlInstance); err != nil { + return "", temporaryFailureError(fmt.Errorf("failed to get SQLUser: %w", err)) + } + if sqlInstance.Spec.Settings.IpConfiguration.PrivateNetworkRef == nil { + return "", permanentFailureError(fmt.Errorf("referenced sql instance is not configured for private ip")) + } + if sqlInstance.Status.PrivateIpAddress == nil || *sqlInstance.Status.PrivateIpAddress == "" { + return "", temporaryFailureError(fmt.Errorf("referenced sql instance does not have a private ip")) + } + return *sqlInstance.Status.PrivateIpAddress, nil +} + +func (r *SQLUserReconciler) reconcileSQLUser(ctx context.Context, req ctrl.Request) error { + logger := log.FromContext(ctx) + + sqlUser := &v1beta1.SQLUser{} + if err := r.Client.Get(ctx, req.NamespacedName, sqlUser); err != nil { + if apierrors.IsNotFound(err) { + logger.Info("SQLUser not found, aborting reconcile") + return nil + } + return temporaryFailureError(fmt.Errorf("failed to get SQLUser: %w", err)) + } + + if err := validateSecretKeyRef(sqlUser); err != nil { + return permanentFailureError(err) + } + secretName := sqlUser.Spec.Password.ValueFrom.SecretKeyRef.Name + secretKey := sqlUser.Spec.Password.ValueFrom.SecretKeyRef.Key + logger = logger.WithValues("secretName", secretName, "secretKey", secretKey) + + envVarPrefix, ok := sqlUser.Annotations["sqeletor.nais.io/env-var-prefix"] + if !ok { + return fmt.Errorf("env var prefix annotation not found") + } + dbName, ok := sqlUser.Annotations["sqeletor.nais.io/database-name"] + if !ok { + return fmt.Errorf("database name annotation not found") + } + + logger = logger.WithValues("envVarPrefix", envVarPrefix, "databaseName", dbName) + + instanceKey := types.NamespacedName{Name: sqlUser.Spec.InstanceRef.Name, Namespace: sqlUser.Spec.InstanceRef.Namespace} + instanceIP, err := r.getInstancePrivateIP(ctx, instanceKey) + if err != nil { + return err + } + + secret := &core_v1.Secret{ObjectMeta: meta_v1.ObjectMeta{Namespace: req.Namespace, Name: secretName}} + op, err := controllerutil.CreateOrUpdate(ctx, r.Client, secret, func() error { + if secret.Labels == nil { + secret.Labels = make(map[string]string) + } + if secret.Annotations == nil { + secret.Annotations = make(map[string]string) + } + + ownerReference := meta_v1.OwnerReference{ + APIVersion: sqlUser.GetObjectKind().GroupVersionKind().GroupVersion().String(), + Kind: sqlUser.GetObjectKind().GroupVersionKind().Kind, + Name: sqlUser.GetName(), + UID: sqlUser.GetUID(), + } + if err := validateOwnership(ownerReference, secret); err != nil { + return err + } + + // if new resource, add owner reference and managed-by label + if secret.CreationTimestamp.IsZero() { + secret.OwnerReferences = []meta_v1.OwnerReference{ownerReference} + secret.Labels[managedByKey] = sqeletorFqdnId + } + + secret.Labels[typeKey] = sqeletorFqdnId + secret.Labels[appKey] = sqlUser.Labels[appKey] + secret.Labels[teamKey] = sqlUser.Labels[teamKey] + + secret.Annotations[deploymentCorrelationIdKey] = sqlUser.Annotations[deploymentCorrelationIdKey] + + password := generatePassword() + prefixedPasswordKey := envVarPrefix + "_PASSWORD" + if secretKey != prefixedPasswordKey { + return permanentFailureError(fmt.Errorf("secret key %s does not match expected key %s", secretKey, prefixedPasswordKey)) + } + + postgresPort := "5432" + + rootCertPath := filepath.Join(nais_io_v1alpha1.DefaultSqeletorMountPath, serverCaCertKey) + certPath := filepath.Join(nais_io_v1alpha1.DefaultSqeletorMountPath, certKey) + privateKeyPath := filepath.Join(nais_io_v1alpha1.DefaultSqeletorMountPath, privateKeyKey) + + queries := url.Values{} + queries.Add("sslmode", "verify-ca") + queries.Add("sslcert", certPath) + queries.Add("sslkey", privateKeyPath) + queries.Add("sslrootcert", rootCertPath) + googleSQLPostgresURL := url.URL{ + Scheme: "postgresql", + Path: dbName, + User: url.UserPassword(sqlUser.Name, password), + Host: net.JoinHostPort(instanceIP, postgresPort), + RawQuery: queries.Encode(), + } + + secret.StringData = map[string]string{ + prefixedPasswordKey: password, + envVarPrefix + "_HOST": instanceIP, + envVarPrefix + "_PORT": postgresPort, + envVarPrefix + "_DATABASE": dbName, + envVarPrefix + "_USERNAME": sqlUser.Name, + envVarPrefix + "_URL": googleSQLPostgresURL.String(), + + "PGSSLMODE": "verify-ca", + "PGSSLROOTCERT": rootCertPath, + "PGSSLCERT": certPath, + "PGSSLKEY": privateKeyPath, + "PGHOSTADDR": instanceIP, + "PGPORT": postgresPort, + "PGPASSWORD": password, + "PGDATABASE": dbName, + "PGUSER": sqlUser.Name, + } + + return nil + }) + + if err != nil { + if errors.Is(err, errPermanentFailure) { + return err + } + return temporaryFailureError(err) + } + + logger.Info("Secret reconciled", "operation", op) + return nil +} + +func (r *SQLUserReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&v1beta1.SQLUser{}). + Complete(r) +} + +func generatePassword() string { + buf := make([]byte, 32) + _, err := rand.Read(buf) + if err != nil { + panic(err) + } + return base64.URLEncoding.WithPadding(base64.NoPadding).EncodeToString(buf) +} diff --git a/internal/controller/sqluser_controller_test.go b/internal/controller/sqluser_controller_test.go new file mode 100644 index 0000000..38b9265 --- /dev/null +++ b/internal/controller/sqluser_controller_test.go @@ -0,0 +1,248 @@ +package controller + +import ( + "context" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + core_v1 "k8s.io/api/core/v1" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/utils/ptr" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + "time" + + "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/clients/generated/apis/sql/v1beta1" + meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/kubernetes/scheme" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +var _ = Describe("SQLSSLCert Controller", func() { + ctx := context.Background() + + Context("When reconciling a resource", func() { + var clientBuilder *fake.ClientBuilder + var k8sClient client.Client + var controller *SQLSSLCertReconciler + + BeforeEach(func() { + utilruntime.Must(v1beta1.AddToScheme(scheme.Scheme)) + clientBuilder = fake.NewClientBuilder(). + WithScheme(scheme.Scheme) + }) + + When("the resource exists", func() { + BeforeEach(func() { + existingCert := &v1beta1.SQLSSLCert{ + TypeMeta: meta_v1.TypeMeta{ + APIVersion: "sql.cnrm.cloud.google.com/v1beta1", + Kind: "SQLSSLCert", + }, + ObjectMeta: meta_v1.ObjectMeta{ + Name: "test-cert", + Namespace: "default", + Annotations: map[string]string{ + "sqeletor.nais.io/secret-name": "sqeletor-test-secret", + }, + }, + Spec: v1beta1.SQLSSLCertSpec{}, + Status: v1beta1.SQLSSLCertStatus{ + Cert: ptr.To("dummy-cert"), + PrivateKey: ptr.To("dummy-private-key"), + ServerCaCert: ptr.To("dummy-server-ca-cert"), + }, + } + + clientBuilder = clientBuilder.WithObjects(existingCert) + }) + + When("no secret exists", func() { + BeforeEach(func() { + k8sClient = clientBuilder.Build() + controller = &SQLSSLCertReconciler{Scheme: scheme.Scheme, Client: k8sClient} + }) + + It("should successfully reconcile the resource", func() { + req := ctrl.Request{NamespacedName: types.NamespacedName{Name: "test-cert", Namespace: "default"}} + result, err := controller.Reconcile(ctx, req) + + Expect(err).ToNot(HaveOccurred()) + Expect(result).To(Equal(ctrl.Result{})) + }) + + It("should create a secret containing the certificate data", func() { + req := ctrl.Request{NamespacedName: types.NamespacedName{Name: "test-cert", Namespace: "default"}} + _, err := controller.Reconcile(ctx, req) + Expect(err).ToNot(HaveOccurred()) + + secret := &core_v1.Secret{} + err = k8sClient.Get(ctx, types.NamespacedName{Name: "sqeletor-test-secret", Namespace: "default"}, secret) + Expect(err).ToNot(HaveOccurred()) + + Expect(secret.StringData).To(HaveKeyWithValue(certKey, "dummy-cert")) + Expect(secret.StringData).To(HaveKeyWithValue(privateKeyKey, "dummy-private-key")) + Expect(secret.StringData).To(HaveKeyWithValue(serverCaCertKey, "dummy-server-ca-cert")) + }) + + It("should set owner reference and managed by", func() { + req := ctrl.Request{NamespacedName: types.NamespacedName{Name: "test-cert", Namespace: "default"}} + _, err := controller.Reconcile(ctx, req) + Expect(err).ToNot(HaveOccurred()) + + secret := &core_v1.Secret{} + err = k8sClient.Get(ctx, types.NamespacedName{Name: "sqeletor-test-secret", Namespace: "default"}, secret) + Expect(err).ToNot(HaveOccurred()) + + Expect(secret.OwnerReferences).To(HaveLen(1)) + Expect(secret.OwnerReferences[0].Name).To(Equal("test-cert")) + Expect(secret.OwnerReferences[0].Kind).To(Equal("SQLSSLCert")) + Expect(secret.OwnerReferences[0].APIVersion).To(Equal("sql.cnrm.cloud.google.com/v1beta1")) + + Expect(secret.Labels[managedByKey]).To(Equal(sqeletorFqdnId)) + }) + }) + + When("a secret already exists that is not owned or managed", func() { + BeforeEach(func() { + existingSecret := &core_v1.Secret{ + ObjectMeta: meta_v1.ObjectMeta{ + Name: "sqeletor-test-secret", + Namespace: "default", + CreationTimestamp: meta_v1.Time{ + Time: time.Now(), + }, + }, + } + k8sClient = clientBuilder.WithObjects(existingSecret).Build() + controller = &SQLSSLCertReconciler{Scheme: scheme.Scheme, Client: k8sClient} + }) + + It("should not update the secret with the certificate data", func() { + req := ctrl.Request{NamespacedName: types.NamespacedName{Name: "test-cert", Namespace: "default"}} + _, err := controller.Reconcile(ctx, req) + Expect(err).To(HaveOccurred()) + + secret := &core_v1.Secret{} + err = k8sClient.Get(ctx, types.NamespacedName{Name: "sqeletor-test-secret", Namespace: "default"}, secret) + Expect(err).ToNot(HaveOccurred()) + + Expect(secret.StringData).To(BeEmpty()) + }) + + It("should not update owner reference or managed by", func() { + req := ctrl.Request{NamespacedName: types.NamespacedName{Name: "test-cert", Namespace: "default"}} + _, err := controller.Reconcile(ctx, req) + Expect(err).To(HaveOccurred()) + + secret := &core_v1.Secret{} + err = k8sClient.Get(ctx, types.NamespacedName{Name: "sqeletor-test-secret", Namespace: "default"}, secret) + Expect(err).ToNot(HaveOccurred()) + + Expect(secret.OwnerReferences).To(HaveLen(0)) + Expect(secret.Labels[managedByKey]).To(BeEmpty()) + }) + }) + + When("a secret already exists that is owned and managed by correct cert", func() { + BeforeEach(func() { + existingSecret := &core_v1.Secret{ + ObjectMeta: meta_v1.ObjectMeta{ + Name: "sqeletor-test-secret", + Namespace: "default", + CreationTimestamp: meta_v1.Time{ + Time: time.Now(), + }, + Labels: map[string]string{ + managedByKey: sqeletorFqdnId, + }, + OwnerReferences: []meta_v1.OwnerReference{ + { + APIVersion: "sql.cnrm.cloud.google.com/v1beta1", + Kind: "SQLSSLCert", + Name: "test-cert", + }, + }, + }, + } + k8sClient = clientBuilder.WithObjects(existingSecret).Build() + controller = &SQLSSLCertReconciler{Scheme: scheme.Scheme, Client: k8sClient} + }) + + It("should update the secret with the certificate data", func() { + req := ctrl.Request{NamespacedName: types.NamespacedName{Name: "test-cert", Namespace: "default"}} + _, err := controller.Reconcile(ctx, req) + Expect(err).ToNot(HaveOccurred()) + + secret := &core_v1.Secret{} + err = k8sClient.Get(ctx, types.NamespacedName{Name: "sqeletor-test-secret", Namespace: "default"}, secret) + Expect(err).ToNot(HaveOccurred()) + + Expect(secret.StringData).To(HaveKeyWithValue(certKey, "dummy-cert")) + Expect(secret.StringData).To(HaveKeyWithValue(privateKeyKey, "dummy-private-key")) + Expect(secret.StringData).To(HaveKeyWithValue(serverCaCertKey, "dummy-server-ca-cert")) + }) + }) + + When("a secret already exists that is owned and managed by other cert", func() { + BeforeEach(func() { + existingSecret := &core_v1.Secret{ + ObjectMeta: meta_v1.ObjectMeta{ + Name: "sqeletor-test-secret", + Namespace: "default", + CreationTimestamp: meta_v1.Time{ + Time: time.Now(), + }, + Labels: map[string]string{ + managedByKey: sqeletorFqdnId, + }, + OwnerReferences: []meta_v1.OwnerReference{ + { + APIVersion: "sql.cnrm.cloud.google.com/v1beta1", + Kind: "SQLSSLCert", + Name: "other-cert", + }, + }, + }, + StringData: map[string]string{ + certKey: "existing-cert", + privateKeyKey: "existing-private-key", + serverCaCertKey: "existing-server-ca-cert", + }, + } + k8sClient = clientBuilder.WithObjects(existingSecret).Build() + controller = &SQLSSLCertReconciler{Scheme: scheme.Scheme, Client: k8sClient} + }) + + It("should not update the secret with the certificate data", func() { + req := ctrl.Request{NamespacedName: types.NamespacedName{Name: "test-cert", Namespace: "default"}} + _, err := controller.Reconcile(ctx, req) + Expect(err).To(HaveOccurred()) + + secret := &core_v1.Secret{} + err = k8sClient.Get(ctx, types.NamespacedName{Name: "sqeletor-test-secret", Namespace: "default"}, secret) + Expect(err).ToNot(HaveOccurred()) + + Expect(secret.StringData).To(HaveKeyWithValue(certKey, "existing-cert")) + Expect(secret.StringData).To(HaveKeyWithValue(privateKeyKey, "existing-private-key")) + Expect(secret.StringData).To(HaveKeyWithValue(serverCaCertKey, "existing-server-ca-cert")) + }) + + It("should leave owner reference alone", func() { + req := ctrl.Request{NamespacedName: types.NamespacedName{Name: "test-cert", Namespace: "default"}} + _, err := controller.Reconcile(ctx, req) + Expect(err).To(HaveOccurred()) + + secret := &core_v1.Secret{} + err = k8sClient.Get(ctx, types.NamespacedName{Name: "sqeletor-test-secret", Namespace: "default"}, secret) + Expect(err).ToNot(HaveOccurred()) + + Expect(secret.OwnerReferences).To(HaveLen(1)) + Expect(secret.OwnerReferences[0].Name).To(Equal("other-cert")) + Expect(secret.OwnerReferences[0].Kind).To(Equal("SQLSSLCert")) + Expect(secret.OwnerReferences[0].APIVersion).To(Equal("sql.cnrm.cloud.google.com/v1beta1")) + }) + }) + }) + }) +}) From 4a6ff66413a0850ced63c5dc0fdc8c1293483f46 Mon Sep 17 00:00:00 2001 From: Vegar Sechmann Molvig Date: Mon, 15 Apr 2024 10:01:01 +0200 Subject: [PATCH 2/3] use common validateOwnership func in cert controller Co-authored-by: sindrerh2 --- internal/controller/common.go | 22 ++++++++++++++++++++ internal/controller/sqlsslcert_controller.go | 18 +++------------- internal/controller/sqluser_controller.go | 19 ----------------- 3 files changed, 25 insertions(+), 34 deletions(-) diff --git a/internal/controller/common.go b/internal/controller/common.go index 2b64a98..acba761 100644 --- a/internal/controller/common.go +++ b/internal/controller/common.go @@ -3,6 +3,9 @@ package controller import ( "errors" "fmt" + + core_v1 "k8s.io/api/core/v1" + meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) const ( @@ -29,3 +32,22 @@ func temporaryFailureError(err error) error { func permanentFailureError(err error) error { return fmt.Errorf("%w: %w", errPermanentFailure, err) } + +func validateOwnership(ownerReference meta_v1.OwnerReference, secret *core_v1.Secret) error { + // if we don't manage this resource, error out + if secret.Labels[managedByKey] != sqeletorFqdnId { + return fmt.Errorf("secret %s in namespace %s is not managed by us: %w", secret.Name, secret.Namespace, errNotManaged) + } + + if len(secret.OwnerReferences) > 1 { + return fmt.Errorf("secret %s in namespace %s has multiple owner references: %w", secret.Name, secret.Namespace, errMultipleOwners) + } + + if secret.OwnerReferences[0].APIVersion != ownerReference.APIVersion || + secret.OwnerReferences[0].Kind != ownerReference.Kind || + secret.OwnerReferences[0].Name != ownerReference.Name { + return fmt.Errorf("secret %s in namespace %s has different owner reference: %w", secret.Name, secret.Namespace, errOwnedByOther) + } + + return nil +} diff --git a/internal/controller/sqlsslcert_controller.go b/internal/controller/sqlsslcert_controller.go index 08fda5a..0f5e9ea 100644 --- a/internal/controller/sqlsslcert_controller.go +++ b/internal/controller/sqlsslcert_controller.go @@ -103,6 +103,9 @@ func (r *SQLSSLCertReconciler) reconcileSQLSSLCert(ctx context.Context, req ctrl Name: sqlSslCert.GetName(), UID: sqlSslCert.GetUID(), } + if err := validateOwnership(ownerReference, secret); err != nil { + return err + } // if new resource, add owner reference and managed-by label if secret.CreationTimestamp.IsZero() { @@ -110,21 +113,6 @@ func (r *SQLSSLCertReconciler) reconcileSQLSSLCert(ctx context.Context, req ctrl secret.Labels[managedByKey] = sqeletorFqdnId } - // if we don't manage this resource, error out - if secret.Labels[managedByKey] != sqeletorFqdnId { - return fmt.Errorf("secret %s in namespace %s is not managed by us: %w", secret.Name, secret.Namespace, errNotManaged) - } - - if len(secret.OwnerReferences) > 1 { - return fmt.Errorf("secret %s in namespace %s has multiple owner references: %w", secret.Name, secret.Namespace, errMultipleOwners) - } - - if secret.OwnerReferences[0].APIVersion != ownerReference.APIVersion || - secret.OwnerReferences[0].Kind != ownerReference.Kind || - secret.OwnerReferences[0].Name != ownerReference.Name { - return fmt.Errorf("secret %s in namespace %s has different owner reference: %w", secret.Name, secret.Namespace, errOwnedByOther) - } - secret.Labels[typeKey] = sqeletorFqdnId secret.Labels[appKey] = sqlSslCert.Labels[appKey] secret.Labels[teamKey] = sqlSslCert.Labels[teamKey] diff --git a/internal/controller/sqluser_controller.go b/internal/controller/sqluser_controller.go index e8b6db3..4f46763 100644 --- a/internal/controller/sqluser_controller.go +++ b/internal/controller/sqluser_controller.go @@ -74,25 +74,6 @@ func validateSecretKeyRef(sqlUser *v1beta1.SQLUser) error { return nil } -func validateOwnership(ownerReference meta_v1.OwnerReference, secret *core_v1.Secret) error { - // if we don't manage this resource, error out - if secret.Labels[managedByKey] != sqeletorFqdnId { - return fmt.Errorf("secret %s in namespace %s is not managed by us: %w", secret.Name, secret.Namespace, errNotManaged) - } - - if len(secret.OwnerReferences) > 1 { - return fmt.Errorf("secret %s in namespace %s has multiple owner references: %w", secret.Name, secret.Namespace, errMultipleOwners) - } - - if secret.OwnerReferences[0].APIVersion != ownerReference.APIVersion || - secret.OwnerReferences[0].Kind != ownerReference.Kind || - secret.OwnerReferences[0].Name != ownerReference.Name { - return fmt.Errorf("secret %s in namespace %s has different owner reference: %w", secret.Name, secret.Namespace, errOwnedByOther) - } - - return nil -} - func (r *SQLUserReconciler) getInstancePrivateIP(ctx context.Context, key types.NamespacedName) (string, error) { sqlInstance := &v1beta1.SQLInstance{} if err := r.Client.Get(ctx, key, sqlInstance); err != nil { From d0c7adc9d3ad7844d053cb0aa0b95ae0d4bc9d1c Mon Sep 17 00:00:00 2001 From: Vegar Sechmann Molvig Date: Mon, 15 Apr 2024 11:18:29 +0200 Subject: [PATCH 3/3] add tests for sqluser controller Co-authored-by: Morten Lied Johansen Co-authored-by: sindrerh2 --- internal/controller/sqlsslcert_controller.go | 5 +- internal/controller/sqluser_controller.go | 9 +- .../controller/sqluser_controller_test.go | 469 ++++++++++++------ 3 files changed, 310 insertions(+), 173 deletions(-) diff --git a/internal/controller/sqlsslcert_controller.go b/internal/controller/sqlsslcert_controller.go index 0f5e9ea..d12d687 100644 --- a/internal/controller/sqlsslcert_controller.go +++ b/internal/controller/sqlsslcert_controller.go @@ -103,14 +103,13 @@ func (r *SQLSSLCertReconciler) reconcileSQLSSLCert(ctx context.Context, req ctrl Name: sqlSslCert.GetName(), UID: sqlSslCert.GetUID(), } - if err := validateOwnership(ownerReference, secret); err != nil { - return err - } // if new resource, add owner reference and managed-by label if secret.CreationTimestamp.IsZero() { secret.OwnerReferences = []meta_v1.OwnerReference{ownerReference} secret.Labels[managedByKey] = sqeletorFqdnId + } else if err := validateOwnership(ownerReference, secret); err != nil { + return err } secret.Labels[typeKey] = sqeletorFqdnId diff --git a/internal/controller/sqluser_controller.go b/internal/controller/sqluser_controller.go index 4f46763..acd17c5 100644 --- a/internal/controller/sqluser_controller.go +++ b/internal/controller/sqluser_controller.go @@ -39,7 +39,7 @@ var ( ) func init() { - metrics.Registry.MustRegister(requeuesMetric) + metrics.Registry.MustRegister(userRequeuesMetric) } // SQLUserReconciler reconciles a SQLUser object @@ -77,7 +77,7 @@ func validateSecretKeyRef(sqlUser *v1beta1.SQLUser) error { func (r *SQLUserReconciler) getInstancePrivateIP(ctx context.Context, key types.NamespacedName) (string, error) { sqlInstance := &v1beta1.SQLInstance{} if err := r.Client.Get(ctx, key, sqlInstance); err != nil { - return "", temporaryFailureError(fmt.Errorf("failed to get SQLUser: %w", err)) + return "", temporaryFailureError(fmt.Errorf("failed to get SQLInstance: %w", err)) } if sqlInstance.Spec.Settings.IpConfiguration.PrivateNetworkRef == nil { return "", permanentFailureError(fmt.Errorf("referenced sql instance is not configured for private ip")) @@ -139,14 +139,13 @@ func (r *SQLUserReconciler) reconcileSQLUser(ctx context.Context, req ctrl.Reque Name: sqlUser.GetName(), UID: sqlUser.GetUID(), } - if err := validateOwnership(ownerReference, secret); err != nil { - return err - } // if new resource, add owner reference and managed-by label if secret.CreationTimestamp.IsZero() { secret.OwnerReferences = []meta_v1.OwnerReference{ownerReference} secret.Labels[managedByKey] = sqeletorFqdnId + } else if err := validateOwnership(ownerReference, secret); err != nil { + return err } secret.Labels[typeKey] = sqeletorFqdnId diff --git a/internal/controller/sqluser_controller_test.go b/internal/controller/sqluser_controller_test.go index 38b9265..f865ae9 100644 --- a/internal/controller/sqluser_controller_test.go +++ b/internal/controller/sqluser_controller_test.go @@ -2,14 +2,18 @@ package controller import ( "context" + "path/filepath" + "time" + + nais_io_v1alpha1 "github.com/nais/liberator/pkg/apis/nais.io/v1alpha1" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" core_v1 "k8s.io/api/core/v1" utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/utils/ptr" "sigs.k8s.io/controller-runtime/pkg/client/fake" - "time" + "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/clients/generated/apis/k8s/v1alpha1" "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/clients/generated/apis/sql/v1beta1" meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" @@ -18,13 +22,24 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" ) -var _ = Describe("SQLSSLCert Controller", func() { +var _ = Describe("SQLUser Controller", func() { ctx := context.Background() Context("When reconciling a resource", func() { var clientBuilder *fake.ClientBuilder var k8sClient client.Client - var controller *SQLSSLCertReconciler + var controller *SQLUserReconciler + + const ( + instanceIP = "10.10.10.10" + dbName = "test-db" + userName = "test-user" + envVarPrefix = "PREFIX" + secretName = "test-secret-env" + secretKey = "PREFIX_PASSWORD" + instanceName = "test-instance" + namespace = "default" + ) BeforeEach(func() { utilruntime.Must(v1beta1.AddToScheme(scheme.Scheme)) @@ -34,213 +49,337 @@ var _ = Describe("SQLSSLCert Controller", func() { When("the resource exists", func() { BeforeEach(func() { - existingCert := &v1beta1.SQLSSLCert{ + existingUser := &v1beta1.SQLUser{ TypeMeta: meta_v1.TypeMeta{ APIVersion: "sql.cnrm.cloud.google.com/v1beta1", - Kind: "SQLSSLCert", + Kind: "SQLUser", }, ObjectMeta: meta_v1.ObjectMeta{ - Name: "test-cert", - Namespace: "default", + Name: userName, + Namespace: namespace, Annotations: map[string]string{ - "sqeletor.nais.io/secret-name": "sqeletor-test-secret", + "sqeletor.nais.io/env-var-prefix": envVarPrefix, + "sqeletor.nais.io/database-name": dbName, }, }, - Spec: v1beta1.SQLSSLCertSpec{}, - Status: v1beta1.SQLSSLCertStatus{ - Cert: ptr.To("dummy-cert"), - PrivateKey: ptr.To("dummy-private-key"), - ServerCaCert: ptr.To("dummy-server-ca-cert"), + Spec: v1beta1.SQLUserSpec{ + Password: &v1beta1.UserPassword{ + ValueFrom: &v1beta1.UserValueFrom{ + SecretKeyRef: &v1alpha1.SecretKeyRef{ + Name: secretName, + Key: secretKey, + }, + }, + }, + InstanceRef: v1alpha1.ResourceRef{ + Name: instanceName, + Namespace: namespace, + }, }, } - clientBuilder = clientBuilder.WithObjects(existingCert) + clientBuilder = clientBuilder.WithObjects(existingUser) }) - When("no secret exists", func() { + When("sql instance exists and is ready", func() { BeforeEach(func() { - k8sClient = clientBuilder.Build() - controller = &SQLSSLCertReconciler{Scheme: scheme.Scheme, Client: k8sClient} - }) - - It("should successfully reconcile the resource", func() { - req := ctrl.Request{NamespacedName: types.NamespacedName{Name: "test-cert", Namespace: "default"}} - result, err := controller.Reconcile(ctx, req) - - Expect(err).ToNot(HaveOccurred()) - Expect(result).To(Equal(ctrl.Result{})) - }) - - It("should create a secret containing the certificate data", func() { - req := ctrl.Request{NamespacedName: types.NamespacedName{Name: "test-cert", Namespace: "default"}} - _, err := controller.Reconcile(ctx, req) - Expect(err).ToNot(HaveOccurred()) - - secret := &core_v1.Secret{} - err = k8sClient.Get(ctx, types.NamespacedName{Name: "sqeletor-test-secret", Namespace: "default"}, secret) - Expect(err).ToNot(HaveOccurred()) - - Expect(secret.StringData).To(HaveKeyWithValue(certKey, "dummy-cert")) - Expect(secret.StringData).To(HaveKeyWithValue(privateKeyKey, "dummy-private-key")) - Expect(secret.StringData).To(HaveKeyWithValue(serverCaCertKey, "dummy-server-ca-cert")) - }) - - It("should set owner reference and managed by", func() { - req := ctrl.Request{NamespacedName: types.NamespacedName{Name: "test-cert", Namespace: "default"}} - _, err := controller.Reconcile(ctx, req) - Expect(err).ToNot(HaveOccurred()) - - secret := &core_v1.Secret{} - err = k8sClient.Get(ctx, types.NamespacedName{Name: "sqeletor-test-secret", Namespace: "default"}, secret) - Expect(err).ToNot(HaveOccurred()) - - Expect(secret.OwnerReferences).To(HaveLen(1)) - Expect(secret.OwnerReferences[0].Name).To(Equal("test-cert")) - Expect(secret.OwnerReferences[0].Kind).To(Equal("SQLSSLCert")) - Expect(secret.OwnerReferences[0].APIVersion).To(Equal("sql.cnrm.cloud.google.com/v1beta1")) - - Expect(secret.Labels[managedByKey]).To(Equal(sqeletorFqdnId)) - }) - }) - - When("a secret already exists that is not owned or managed", func() { - BeforeEach(func() { - existingSecret := &core_v1.Secret{ + existingSqlInstance := &v1beta1.SQLInstance{ + TypeMeta: meta_v1.TypeMeta{ + APIVersion: "sql.cnrm.cloud.google.com/v1beta1", + Kind: "SQLInstance", + }, ObjectMeta: meta_v1.ObjectMeta{ - Name: "sqeletor-test-secret", - Namespace: "default", - CreationTimestamp: meta_v1.Time{ - Time: time.Now(), + Name: instanceName, + Namespace: namespace, + }, + Spec: v1beta1.SQLInstanceSpec{ + Settings: v1beta1.InstanceSettings{ + IpConfiguration: &v1beta1.InstanceIpConfiguration{ + PrivateNetworkRef: &v1alpha1.ResourceRef{ + Name: "test-network", + }, + }, }, }, + Status: v1beta1.SQLInstanceStatus{ + PrivateIpAddress: ptr.To(instanceIP), + }, } - k8sClient = clientBuilder.WithObjects(existingSecret).Build() - controller = &SQLSSLCertReconciler{Scheme: scheme.Scheme, Client: k8sClient} - }) - - It("should not update the secret with the certificate data", func() { - req := ctrl.Request{NamespacedName: types.NamespacedName{Name: "test-cert", Namespace: "default"}} - _, err := controller.Reconcile(ctx, req) - Expect(err).To(HaveOccurred()) - - secret := &core_v1.Secret{} - err = k8sClient.Get(ctx, types.NamespacedName{Name: "sqeletor-test-secret", Namespace: "default"}, secret) - Expect(err).ToNot(HaveOccurred()) - Expect(secret.StringData).To(BeEmpty()) + clientBuilder = clientBuilder.WithObjects(existingSqlInstance) }) - It("should not update owner reference or managed by", func() { - req := ctrl.Request{NamespacedName: types.NamespacedName{Name: "test-cert", Namespace: "default"}} - _, err := controller.Reconcile(ctx, req) - Expect(err).To(HaveOccurred()) - - secret := &core_v1.Secret{} - err = k8sClient.Get(ctx, types.NamespacedName{Name: "sqeletor-test-secret", Namespace: "default"}, secret) - Expect(err).ToNot(HaveOccurred()) + When("no secret exists", func() { + BeforeEach(func() { + k8sClient = clientBuilder.Build() + controller = &SQLUserReconciler{Scheme: scheme.Scheme, Client: k8sClient} + }) + + It("should successfully reconcile the resource", func() { + req := ctrl.Request{NamespacedName: types.NamespacedName{Name: userName, Namespace: namespace}} + result, err := controller.Reconcile(ctx, req) + + Expect(err).ToNot(HaveOccurred()) + Expect(result).To(Equal(ctrl.Result{})) + }) + + It("should create a secret containing the env vars", func() { + req := ctrl.Request{NamespacedName: types.NamespacedName{Name: userName, Namespace: namespace}} + _, err := controller.Reconcile(ctx, req) + Expect(err).ToNot(HaveOccurred()) + + secret := &core_v1.Secret{} + err = k8sClient.Get(ctx, types.NamespacedName{Name: secretName, Namespace: namespace}, secret) + Expect(err).ToNot(HaveOccurred()) + + rootCertPath := filepath.Join(nais_io_v1alpha1.DefaultSqeletorMountPath, serverCaCertKey) + certPath := filepath.Join(nais_io_v1alpha1.DefaultSqeletorMountPath, certKey) + privateKeyPath := filepath.Join(nais_io_v1alpha1.DefaultSqeletorMountPath, privateKeyKey) + + Expect(secret.StringData).To(HaveKey(envVarPrefix + "_PASSWORD")) + Expect(secret.StringData).To(HaveKeyWithValue(envVarPrefix+"_HOST", instanceIP)) + Expect(secret.StringData).To(HaveKeyWithValue(envVarPrefix+"_PORT", "5432")) + Expect(secret.StringData).To(HaveKeyWithValue(envVarPrefix+"_DATABASE", dbName)) + Expect(secret.StringData).To(HaveKeyWithValue(envVarPrefix+"_USERNAME", userName)) + Expect(secret.StringData).To(HaveKeyWithValue(envVarPrefix+"_URL", MatchRegexp(`^postgresql:\/\/test-user:[^@]+@10.10.10.10:5432\/test-db\?sslcert=%2Fvar%2Frun%2Fsecrets%2Fnais.io%2Fsqlcertificate%2Fcert.pem&sslkey=%2Fvar%2Frun%2Fsecrets%2Fnais.io%2Fsqlcertificate%2Fprivate-key.pem&sslmode=verify-ca&sslrootcert=%2Fvar%2Frun%2Fsecrets%2Fnais.io%2Fsqlcertificate%2Fserver-ca-cert.pem$`))) + Expect(secret.StringData).To(HaveKeyWithValue("PGSSLMODE", "verify-ca")) + Expect(secret.StringData).To(HaveKeyWithValue("PGSSLROOTCERT", rootCertPath)) + Expect(secret.StringData).To(HaveKeyWithValue("PGSSLCERT", certPath)) + Expect(secret.StringData).To(HaveKeyWithValue("PGSSLKEY", privateKeyPath)) + Expect(secret.StringData).To(HaveKeyWithValue("PGHOSTADDR", instanceIP)) + Expect(secret.StringData).To(HaveKeyWithValue("PGPORT", "5432")) + Expect(secret.StringData).To(HaveKey("PGPASSWORD")) + Expect(secret.StringData).To(HaveKeyWithValue("PGDATABASE", dbName)) + Expect(secret.StringData).To(HaveKeyWithValue("PGUSER", userName)) + }) + + It("should set owner reference and managed by", func() { + req := ctrl.Request{NamespacedName: types.NamespacedName{Name: userName, Namespace: namespace}} + _, err := controller.Reconcile(ctx, req) + Expect(err).ToNot(HaveOccurred()) + + secret := &core_v1.Secret{} + err = k8sClient.Get(ctx, types.NamespacedName{Name: secretName, Namespace: namespace}, secret) + Expect(err).ToNot(HaveOccurred()) + + Expect(secret.OwnerReferences).To(HaveLen(1)) + Expect(secret.OwnerReferences[0].Name).To(Equal(userName)) + Expect(secret.OwnerReferences[0].Kind).To(Equal("SQLUser")) + Expect(secret.OwnerReferences[0].APIVersion).To(Equal("sql.cnrm.cloud.google.com/v1beta1")) + + Expect(secret.Labels[managedByKey]).To(Equal(sqeletorFqdnId)) + }) + }) - Expect(secret.OwnerReferences).To(HaveLen(0)) - Expect(secret.Labels[managedByKey]).To(BeEmpty()) + When("a secret already exists that is not owned or managed", func() { + BeforeEach(func() { + existingSecret := &core_v1.Secret{ + ObjectMeta: meta_v1.ObjectMeta{ + Name: secretName, + Namespace: namespace, + CreationTimestamp: meta_v1.Time{ + Time: time.Now(), + }, + }, + } + k8sClient = clientBuilder.WithObjects(existingSecret).Build() + controller = &SQLUserReconciler{Scheme: scheme.Scheme, Client: k8sClient} + }) + + It("should not update the secret with the config data", func() { + req := ctrl.Request{NamespacedName: types.NamespacedName{Name: userName, Namespace: namespace}} + _, err := controller.Reconcile(ctx, req) + Expect(err).To(HaveOccurred()) + + secret := &core_v1.Secret{} + err = k8sClient.Get(ctx, types.NamespacedName{Name: secretName, Namespace: namespace}, secret) + Expect(err).ToNot(HaveOccurred()) + + Expect(secret.StringData).To(BeEmpty()) + }) + + It("should not update owner reference or managed by", func() { + req := ctrl.Request{NamespacedName: types.NamespacedName{Name: userName, Namespace: namespace}} + _, err := controller.Reconcile(ctx, req) + Expect(err).To(HaveOccurred()) + + secret := &core_v1.Secret{} + err = k8sClient.Get(ctx, types.NamespacedName{Name: secretName, Namespace: namespace}, secret) + Expect(err).ToNot(HaveOccurred()) + + Expect(secret.OwnerReferences).To(HaveLen(0)) + Expect(secret.Labels[managedByKey]).To(BeEmpty()) + }) }) - }) - When("a secret already exists that is owned and managed by correct cert", func() { - BeforeEach(func() { - existingSecret := &core_v1.Secret{ - ObjectMeta: meta_v1.ObjectMeta{ - Name: "sqeletor-test-secret", - Namespace: "default", - CreationTimestamp: meta_v1.Time{ - Time: time.Now(), + When("a secret already exists that is owned and managed by correct user", func() { + BeforeEach(func() { + existingSecret := &core_v1.Secret{ + ObjectMeta: meta_v1.ObjectMeta{ + Name: secretName, + Namespace: namespace, + CreationTimestamp: meta_v1.Time{ + Time: time.Now(), + }, + Labels: map[string]string{ + managedByKey: sqeletorFqdnId, + }, + OwnerReferences: []meta_v1.OwnerReference{ + { + APIVersion: "sql.cnrm.cloud.google.com/v1beta1", + Kind: "SQLUser", + Name: userName, + }, + }, }, - Labels: map[string]string{ - managedByKey: sqeletorFqdnId, + StringData: map[string]string{ + "PGDATABASE": "something-else", }, - OwnerReferences: []meta_v1.OwnerReference{ - { - APIVersion: "sql.cnrm.cloud.google.com/v1beta1", - Kind: "SQLSSLCert", - Name: "test-cert", + } + k8sClient = clientBuilder.WithObjects(existingSecret).Build() + controller = &SQLUserReconciler{Scheme: scheme.Scheme, Client: k8sClient} + }) + + It("should update the secret with the env data", func() { + req := ctrl.Request{NamespacedName: types.NamespacedName{Name: userName, Namespace: namespace}} + _, err := controller.Reconcile(ctx, req) + Expect(err).ToNot(HaveOccurred()) + + secret := &core_v1.Secret{} + err = k8sClient.Get(ctx, types.NamespacedName{Name: secretName, Namespace: namespace}, secret) + Expect(err).ToNot(HaveOccurred()) + + // just test one value, the rest is tested in a previous test + Expect(secret.StringData).To(HaveKeyWithValue("PGDATABASE", dbName)) + }) + }) + + When("a secret already exists that is owned and managed by other user", func() { + BeforeEach(func() { + existingSecret := &core_v1.Secret{ + ObjectMeta: meta_v1.ObjectMeta{ + Name: secretName, + Namespace: namespace, + CreationTimestamp: meta_v1.Time{ + Time: time.Now(), + }, + Labels: map[string]string{ + managedByKey: sqeletorFqdnId, + }, + OwnerReferences: []meta_v1.OwnerReference{ + { + APIVersion: "sql.cnrm.cloud.google.com/v1beta1", + Kind: "SQLUser", + Name: "other-user", + }, }, }, + StringData: map[string]string{ + "PGDATABASE": "something-else", + }, + } + k8sClient = clientBuilder.WithObjects(existingSecret).Build() + controller = &SQLUserReconciler{Scheme: scheme.Scheme, Client: k8sClient} + }) + + It("should not update the secret with the env data", func() { + req := ctrl.Request{NamespacedName: types.NamespacedName{Name: userName, Namespace: namespace}} + _, err := controller.Reconcile(ctx, req) + Expect(err).To(HaveOccurred()) + + secret := &core_v1.Secret{} + err = k8sClient.Get(ctx, types.NamespacedName{Name: secretName, Namespace: namespace}, secret) + Expect(err).ToNot(HaveOccurred()) + + Expect(secret.StringData).To(HaveKeyWithValue("PGDATABASE", "something-else")) + }) + + It("should leave owner reference alone", func() { + req := ctrl.Request{NamespacedName: types.NamespacedName{Name: userName, Namespace: namespace}} + _, err := controller.Reconcile(ctx, req) + Expect(err).To(HaveOccurred()) + + secret := &core_v1.Secret{} + err = k8sClient.Get(ctx, types.NamespacedName{Name: secretName, Namespace: namespace}, secret) + Expect(err).ToNot(HaveOccurred()) + + Expect(secret.OwnerReferences).To(HaveLen(1)) + Expect(secret.OwnerReferences[0].Name).To(Equal("other-user")) + Expect(secret.OwnerReferences[0].Kind).To(Equal("SQLUser")) + Expect(secret.OwnerReferences[0].APIVersion).To(Equal("sql.cnrm.cloud.google.com/v1beta1")) + }) + }) + }) + When("sql instance exists but is not configured for private ip", func() { + It("shuld return a permanent error", func() { + existingSqlInstance := &v1beta1.SQLInstance{ + TypeMeta: meta_v1.TypeMeta{ + APIVersion: "sql.cnrm.cloud.google.com/v1beta1", + Kind: "SQLInstance", + }, + ObjectMeta: meta_v1.ObjectMeta{ + Name: instanceName, + Namespace: namespace, + }, + Spec: v1beta1.SQLInstanceSpec{ + Settings: v1beta1.InstanceSettings{ + IpConfiguration: &v1beta1.InstanceIpConfiguration{}, + }, }, } - k8sClient = clientBuilder.WithObjects(existingSecret).Build() - controller = &SQLSSLCertReconciler{Scheme: scheme.Scheme, Client: k8sClient} - }) - - It("should update the secret with the certificate data", func() { - req := ctrl.Request{NamespacedName: types.NamespacedName{Name: "test-cert", Namespace: "default"}} - _, err := controller.Reconcile(ctx, req) - Expect(err).ToNot(HaveOccurred()) - secret := &core_v1.Secret{} - err = k8sClient.Get(ctx, types.NamespacedName{Name: "sqeletor-test-secret", Namespace: "default"}, secret) - Expect(err).ToNot(HaveOccurred()) + clientBuilder = clientBuilder.WithObjects(existingSqlInstance) + k8sClient = clientBuilder.Build() + controller = &SQLUserReconciler{Scheme: scheme.Scheme, Client: k8sClient} - Expect(secret.StringData).To(HaveKeyWithValue(certKey, "dummy-cert")) - Expect(secret.StringData).To(HaveKeyWithValue(privateKeyKey, "dummy-private-key")) - Expect(secret.StringData).To(HaveKeyWithValue(serverCaCertKey, "dummy-server-ca-cert")) + req := ctrl.Request{NamespacedName: types.NamespacedName{Name: userName, Namespace: namespace}} + _, err := controller.Reconcile(ctx, req) + Expect(err).To(HaveOccurred()) + Expect(err).To(MatchError("permanent failure: referenced sql instance is not configured for private ip")) }) }) - When("a secret already exists that is owned and managed by other cert", func() { - BeforeEach(func() { - existingSecret := &core_v1.Secret{ + When("sql instance exists but does not have a private ip yet", func() { + It("shuld return a temporary error", func() { + existingSqlInstance := &v1beta1.SQLInstance{ + TypeMeta: meta_v1.TypeMeta{ + APIVersion: "sql.cnrm.cloud.google.com/v1beta1", + Kind: "SQLInstance", + }, ObjectMeta: meta_v1.ObjectMeta{ - Name: "sqeletor-test-secret", - Namespace: "default", - CreationTimestamp: meta_v1.Time{ - Time: time.Now(), - }, - Labels: map[string]string{ - managedByKey: sqeletorFqdnId, - }, - OwnerReferences: []meta_v1.OwnerReference{ - { - APIVersion: "sql.cnrm.cloud.google.com/v1beta1", - Kind: "SQLSSLCert", - Name: "other-cert", + Name: instanceName, + Namespace: namespace, + }, + Spec: v1beta1.SQLInstanceSpec{ + Settings: v1beta1.InstanceSettings{ + IpConfiguration: &v1beta1.InstanceIpConfiguration{ + PrivateNetworkRef: &v1alpha1.ResourceRef{ + Name: "test-network", + }, }, }, }, - StringData: map[string]string{ - certKey: "existing-cert", - privateKeyKey: "existing-private-key", - serverCaCertKey: "existing-server-ca-cert", - }, } - k8sClient = clientBuilder.WithObjects(existingSecret).Build() - controller = &SQLSSLCertReconciler{Scheme: scheme.Scheme, Client: k8sClient} - }) - It("should not update the secret with the certificate data", func() { - req := ctrl.Request{NamespacedName: types.NamespacedName{Name: "test-cert", Namespace: "default"}} - _, err := controller.Reconcile(ctx, req) - Expect(err).To(HaveOccurred()) + clientBuilder = clientBuilder.WithObjects(existingSqlInstance) + k8sClient = clientBuilder.Build() + controller = &SQLUserReconciler{Scheme: scheme.Scheme, Client: k8sClient} - secret := &core_v1.Secret{} - err = k8sClient.Get(ctx, types.NamespacedName{Name: "sqeletor-test-secret", Namespace: "default"}, secret) + req := ctrl.Request{NamespacedName: types.NamespacedName{Name: userName, Namespace: namespace}} + result, err := controller.Reconcile(ctx, req) Expect(err).ToNot(HaveOccurred()) - - Expect(secret.StringData).To(HaveKeyWithValue(certKey, "existing-cert")) - Expect(secret.StringData).To(HaveKeyWithValue(privateKeyKey, "existing-private-key")) - Expect(secret.StringData).To(HaveKeyWithValue(serverCaCertKey, "existing-server-ca-cert")) + Expect(result).To(Equal(ctrl.Result{RequeueAfter: time.Minute})) }) + }) + When("sql instance does not exist", func() { + It("should return a temporary error", func() { + k8sClient = clientBuilder.Build() + controller = &SQLUserReconciler{Scheme: scheme.Scheme, Client: k8sClient} - It("should leave owner reference alone", func() { - req := ctrl.Request{NamespacedName: types.NamespacedName{Name: "test-cert", Namespace: "default"}} - _, err := controller.Reconcile(ctx, req) - Expect(err).To(HaveOccurred()) - - secret := &core_v1.Secret{} - err = k8sClient.Get(ctx, types.NamespacedName{Name: "sqeletor-test-secret", Namespace: "default"}, secret) + req := ctrl.Request{NamespacedName: types.NamespacedName{Name: userName, Namespace: namespace}} + result, err := controller.Reconcile(ctx, req) Expect(err).ToNot(HaveOccurred()) - - Expect(secret.OwnerReferences).To(HaveLen(1)) - Expect(secret.OwnerReferences[0].Name).To(Equal("other-cert")) - Expect(secret.OwnerReferences[0].Kind).To(Equal("SQLSSLCert")) - Expect(secret.OwnerReferences[0].APIVersion).To(Equal("sql.cnrm.cloud.google.com/v1beta1")) + Expect(result).To(Equal(ctrl.Result{RequeueAfter: time.Minute})) }) }) })