diff --git a/pkg/apis/secret/go.mod b/pkg/apis/secret/go.mod index ba65bd5f9c9..81f96e3ecd2 100644 --- a/pkg/apis/secret/go.mod +++ b/pkg/apis/secret/go.mod @@ -9,88 +9,36 @@ require ( google.golang.org/protobuf v1.36.6 gopkg.in/yaml.v3 v3.0.1 k8s.io/apimachinery v0.33.2 - k8s.io/apiserver v0.33.2 k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 ) require ( - github.com/beorn7/perks v1.0.1 // indirect - github.com/blang/semver/v4 v4.0.0 // indirect - github.com/cenkalti/backoff/v5 v5.0.2 // indirect - github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/coreos/go-semver v0.3.1 // indirect - github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect - github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/go-logr/logr v1.4.2 // indirect - github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonreference v0.21.0 // indirect github.com/go-openapi/swag v0.23.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/protobuf v1.5.4 // indirect github.com/google/gnostic-models v0.6.9 // indirect - github.com/google/go-cmp v0.7.0 // indirect - github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect - github.com/google/uuid v1.6.0 // indirect - github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect - github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a5340 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect - github.com/jonboulle/clockwork v0.5.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/kylelemons/godebug v1.1.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/onsi/ginkgo/v2 v2.22.2 // indirect - github.com/onsi/gomega v1.36.2 // indirect - github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/prometheus/client_golang v1.22.0 // indirect - github.com/prometheus/client_model v0.6.2 // indirect - github.com/prometheus/common v0.64.0 // indirect - github.com/prometheus/procfs v0.16.1 // indirect - github.com/spf13/pflag v1.0.6 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/x448/float16 v0.8.4 // indirect - go.etcd.io/bbolt v1.4.0 // indirect - go.etcd.io/etcd/api/v3 v3.5.21 // indirect - go.etcd.io/etcd/client/pkg/v3 v3.5.21 // indirect - go.etcd.io/etcd/client/v3 v3.5.21 // indirect - go.opentelemetry.io/auto/sdk v1.1.0 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect go.opentelemetry.io/otel v1.36.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.36.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.36.0 // indirect - go.opentelemetry.io/otel/metric v1.36.0 // indirect - go.opentelemetry.io/otel/sdk v1.36.0 // indirect - go.opentelemetry.io/otel/trace v1.36.0 // indirect - go.opentelemetry.io/proto/otlp v1.6.0 // indirect - go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.27.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.36.0 // indirect golang.org/x/net v0.41.0 // indirect - golang.org/x/oauth2 v0.30.0 // indirect golang.org/x/sys v0.33.0 // indirect - golang.org/x/term v0.32.0 // indirect golang.org/x/text v0.26.0 // indirect - golang.org/x/time v0.11.0 // indirect - golang.org/x/tools v0.34.0 // indirect - google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250519155744-55703ea1f237 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250519155744-55703ea1f237 // indirect - gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect - k8s.io/api v0.33.2 // indirect - k8s.io/client-go v0.33.2 // indirect - k8s.io/component-base v0.33.2 // indirect k8s.io/klog/v2 v2.130.1 // indirect - sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 // indirect sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect diff --git a/pkg/apis/secret/go.sum b/pkg/apis/secret/go.sum index e8ea9a27592..3a4d0158519 100644 --- a/pkg/apis/secret/go.sum +++ b/pkg/apis/secret/go.sum @@ -1,41 +1,11 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -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/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= -github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= -github.com/cenkalti/backoff/v5 v5.0.2 h1:rIfFVxEf1QsI7E1ZHfp/B4DF/6QBAUhmgkxc0H7Zss8= -github.com/cenkalti/backoff/v5 v5.0.2/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= -github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -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/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= -github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= -github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -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.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= @@ -46,156 +16,58 @@ github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= -github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= -github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= -github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw= github.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8= -github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo= -github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA= github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250514132646-acbc7b54ed9e h1:BTKk7LHuG1kmAkucwTA7DuMbKpKvJTKrGdBmUNO4dfQ= github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250514132646-acbc7b54ed9e/go.mod h1:IA4SOwun8QyST9c5UNs/fN37XL6boXXDvRYFcFwbipg= -github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= -github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a5340 h1:uGoIog/wiQHI9GAxXO5TJbT0wWKH3O9HhOJW1F9c3fY= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20191002090509-6af20e3a5340/go.mod h1:3bDW6wMZJB7tiONtC/1Xpicra6Wp5GgbTbQWCbI5fkc= -github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= -github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI= -github.com/jonboulle/clockwork v0.5.0 h1:Hyh9A8u51kptdkR+cqRpT1EebBwTn1oK9YfGYbdFz6I= -github.com/jonboulle/clockwork v0.5.0/go.mod h1:3mZlmanh0g2NDKO5TWZVJAfofYk64M7XN3SzBPjZF60= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= -github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= -github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= 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= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= -github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/onsi/ginkgo/v2 v2.22.2 h1:/3X8Panh8/WwhU/3Ssa6rCKqPLuAkVY2I0RoyDLySlU= -github.com/onsi/ginkgo/v2 v2.22.2/go.mod h1:oeMosUL+8LtarXBHu/c0bx2D/K9zyQ6uX3cTyztHwsk= -github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8= -github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY= -github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -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/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/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= -github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= -github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= -github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= -github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.64.0 h1:pdZeA+g617P7oGv1CzdTzyeShxAGrTBsolKNOLQPGO4= -github.com/prometheus/common v0.64.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8= -github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= -github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= -github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= -github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 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.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 h1:6fotK7otjonDflCTK0BCfls4SPy3NcCVb5dqqmbRknE= -github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75/go.mod h1:KO6IkyS8Y3j8OdNO85qEYBsRPuteD+YciPomcXdrMnk= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= -github.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510 h1:S2dVYn90KE98chqDkyE9Z4N61UnQd+KOfgp5Iu53llk= -github.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -go.etcd.io/bbolt v1.4.0 h1:TU77id3TnN/zKr7CO/uk+fBCwF2jGcMuw2B/FMAzYIk= -go.etcd.io/bbolt v1.4.0/go.mod h1:AsD+OCi/qPN1giOX1aiLAha3o1U8rAz65bvN4j0sRuk= -go.etcd.io/etcd/api/v3 v3.5.21 h1:A6O2/JDb3tvHhiIz3xf9nJ7REHvtEFJJ3veW3FbCnS8= -go.etcd.io/etcd/api/v3 v3.5.21/go.mod h1:c3aH5wcvXv/9dqIw2Y810LDXJfhSYdHQ0vxmP3CCHVY= -go.etcd.io/etcd/client/pkg/v3 v3.5.21 h1:lPBu71Y7osQmzlflM9OfeIV2JlmpBjqBNlLtcoBqUTc= -go.etcd.io/etcd/client/pkg/v3 v3.5.21/go.mod h1:BgqT/IXPjK9NkeSDjbzwsHySX3yIle2+ndz28nVsjUs= -go.etcd.io/etcd/client/v2 v2.305.21 h1:eLiFfexc2mE+pTLz9WwnoEsX5JTTpLCYVivKkmVXIRA= -go.etcd.io/etcd/client/v2 v2.305.21/go.mod h1:OKkn4hlYNf43hpjEM3Ke3aRdUkhSl8xjKjSf8eCq2J8= -go.etcd.io/etcd/client/v3 v3.5.21 h1:T6b1Ow6fNjOLOtM0xSoKNQt1ASPCLWrF9XMHcH9pEyY= -go.etcd.io/etcd/client/v3 v3.5.21/go.mod h1:mFYy67IOqmbRf/kRUvsHixzo3iG+1OF2W2+jVIQRAnU= -go.etcd.io/etcd/pkg/v3 v3.5.21 h1:jUItxeKyrDuVuWhdh0HtjUANwyuzcb7/FAeUfABmQsk= -go.etcd.io/etcd/pkg/v3 v3.5.21/go.mod h1:wpZx8Egv1g4y+N7JAsqi2zoUiBIUWznLjqJbylDjWgU= -go.etcd.io/etcd/raft/v3 v3.5.21 h1:dOmE0mT55dIUsX77TKBLq+RgyumsQuYeiRQnW/ylugk= -go.etcd.io/etcd/raft/v3 v3.5.21/go.mod h1:fmcuY5R2SNkklU4+fKVBQi2biVp5vafMrWUEj4TJ4Cs= -go.etcd.io/etcd/server/v3 v3.5.21 h1:9w0/k12majtgarGmlMVuhwXRI2ob3/d1Ik3X5TKo0yU= -go.etcd.io/etcd/server/v3 v3.5.21/go.mod h1:G1mOzdwuzKT1VRL7SqRchli/qcFrtLBTAQ4lV20sXXo= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 h1:x7wzEgXfnzJcHDwStJT+mxOz4etr2EcexjqhBvmoakw= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0/go.mod h1:rg+RlpR5dKwaS95IyyZqj5Wd4E13lk/msnTS0Xl9lJM= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q= go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg= go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.36.0 h1:dNzwXjZKpMpE2JhmO+9HsPl42NIXFIFSUSSs0fiqra0= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.36.0/go.mod h1:90PoxvaEB5n6AOdZvi+yWJQoE95U8Dhhw2bSyRqnTD0= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.36.0 h1:JgtbA0xkWHnTmYk7YusopJFX6uleBmAuZ8n05NEh8nQ= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.36.0/go.mod h1:179AK5aar5R3eS9FucPy6rggvU0g52cvKId8pv4+v0c= go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE= go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs= go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs= @@ -204,139 +76,58 @@ go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFw go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4= go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w= go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA= -go.opentelemetry.io/proto/otlp v1.6.0 h1:jQjP+AQyTf+Fe7OKj/MfkDrmK4MNVtw2NpXsf9fefDI= -go.opentelemetry.io/proto/otlp v1.6.0/go.mod h1:cicgGehlFuNdgZkcALOCh3VE6K/u2tAjzlRhDwmVpZc= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= -go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= -go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= -go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= -go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= -go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= -golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -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-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= -golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= -golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= -golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= -golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= -golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo= -golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= 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= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb h1:ITgPrl429bc6+2ZraNSzMDk3I95nmQln2fuPstKwFDE= -google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:sAo5UzpjUwgFBCzupwhcLcxHVDK7vG5IqI30YnwX2eE= -google.golang.org/genproto/googleapis/api v0.0.0-20250519155744-55703ea1f237 h1:Kog3KlB4xevJlAcbbbzPfRG0+X9fdoGM+UBRKVz6Wr0= -google.golang.org/genproto/googleapis/api v0.0.0-20250519155744-55703ea1f237/go.mod h1:ezi0AVyMKDWy5xAncvjLWH7UcLBB5n7y2fQ8MzjJcto= google.golang.org/genproto/googleapis/rpc v0.0.0-20250519155744-55703ea1f237 h1:cJfm9zPbe1e873mHJzmQ1nwVEeRDU/T1wXDK2kUSU34= google.golang.org/genproto/googleapis/rpc v0.0.0-20250519155744-55703ea1f237/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= -google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok= google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc= google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4= -gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -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.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -k8s.io/api v0.33.2 h1:YgwIS5jKfA+BZg//OQhkJNIfie/kmRsO0BmNaVSimvY= -k8s.io/api v0.33.2/go.mod h1:fhrbphQJSM2cXzCWgqU29xLDuks4mu7ti9vveEnpSXs= k8s.io/apimachinery v0.33.2 h1:IHFVhqg59mb8PJWTLi8m1mAoepkUNYmptHsV+Z1m5jY= k8s.io/apimachinery v0.33.2/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM= -k8s.io/apiserver v0.33.2 h1:KGTRbxn2wJagJowo29kKBp4TchpO1DRO3g+dB/KOJN4= -k8s.io/apiserver v0.33.2/go.mod h1:9qday04wEAMLPWWo9AwqCZSiIn3OYSZacDyu/AcoM/M= -k8s.io/client-go v0.33.2 h1:z8CIcc0P581x/J1ZYf4CNzRKxRvQAwoAolYPbtQes+E= -k8s.io/client-go v0.33.2/go.mod h1:9mCgT4wROvL948w6f6ArJNb7yQd7QsvqavDeZHvNmHo= -k8s.io/component-base v0.33.2 h1:sCCsn9s/dG3ZrQTX/Us0/Sx2R0G5kwa0wbZFYoVp/+0= -k8s.io/component-base v0.33.2/go.mod h1:/41uw9wKzuelhN+u+/C59ixxf4tYQKW7p32ddkYNe2k= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4= k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff/go.mod h1:5jIi+8yX4RIb8wk3XwBo5Pq2ccx4FP10ohkbSKCZoK8= k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro= k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 h1:jpcvIRr3GLoUoEKRkHKSmGjxb6lWwrBlJsXc+eUYQHM= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw= sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8= sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo= sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= diff --git a/pkg/apis/secret/v0alpha1/register.go b/pkg/apis/secret/v0alpha1/register.go index f31ab882212..87e99392e91 100644 --- a/pkg/apis/secret/v0alpha1/register.go +++ b/pkg/apis/secret/v0alpha1/register.go @@ -4,10 +4,8 @@ import ( "fmt" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apiserver/pkg/registry/generic" "github.com/grafana/grafana/pkg/apimachinery/utils" ) @@ -33,7 +31,6 @@ var SecureValuesResourceInfo = utils.NewResourceInfo( {Name: "Description", Type: "string", Format: "string", Description: "Short description that explains the purpose of this SecureValue"}, {Name: "Keeper", Type: "string", Format: "string", Description: "Storage of the secure value"}, {Name: "Ref", Type: "string", Format: "string", Description: "If present, the reference to a secret"}, - {Name: "Status", Type: "string", Format: "string", Description: "The status of the secure value"}, }, // Decodes the object into a concrete type. Return order in the slice must be the same as in `Definition`. Reader: func(obj any) ([]interface{}, error) { @@ -44,7 +41,6 @@ var SecureValuesResourceInfo = utils.NewResourceInfo( r.Spec.Description, r.Spec.Keeper, r.Spec.Ref, - r.Status.Phase, }, nil } @@ -92,13 +88,6 @@ var ( AddToScheme = localSchemeBuilder.AddToScheme ) -// Adds the status phase to the selectable fields, besides the generic metadata name and namespace. -func SelectableSecureValueFields(obj *SecureValue) fields.Set { - return generic.MergeFieldsSets(generic.ObjectMetaFieldsSet(&obj.ObjectMeta, false), fields.Set{ - "status.phase": string(obj.Status.Phase), - }) -} - // Adds the list of known types to the given scheme. func AddKnownTypes(scheme *runtime.Scheme, version string) error { // TODO: do we need a type for the secure value decrypt? @@ -112,20 +101,5 @@ func AddKnownTypes(scheme *runtime.Scheme, version string) error { // &secretV0.SecureValueActivityList{}, ) - err := scheme.AddFieldLabelConversionFunc( - SecureValuesResourceInfo.GroupVersionKind(), - func(label, value string) (string, string, error) { - fieldSet := SelectableSecureValueFields(&SecureValue{}) - for key := range fieldSet { - if label == key { - return label, value, nil - } - } - return "", "", fmt.Errorf("field label not supported for %s: %s", SecureValuesResourceInfo.GroupVersionKind(), label) - }, - ) - if err != nil { - return err - } return nil } diff --git a/pkg/apis/secret/v0alpha1/secure_value.go b/pkg/apis/secret/v0alpha1/secure_value.go index 26a68263568..7208683cd0a 100644 --- a/pkg/apis/secret/v0alpha1/secure_value.go +++ b/pkg/apis/secret/v0alpha1/secure_value.go @@ -11,41 +11,18 @@ type SecureValue struct { // Standard object's metadata. It can only be one of `metav1.ObjectMeta` or `metav1.ListMeta`. // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata // +optional - metav1.ObjectMeta `json:"metadata,omitempty"` + metav1.ObjectMeta `json:"metadata"` // This is the actual secure value schema. Spec SecureValueSpec `json:"spec"` // Read-only observed status of the `SecureValue`. // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status - Status SecureValueStatus `json:"status,omitempty"` + Status SecureValueStatus `json:"status"` } -// +enum -type SecureValuePhase string - -const ( - // When the `SecureValue` is created, it will start in `Pending` phase to create the underlying secret asynchronously. - SecureValuePhasePending SecureValuePhase = "Pending" - - // If the creation of the secret is successful, it will move to the `Succeeded` phase. - SecureValuePhaseSucceeded SecureValuePhase = "Succeeded" - - // If the creation of the secret fails, it will move to the `Failed` phase. - // Check the additional `status` fields for more information on what caused the failure. - // This state is unrecoverable. - SecureValuePhaseFailed SecureValuePhase = "Failed" -) - type SecureValueStatus struct { - // High-level summary of where the `SecureValue` is in its lifecycle. - // One of: `Pending`, `Succeeded` or `Failed`. - Phase SecureValuePhase `json:"phase"` - - // A human readable message indicating details about why the `SecureValue` is in this phase. - // Only applicable if the `phase=Failed`. - // +optional - Message string `json:"message,omitempty"` + Version int64 `json:"version"` // +optional ExternalID string `json:"externalId,omitempty"` @@ -94,7 +71,7 @@ type SecureValueList struct { // Standard list's metadata. It can only be one of `metav1.ObjectMeta` or `metav1.ListMeta`. // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata // +optional - metav1.ListMeta `json:"metadata,omitempty"` + metav1.ListMeta `json:"metadata"` // Slice containing all secure values. This will NOT output decrypted values. Items []SecureValue `json:"items"` diff --git a/pkg/apis/secret/v0alpha1/zz_generated.openapi.go b/pkg/apis/secret/v0alpha1/zz_generated.openapi.go index de1934c36cb..836d33f83fa 100644 --- a/pkg/apis/secret/v0alpha1/zz_generated.openapi.go +++ b/pkg/apis/secret/v0alpha1/zz_generated.openapi.go @@ -554,7 +554,7 @@ func schema_pkg_apis_secret_v0alpha1_SecureValue(ref common.ReferenceCallback) c }, }, }, - Required: []string{"spec"}, + Required: []string{"spec", "status"}, }, }, Dependencies: []string{ @@ -690,20 +690,11 @@ func schema_pkg_apis_secret_v0alpha1_SecureValueStatus(ref common.ReferenceCallb SchemaProps: spec.SchemaProps{ Type: []string{"object"}, Properties: map[string]spec.Schema{ - "phase": { + "version": { SchemaProps: spec.SchemaProps{ - Description: "High-level summary of where the `SecureValue` is in its lifecycle. One of: `Pending`, `Succeeded` or `Failed`.\n\nPossible enum values:\n - `\"Failed\"` If the creation of the secret fails, it will move to the `Failed` phase. Check the additional `status` fields for more information on what caused the failure. This state is unrecoverable.\n - `\"Pending\"` When the `SecureValue` is created, it will start in `Pending` phase to create the underlying secret asynchronously.\n - `\"Succeeded\"` If the creation of the secret is successful, it will move to the `Succeeded` phase.", - Default: "", - Type: []string{"string"}, - Format: "", - Enum: []interface{}{"Failed", "Pending", "Succeeded"}, - }, - }, - "message": { - SchemaProps: spec.SchemaProps{ - Description: "A human readable message indicating details about why the `SecureValue` is in this phase. Only applicable if the `phase=Failed`.", - Type: []string{"string"}, - Format: "", + Default: 0, + Type: []string{"integer"}, + Format: "int64", }, }, "externalId": { @@ -713,7 +704,7 @@ func schema_pkg_apis_secret_v0alpha1_SecureValueStatus(ref common.ReferenceCallb }, }, }, - Required: []string{"phase"}, + Required: []string{"version"}, }, }, } diff --git a/pkg/apis/secret/v0alpha1/zz_generated.openapi_violation_exceptions.list b/pkg/apis/secret/v0alpha1/zz_generated.openapi_violation_exceptions.list index 679e6938ae0..0487679a6a6 100644 --- a/pkg/apis/secret/v0alpha1/zz_generated.openapi_violation_exceptions.list +++ b/pkg/apis/secret/v0alpha1/zz_generated.openapi_violation_exceptions.list @@ -6,3 +6,4 @@ API rule violation: names_match,github.com/grafana/grafana/pkg/apis/secret/v0alp API rule violation: names_match,github.com/grafana/grafana/pkg/apis/secret/v0alpha1,KeeperSpec,Azure API rule violation: names_match,github.com/grafana/grafana/pkg/apis/secret/v0alpha1,KeeperSpec,HashiCorp API rule violation: names_match,github.com/grafana/grafana/pkg/apis/secret/v0alpha1,SecureValueStatus,ExternalID +API rule violation: streaming_list_type_json_tags,github.com/grafana/grafana/pkg/apis/secret/v0alpha1,SecureValueList,ListMeta diff --git a/pkg/registry/apis/secret/contracts/outbox_queue.go b/pkg/registry/apis/secret/contracts/outbox_queue.go deleted file mode 100644 index 767273b1254..00000000000 --- a/pkg/registry/apis/secret/contracts/outbox_queue.go +++ /dev/null @@ -1,64 +0,0 @@ -package contracts - -import ( - "context" -) - -type contextRequestIdKey struct{} - -type OutboxMessageType string - -func GetRequestId(ctx context.Context) string { - v := ctx.Value(contextRequestIdKey{}) - requestId, ok := v.(string) - if !ok { - return "" - } - - return requestId -} - -func ContextWithRequestID(ctx context.Context, requestId string) context.Context { - return context.WithValue(ctx, contextRequestIdKey{}, requestId) -} - -const ( - CreateSecretOutboxMessage OutboxMessageType = "create" - UpdateSecretOutboxMessage OutboxMessageType = "update" - DeleteSecretOutboxMessage OutboxMessageType = "delete" -) - -type AppendOutboxMessage struct { - RequestID string - Type OutboxMessageType - Name string - Namespace string - EncryptedSecret string - KeeperName *string - ExternalID *string -} - -type OutboxMessage struct { - RequestID string - Type OutboxMessageType - MessageID int64 - Name string - Namespace string - EncryptedSecret string - KeeperName *string - ExternalID *string - // How many times this message has been received - ReceiveCount int - Created int64 -} - -type OutboxQueue interface { - // Appends a message to the outbox queue - Append(ctx context.Context, message AppendOutboxMessage) (int64, error) - // Receives at most n messages from the outbox queue - ReceiveN(ctx context.Context, n uint) ([]OutboxMessage, error) - // Deletes a message from the outbox queue - Delete(ctx context.Context, messageID int64) error - // Increments the number of times each message has been received by 1. Must be atomic. - IncrementReceiveCount(ctx context.Context, messageIDs []int64) error -} diff --git a/pkg/registry/apis/secret/contracts/secure_value.go b/pkg/registry/apis/secret/contracts/secure_value.go index ca3f66f991d..94bde58c68e 100644 --- a/pkg/registry/apis/secret/contracts/secure_value.go +++ b/pkg/registry/apis/secret/contracts/secure_value.go @@ -32,10 +32,9 @@ type ReadOpts struct { type SecureValueMetadataStorage interface { Create(ctx context.Context, sv *secretv0alpha1.SecureValue, actorUID string) (*secretv0alpha1.SecureValue, error) Read(ctx context.Context, namespace xkube.Namespace, name string, opts ReadOpts) (*secretv0alpha1.SecureValue, error) - Update(ctx context.Context, sv *secretv0alpha1.SecureValue, actorUID string) (*secretv0alpha1.SecureValue, error) - Delete(ctx context.Context, namespace xkube.Namespace, name string) error List(ctx context.Context, namespace xkube.Namespace) ([]secretv0alpha1.SecureValue, error) - SetStatus(ctx context.Context, namespace xkube.Namespace, name string, status secretv0alpha1.SecureValueStatus) error - SetExternalID(ctx context.Context, namespace xkube.Namespace, name string, externalID ExternalID) error + SetVersionToActive(ctx context.Context, namespace xkube.Namespace, name string, version int64) error + SetVersionToInactive(ctx context.Context, namespace xkube.Namespace, name string, version int64) error + SetExternalID(ctx context.Context, namespace xkube.Namespace, name string, version int64, externalID ExternalID) error ReadForDecrypt(ctx context.Context, namespace xkube.Namespace, name string) (*DecryptSecureValue, error) } diff --git a/pkg/registry/apis/secret/service/secure_value.go b/pkg/registry/apis/secret/service/secure_value.go index e667ad4c4be..01b382edbf7 100644 --- a/pkg/registry/apis/secret/service/secure_value.go +++ b/pkg/registry/apis/secret/service/secure_value.go @@ -5,10 +5,10 @@ import ( "fmt" claims "github.com/grafana/authlib/types" + "github.com/grafana/grafana-app-sdk/logging" "github.com/grafana/grafana/pkg/apimachinery/utils" secretv0alpha1 "github.com/grafana/grafana/pkg/apis/secret/v0alpha1" "github.com/grafana/grafana/pkg/registry/apis/secret/contracts" - "github.com/grafana/grafana/pkg/registry/apis/secret/tracectx" "github.com/grafana/grafana/pkg/registry/apis/secret/xkube" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" @@ -19,8 +19,8 @@ type SecureValueService struct { accessClient claims.AccessClient database contracts.Database secureValueMetadataStorage contracts.SecureValueMetadataStorage - outboxQueue contracts.OutboxQueue - encryptionManager contracts.EncryptionManager + keeperMetadataStorage contracts.KeeperMetadataStorage + keeperService contracts.KeeperService } func ProvideSecureValueService( @@ -28,16 +28,16 @@ func ProvideSecureValueService( accessClient claims.AccessClient, database contracts.Database, secureValueMetadataStorage contracts.SecureValueMetadataStorage, - outboxQueue contracts.OutboxQueue, - encryptionManager contracts.EncryptionManager, + keeperMetadataStorage contracts.KeeperMetadataStorage, + keeperService contracts.KeeperService, ) *SecureValueService { return &SecureValueService{ tracer: tracer, accessClient: accessClient, database: database, secureValueMetadataStorage: secureValueMetadataStorage, - outboxQueue: outboxQueue, - encryptionManager: encryptionManager, + keeperMetadataStorage: keeperMetadataStorage, + keeperService: keeperService, } } @@ -48,43 +48,91 @@ func (s *SecureValueService) Create(ctx context.Context, sv *secretv0alpha1.Secu attribute.String("actor", actorUID), )) defer span.End() + return s.createNewVersion(ctx, sv, actorUID) +} - sv.Status = secretv0alpha1.SecureValueStatus{Phase: secretv0alpha1.SecureValuePhasePending, Message: "Creating secure value"} - - var out *secretv0alpha1.SecureValue +func (s *SecureValueService) Update(ctx context.Context, newSecureValue *secretv0alpha1.SecureValue, actorUID string) (*secretv0alpha1.SecureValue, bool, error) { + ctx, span := s.tracer.Start(ctx, "SecureValueService.Update", trace.WithAttributes( + attribute.String("name", newSecureValue.GetName()), + attribute.String("namespace", newSecureValue.GetNamespace()), + attribute.String("actor", actorUID), + )) + defer span.End() - encryptedSecret, err := s.encryptionManager.Encrypt(ctx, sv.Namespace, []byte(sv.Spec.Value.DangerouslyExposeAndConsumeValue())) - if err != nil { - return nil, fmt.Errorf("encrypting secure value secret: %w", err) - } + if newSecureValue.Spec.Value == "" { + decrypted, err := s.secureValueMetadataStorage.ReadForDecrypt(ctx, xkube.Namespace(newSecureValue.Namespace), newSecureValue.Name) + if err != nil { + return nil, false, fmt.Errorf("reading secure value secret: %+w", err) + } - // Specifically here so that the spans from the worker are not inside the transaction. - requestID := tracectx.HexEncodeTraceFromContext(ctx) + // TODO: does this need to be for update? + keeperCfg, err := s.keeperMetadataStorage.GetKeeperConfig(ctx, newSecureValue.Namespace, newSecureValue.Spec.Keeper, contracts.ReadOpts{ForUpdate: true}) + if err != nil { + return nil, false, fmt.Errorf("fetching keeper config: namespace=%+v keeperName=%+v %w", newSecureValue.Namespace, newSecureValue.Spec.Keeper, err) + } - if err := s.database.Transaction(ctx, func(ctx context.Context) error { - createdSecureValue, err := s.secureValueMetadataStorage.Create(ctx, sv, actorUID) + keeper, err := s.keeperService.KeeperForConfig(keeperCfg) if err != nil { - return fmt.Errorf("failed to create securevalue: %w", err) + return nil, false, fmt.Errorf("getting keeper for config: namespace=%+v keeperName=%+v %w", newSecureValue.Namespace, newSecureValue.Spec.Keeper, err) } - out = createdSecureValue - - if _, err := s.outboxQueue.Append(ctx, contracts.AppendOutboxMessage{ - RequestID: requestID, - Type: contracts.CreateSecretOutboxMessage, - Name: sv.Name, - Namespace: sv.Namespace, - EncryptedSecret: string(encryptedSecret), - KeeperName: sv.Spec.Keeper, - }); err != nil { - return fmt.Errorf("failed to append message to create secure value to outbox queue: %w", err) + logging.FromContext(ctx).Debug("retrieved keeper", "namespace", newSecureValue.Namespace, "keeperName", newSecureValue.Spec.Keeper, "type", keeperCfg.Type()) + + secret, err := keeper.Expose(ctx, keeperCfg, newSecureValue.Namespace, contracts.ExternalID(decrypted.ExternalID)) + if err != nil { + return nil, false, fmt.Errorf("reading secret value from keeper: %w", err) } - return nil - }); err != nil { - return out, err + newSecureValue.Spec.Value = secret + } + + const updateIsSync = true + createdSv, err := s.createNewVersion(ctx, newSecureValue, actorUID) + return createdSv, updateIsSync, err +} + +func (s *SecureValueService) createNewVersion(ctx context.Context, sv *secretv0alpha1.SecureValue, actorUID string) (*secretv0alpha1.SecureValue, error) { + createdSv, err := s.secureValueMetadataStorage.Create(ctx, sv, actorUID) + if err != nil { + return nil, fmt.Errorf("creating secure value: %w", err) + } + createdSv.Status = secretv0alpha1.SecureValueStatus{ + Version: createdSv.Status.Version, + } + + // TODO: does this need to be for update? + keeperCfg, err := s.keeperMetadataStorage.GetKeeperConfig(ctx, sv.Namespace, sv.Spec.Keeper, contracts.ReadOpts{ForUpdate: true}) + if err != nil { + return nil, fmt.Errorf("fetching keeper config: namespace=%+v keeperName=%+v %w", sv.Namespace, sv.Spec.Keeper, err) + } + + keeper, err := s.keeperService.KeeperForConfig(keeperCfg) + if err != nil { + return nil, fmt.Errorf("getting keeper for config: namespace=%+v keeperName=%+v %w", sv.Namespace, sv.Spec.Keeper, err) + } + logging.FromContext(ctx).Debug("retrieved keeper", "namespace", sv.Namespace, "keeperName", sv.Spec.Keeper, "type", keeperCfg.Type()) + + // TODO: can we stop using external id? + // TODO: store uses only the namespace and returns and id. It could be a kv instead. + // TODO: check that the encrypted store works with multiple versions + externalID, err := keeper.Store(ctx, keeperCfg, sv.Namespace, sv.Spec.Value.DangerouslyExposeAndConsumeValue()) + if err != nil { + return nil, fmt.Errorf("storing secure value in keeper: %w", err) + } + createdSv.Status.ExternalID = string(externalID) + + if err := s.secureValueMetadataStorage.SetExternalID(ctx, xkube.Namespace(sv.Namespace), sv.Name, createdSv.Status.Version, externalID); err != nil { + return nil, fmt.Errorf("setting secure value external id: %w", err) + } + + if err := s.secureValueMetadataStorage.SetVersionToActive(ctx, xkube.Namespace(sv.Namespace), sv.Name, createdSv.Status.Version); err != nil { + return nil, fmt.Errorf("marking secure value version as active: %w", err) } - return out, nil + // In a single query: + // TODO: set external id + // TODO: set to active + + return createdSv, nil } func (s *SecureValueService) Read(ctx context.Context, namespace xkube.Namespace, name string) (*secretv0alpha1.SecureValue, error) { @@ -139,84 +187,6 @@ func (s *SecureValueService) List(ctx context.Context, namespace xkube.Namespace }, nil } -func (s *SecureValueService) Update(ctx context.Context, newSecureValue *secretv0alpha1.SecureValue, actorUID string) (*secretv0alpha1.SecureValue, bool, error) { - ctx, span := s.tracer.Start(ctx, "SecureValueService.Create", trace.WithAttributes( - attribute.String("name", newSecureValue.GetName()), - attribute.String("namespace", newSecureValue.GetNamespace()), - attribute.String("actor", actorUID), - )) - defer span.End() - - // True when the effects of an update can be seen immediately. - // Never true in this case since updating a secure value is async. - const updateIsSync = false - - var ( - out *secretv0alpha1.SecureValue - encryptedSecret string - ) - - if newSecureValue.Spec.Value != "" { - buffer, err := s.encryptionManager.Encrypt(ctx, newSecureValue.Namespace, []byte(newSecureValue.Spec.Value.DangerouslyExposeAndConsumeValue())) - if err != nil { - return nil, false, fmt.Errorf("encrypting secure value secret: %w", err) - } - encryptedSecret = string(buffer) - } - - // Especifically here so that the spans from the worker are not inside the transaction. - requestID := tracectx.HexEncodeTraceFromContext(ctx) - - if err := s.database.Transaction(ctx, func(ctx context.Context) error { - sv, err := s.secureValueMetadataStorage.Read(ctx, xkube.Namespace(newSecureValue.Namespace), newSecureValue.Name, contracts.ReadOpts{ForUpdate: true}) - if err != nil { - return fmt.Errorf("fetching secure value: %+w", err) - } - - if sv.Status.Phase == secretv0alpha1.SecureValuePhasePending { - return contracts.ErrSecureValueOperationInProgress - } - - // Succeed immediately if the value is not going to be updated - if encryptedSecret == "" { - newSecureValue.Status = secretv0alpha1.SecureValueStatus{Phase: secretv0alpha1.SecureValuePhaseSucceeded} - } else { - newSecureValue.Status = secretv0alpha1.SecureValueStatus{ - Message: "Updating secure value", - Phase: secretv0alpha1.SecureValuePhasePending, - } - } - - // Current implementation replaces everything passed in the spec, so it is not a PATCH. Do we want/need to support that? - updatedSecureValue, err := s.secureValueMetadataStorage.Update(ctx, newSecureValue, actorUID) - if err != nil { - return fmt.Errorf("failed to update secure value: %w", err) - } - out = updatedSecureValue - - // Only the value needs to be updated asynchronously by the outbox worker - if encryptedSecret != "" { - if _, err := s.outboxQueue.Append(ctx, contracts.AppendOutboxMessage{ - RequestID: requestID, - Type: contracts.UpdateSecretOutboxMessage, - Name: newSecureValue.Name, - Namespace: newSecureValue.Namespace, - EncryptedSecret: encryptedSecret, - KeeperName: newSecureValue.Spec.Keeper, - ExternalID: &updatedSecureValue.Status.ExternalID, - }); err != nil { - return fmt.Errorf("failed to append message to update secure value to outbox queue: %w", err) - } - } - - return nil - }); err != nil { - return out, updateIsSync, err - } - - return out, updateIsSync, nil -} - func (s *SecureValueService) Delete(ctx context.Context, namespace xkube.Namespace, name string) (*secretv0alpha1.SecureValue, error) { ctx, span := s.tracer.Start(ctx, "SecureValueService.Delete", trace.WithAttributes( attribute.String("name", name), @@ -224,45 +194,14 @@ func (s *SecureValueService) Delete(ctx context.Context, namespace xkube.Namespa )) defer span.End() - // Set inside of the transaction callback - var out *secretv0alpha1.SecureValue - - // Especifically here so that the spans from the worker are not inside the transaction. - requestID := tracectx.HexEncodeTraceFromContext(ctx) - - if err := s.database.Transaction(ctx, func(ctx context.Context) error { - sv, err := s.secureValueMetadataStorage.Read(ctx, namespace, name, contracts.ReadOpts{ForUpdate: true}) - if err != nil { - return fmt.Errorf("fetching secure value: %+w", err) - } - - if sv.Status.Phase == secretv0alpha1.SecureValuePhasePending { - return contracts.ErrSecureValueOperationInProgress - } - - sv.Status = secretv0alpha1.SecureValueStatus{Phase: secretv0alpha1.SecureValuePhasePending, Message: "Deleting secure value"} - - if err := s.secureValueMetadataStorage.SetStatus(ctx, namespace, name, sv.Status); err != nil { - return fmt.Errorf("setting secure value status phase: %+w", err) - } - - if _, err := s.outboxQueue.Append(ctx, contracts.AppendOutboxMessage{ - RequestID: requestID, - Type: contracts.DeleteSecretOutboxMessage, - Name: name, - Namespace: namespace.String(), - KeeperName: sv.Spec.Keeper, - ExternalID: &sv.Status.ExternalID, - }); err != nil { - return fmt.Errorf("appending delete secure value message to outbox queue: %+w", err) - } - - out = sv + sv, err := s.secureValueMetadataStorage.Read(ctx, namespace, name, contracts.ReadOpts{ForUpdate: true}) + if err != nil { + return nil, fmt.Errorf("fetching secure value: %+w", err) + } - return nil - }); err != nil { - return out, err + if err := s.secureValueMetadataStorage.SetVersionToInactive(ctx, namespace, name, sv.Status.Version); err != nil { + return nil, fmt.Errorf("setting secure value version to inactive: %+w", err) } - return out, nil + return sv, nil } diff --git a/pkg/registry/apis/secret/service/secure_value_test.go b/pkg/registry/apis/secret/service/secure_value_test.go new file mode 100644 index 00000000000..865138d097b --- /dev/null +++ b/pkg/registry/apis/secret/service/secure_value_test.go @@ -0,0 +1,94 @@ +package service_test + +import ( + "testing" + + "github.com/grafana/grafana/pkg/apis/secret/v0alpha1" + "github.com/grafana/grafana/pkg/registry/apis/secret/contracts" + "github.com/grafana/grafana/pkg/registry/apis/secret/testutils" + "github.com/grafana/grafana/pkg/registry/apis/secret/xkube" + "github.com/stretchr/testify/require" +) + +func TestCrud(t *testing.T) { + t.Parallel() + + t.Run("creating a secure value creates new versions", func(t *testing.T) { + t.Parallel() + sut := testutils.Setup(t) + + sv1, err := sut.CreateSv(t.Context()) + require.NoError(t, err) + + // Create the same secure value twice + input := sv1.DeepCopy() + input.Spec.Description = "d2" + input.Spec.Value = v0alpha1.NewExposedSecureValue("v2") + + sv2, err := sut.CreateSv(t.Context(), testutils.CreateSvWithSv(input)) + require.NoError(t, err) + require.True(t, sv2.Status.Version > sv1.Status.Version) + + // Read the secure value + sv, err := sut.SecureValueService.Read(t.Context(), xkube.Namespace(sv2.Namespace), sv2.Name) + require.NoError(t, err) + + // It should be the latest version + require.Equal(t, sv2.Namespace, sv.Namespace) + require.Equal(t, sv2.Name, sv.Name) + require.Equal(t, "d2", sv.Spec.Description) + require.Equal(t, sv2.Status.Version, sv.Status.Version) + }) + + t.Run("updating a secure value creates new versions", func(t *testing.T) { + t.Parallel() + + sut := testutils.Setup(t) + + // Create a secure value + sv1, err := sut.CreateSv(t.Context()) + require.NoError(t, err) + + ns := sv1.Namespace + name := sv1.Name + + // Update the secure value + input := sv1.DeepCopy() + input.Spec.Description = "d2" + sv2, err := sut.UpdateSv(t.Context(), input) + require.NoError(t, err) + + // Read the secure value + sv3, err := sut.SecureValueService.Read(t.Context(), xkube.Namespace(ns), name) + require.NoError(t, err) + + // Nothing has changed except for the updated field. + require.Equal(t, ns, sv2.Namespace) + require.Equal(t, name, sv2.Name) + require.True(t, sv2.Status.Version > sv1.Status.Version) + require.Equal(t, "d2", sv2.Spec.Description) + + require.Equal(t, ns, sv3.Namespace) + require.Equal(t, name, sv3.Name) + require.Equal(t, sv2.Status.Version, sv3.Status.Version) + require.Equal(t, "d2", sv3.Spec.Description) + }) + + t.Run("deleting secure values", func(t *testing.T) { + t.Parallel() + + sut := testutils.Setup(t) + + sv1, err := sut.CreateSv(t.Context()) + require.NoError(t, err) + + sv2, err := sut.DeleteSv(t.Context(), sv1.Namespace, sv1.Name) + require.NoError(t, err) + + require.Equal(t, sv1.Namespace, sv2.Namespace) + require.Equal(t, sv1.Name, sv2.Name) + + _, err = sut.SecureValueMetadataStorage.Read(t.Context(), xkube.Namespace(sv1.Namespace), sv1.Name, contracts.ReadOpts{}) + require.ErrorIs(t, err, contracts.ErrSecureValueNotFound) + }) +} diff --git a/pkg/registry/apis/secret/testutils/testutils.go b/pkg/registry/apis/secret/testutils/testutils.go index 40e571aca63..281304320c8 100644 --- a/pkg/registry/apis/secret/testutils/testutils.go +++ b/pkg/registry/apis/secret/testutils/testutils.go @@ -3,7 +3,6 @@ package testutils import ( "context" "testing" - "time" secretv0alpha1 "github.com/grafana/grafana/pkg/apis/secret/v0alpha1" encryptionstorage "github.com/grafana/grafana/pkg/storage/secret/encryption" @@ -12,11 +11,11 @@ import ( "github.com/grafana/grafana/pkg/infra/usagestats" "github.com/grafana/grafana/pkg/registry/apis/secret/contracts" + "github.com/grafana/grafana/pkg/registry/apis/secret/decrypt" "github.com/grafana/grafana/pkg/registry/apis/secret/encryption" "github.com/grafana/grafana/pkg/registry/apis/secret/encryption/manager" "github.com/grafana/grafana/pkg/registry/apis/secret/secretkeeper/sqlkeeper" "github.com/grafana/grafana/pkg/registry/apis/secret/service" - "github.com/grafana/grafana/pkg/registry/apis/secret/worker" "github.com/grafana/grafana/pkg/registry/apis/secret/xkube" "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/accesscontrol/actest" @@ -29,35 +28,28 @@ import ( "github.com/stretchr/testify/require" ) -type setupConfig struct { - workerCfg worker.Config - keeperService contracts.KeeperService +type SetupConfig struct { + KeeperService contracts.KeeperService + AllowList map[string]struct{} } -func defaultSetupCfg() setupConfig { - return setupConfig{ - workerCfg: worker.Config{ - BatchSize: 10, - ReceiveTimeout: 1 * time.Second, - PollingInterval: time.Millisecond, - MaxMessageProcessingAttempts: 5, - }, - } +func defaultSetupCfg() SetupConfig { + return SetupConfig{} } -func WithWorkerConfig(cfg worker.Config) func(*setupConfig) { - return func(setupCfg *setupConfig) { - setupCfg.workerCfg = cfg +func WithKeeperService(keeperService contracts.KeeperService) func(*SetupConfig) { + return func(setupCfg *SetupConfig) { + setupCfg.KeeperService = keeperService } } -func WithKeeperService(keeperService contracts.KeeperService) func(*setupConfig) { - return func(setupCfg *setupConfig) { - setupCfg.keeperService = keeperService +func WithMutateCfg(f func(*SetupConfig)) func(*SetupConfig) { + return func(cfg *SetupConfig) { + f(cfg) } } -func Setup(t *testing.T, opts ...func(*setupConfig)) Sut { +func Setup(t *testing.T, opts ...func(*SetupConfig)) Sut { setupCfg := defaultSetupCfg() for _, opt := range opts { opt(&setupCfg) @@ -68,8 +60,6 @@ func Setup(t *testing.T, opts ...func(*setupConfig)) Sut { database := database.ProvideDatabase(testDB, tracer) - outboxQueue := metadata.ProvideOutboxQueue(database, tracer, nil) - features := featuremgmt.WithFeatures(featuremgmt.FlagGrafanaAPIServerWithExperimentalAPIs, featuremgmt.FlagSecretsManagementAppPlatform) keeperMetadataStorage, err := metadata.ProvideKeeperMetadataStorage(database, tracer, features, nil) @@ -111,34 +101,24 @@ func Setup(t *testing.T, opts ...func(*setupConfig)) Sut { var keeperService contracts.KeeperService = newKeeperServiceWrapper(sqlKeeper) - if setupCfg.keeperService != nil { - keeperService = setupCfg.keeperService + if setupCfg.KeeperService != nil { + keeperService = setupCfg.KeeperService } - secureValueService := service.ProvideSecureValueService(tracer, accessClient, database, secureValueMetadataStorage, outboxQueue, encryptionManager) + secureValueService := service.ProvideSecureValueService(tracer, accessClient, database, secureValueMetadataStorage, keeperMetadataStorage, keeperService) - worker, err := worker.NewWorker( - setupCfg.workerCfg, - tracer, - database, - outboxQueue, - secureValueMetadataStorage, - keeperMetadataStorage, - keeperService, - encryptionManager, - features, - nil, // metrics - ) + decryptAuthorizer := decrypt.ProvideDecryptAuthorizer(tracer, setupCfg.AllowList) + + decryptStorage, err := metadata.ProvideDecryptStorage(features, tracer, keeperService, keeperMetadataStorage, secureValueMetadataStorage, decryptAuthorizer, nil) require.NoError(t, err) - return Sut{Worker: worker, SecureValueService: secureValueService, SecureValueMetadataStorage: secureValueMetadataStorage, OutboxQueue: outboxQueue, Database: database} + return Sut{SecureValueService: secureValueService, SecureValueMetadataStorage: secureValueMetadataStorage, Database: database, DecryptStorage: decryptStorage} } type Sut struct { - Worker *worker.Worker SecureValueService *service.SecureValueService SecureValueMetadataStorage contracts.SecureValueMetadataStorage - OutboxQueue contracts.OutboxQueue + DecryptStorage contracts.DecryptStorage Database *database.Database } @@ -163,9 +143,7 @@ func (s *Sut) CreateSv(ctx context.Context, opts ...func(*CreateSvConfig)) (*sec Description: "desc1", Value: secretv0alpha1.NewExposedSecureValue("v1"), }, - Status: secretv0alpha1.SecureValueStatus{ - Phase: secretv0alpha1.SecureValuePhasePending, - }, + Status: secretv0alpha1.SecureValueStatus{}, }, } for _, opt := range opts { diff --git a/pkg/registry/apis/secret/worker/metrics.go b/pkg/registry/apis/secret/worker/metrics.go deleted file mode 100644 index a6f690f7163..00000000000 --- a/pkg/registry/apis/secret/worker/metrics.go +++ /dev/null @@ -1,44 +0,0 @@ -package worker - -import ( - "github.com/prometheus/client_golang/prometheus" -) - -const ( - namespace = "grafana_secrets_manager" - subsystem = "outbox_worker" -) - -// OutboxMetrics is a struct that contains all the metrics for an implementation of the secrets service. -type OutboxMetrics struct { - OutboxMessageProcessingDuration *prometheus.HistogramVec -} - -func newOutboxMetrics() *OutboxMetrics { - return &OutboxMetrics{ - OutboxMessageProcessingDuration: prometheus.NewHistogramVec(prometheus.HistogramOpts{ - Namespace: namespace, - Subsystem: subsystem, - Name: "message_processing_duration_seconds", - Help: "Duration of outbox message processing", - Buckets: prometheus.DefBuckets, - }, []string{"message_type", "keeper_type"}), - } -} - -// NewOutboxMetrics creates a new SecretsMetrics struct containing registered metrics -func NewOutboxMetrics(reg prometheus.Registerer) *OutboxMetrics { - m := newOutboxMetrics() - - if reg != nil { - reg.MustRegister( - m.OutboxMessageProcessingDuration, - ) - } - - return m -} - -func NewTestMetrics() *OutboxMetrics { - return newOutboxMetrics() -} diff --git a/pkg/registry/apis/secret/worker/worker.go b/pkg/registry/apis/secret/worker/worker.go deleted file mode 100644 index 35474fdae47..00000000000 --- a/pkg/registry/apis/secret/worker/worker.go +++ /dev/null @@ -1,274 +0,0 @@ -package worker - -import ( - "context" - "errors" - "fmt" - "time" - - "github.com/grafana/grafana-app-sdk/logging" - secretv0alpha1 "github.com/grafana/grafana/pkg/apis/secret/v0alpha1" - "github.com/grafana/grafana/pkg/registry" - "github.com/grafana/grafana/pkg/registry/apis/secret/contracts" - "github.com/grafana/grafana/pkg/registry/apis/secret/tracectx" - "github.com/grafana/grafana/pkg/registry/apis/secret/xkube" - "github.com/grafana/grafana/pkg/services/featuremgmt" - "github.com/prometheus/client_golang/prometheus" - "go.opentelemetry.io/otel/attribute" - "go.opentelemetry.io/otel/trace" -) - -// Consumes and processes messages from the secure value outbox queue -type Worker struct { - config Config - tracer trace.Tracer - database contracts.Database - outboxQueue contracts.OutboxQueue - secureValueMetadataStorage contracts.SecureValueMetadataStorage - keeperMetadataStorage contracts.KeeperMetadataStorage - keeperService contracts.KeeperService - encryptionManager contracts.EncryptionManager - metrics *OutboxMetrics - enabled bool -} - -// DefaultConfig for the secure value outbox worker. -var DefaultConfig = Config{ - BatchSize: 20, - ReceiveTimeout: 5 * time.Second, - PollingInterval: 100 * time.Millisecond, - MaxMessageProcessingAttempts: 10, -} - -// ProvideWorkerConfig used for wire. -func ProvideWorkerConfig() Config { - return DefaultConfig -} - -type Config struct { - // The max number of messages to fetch from the outbox queue in a batch - BatchSize uint - // How long to wait for a request to fetch messages from the outbox queue - ReceiveTimeout time.Duration - // How often to poll the outbox queue for new messages - PollingInterval time.Duration - // How many tries to try to process a message before marking the operation as failed - MaxMessageProcessingAttempts uint -} - -func NewWorker( - config Config, - tracer trace.Tracer, - database contracts.Database, - outboxQueue contracts.OutboxQueue, - secureValueMetadataStorage contracts.SecureValueMetadataStorage, - keeperMetadataStorage contracts.KeeperMetadataStorage, - keeperService contracts.KeeperService, - encryptionManager contracts.EncryptionManager, - features featuremgmt.FeatureToggles, - reg prometheus.Registerer, -) (*Worker, error) { - if config.BatchSize == 0 { - return nil, fmt.Errorf("config.BatchSize is required") - } - if config.ReceiveTimeout == 0 { - return nil, fmt.Errorf("config.ReceiveTimeout is required") - } - if config.PollingInterval == 0 { - return nil, fmt.Errorf("config.PollingInterval is required") - } - if config.MaxMessageProcessingAttempts == 0 { - return nil, fmt.Errorf("config.MaxMessageProcessingAttempts is required") - } - - // Require both features to be enabled for the worker to run. - enabled := features.IsEnabledGlobally(featuremgmt.FlagGrafanaAPIServerWithExperimentalAPIs) && features.IsEnabledGlobally(featuremgmt.FlagSecretsManagementAppPlatform) - - return &Worker{ - config: config, - tracer: tracer, - database: database, - outboxQueue: outboxQueue, - secureValueMetadataStorage: secureValueMetadataStorage, - keeperMetadataStorage: keeperMetadataStorage, - keeperService: keeperService, - encryptionManager: encryptionManager, - metrics: NewOutboxMetrics(reg), - enabled: enabled, - }, nil -} - -// Ensure that Worker implements the BackgroundService interface, so we can start it as a background service. -var _ registry.BackgroundService = (*Worker)(nil) - -// Run is the main method to drive the worker -func (w *Worker) Run(ctx context.Context) error { - if !w.enabled { - return nil - } - - logging.FromContext(ctx).Debug("starting worker control loop") - - t := time.NewTicker(w.config.PollingInterval) - defer t.Stop() - - for { - select { - // If the context was canceled - case <-ctx.Done(): - // return the reason it was canceled - return ctx.Err() - - // Otherwise try to receive messages - case <-t.C: - if ctx.Err() != nil { - return ctx.Err() - } - - if err := w.ReceiveAndProcessMessages(ctx); err != nil { - logging.FromContext(ctx).Error("receiving outbox messages", "err", err.Error()) - } - } - } -} - -// TODO: don't rollback every message when a single error happens -func (w *Worker) ReceiveAndProcessMessages(ctx context.Context) error { - messageIDs := make([]int64, 0) - - txErr := w.database.Transaction(ctx, func(ctx context.Context) error { - timeoutCtx, cancel := context.WithTimeout(ctx, w.config.ReceiveTimeout) - messages, err := w.outboxQueue.ReceiveN(timeoutCtx, w.config.BatchSize) - cancel() - if err != nil { - return err - } - - for _, message := range messages { - messageIDs = append(messageIDs, message.MessageID) - if err := w.processMessage(ctx, message); err != nil { - return fmt.Errorf("processing message: %+v %w", message, err) - } - } - return nil - }) - - // This call is made outside the transaction to make sure the receive count is updated on rollbacks. - incrementErr := w.outboxQueue.IncrementReceiveCount(ctx, messageIDs) - if incrementErr != nil { - incrementErr = fmt.Errorf("incrementing receive count for outbox message: %w", incrementErr) - } - - return errors.Join(txErr, incrementErr) -} - -func (w *Worker) processMessage(ctx context.Context, message contracts.OutboxMessage) error { - start := time.Now() - keeperType := "unknown" - defer func() { - w.metrics.OutboxMessageProcessingDuration.WithLabelValues(string(message.Type), keeperType).Observe(time.Since(start).Seconds()) - }() - logging.FromContext(ctx).Debug("processing message", "type", message.Type, "name", message.Name, "namespace", message.Namespace, "receiveCount", message.ReceiveCount) - - opts := []trace.SpanStartOption{} - // If there's no request ID in the message, start a new root span and log an error. - ctx, err := tracectx.HexDecodeTraceIntoContext(ctx, message.RequestID) - if err != nil { - opts = append(opts, trace.WithNewRoot()) - logging.FromContext(ctx).Error("decoding trace context from message", "err", err.Error(), "message.requestID", message.RequestID) - } - - opts = append(opts, trace.WithAttributes( - attribute.String("message.requestID", message.RequestID), - attribute.Int64("message.id", message.MessageID), - attribute.String("message.type", string(message.Type)), - attribute.String("message.namespace", message.Namespace), - attribute.String("message.secureValue.name", message.Name), - attribute.Int("message.receive.count", message.ReceiveCount), - )) - - ctx, span := w.tracer.Start(ctx, "Worker.ProcessMessage", opts...) - defer span.End() - - if message.ReceiveCount >= int(w.config.MaxMessageProcessingAttempts) { - if err := w.secureValueMetadataStorage.SetStatus(ctx, xkube.Namespace(message.Namespace), message.Name, secretv0alpha1.SecureValueStatus{Phase: secretv0alpha1.SecureValuePhaseFailed, Message: fmt.Sprintf("Reached max number of attempts to complete operation: %s", message.Type)}); err != nil { - return fmt.Errorf("setting secret metadata status to Succeeded: message=%+v", message) - } - if err := w.outboxQueue.Delete(ctx, message.MessageID); err != nil { - return fmt.Errorf("deleting message from outbox queue: %w", err) - } - return nil - } - - keeperCfg, err := w.keeperMetadataStorage.GetKeeperConfig(ctx, message.Namespace, message.KeeperName, contracts.ReadOpts{ForUpdate: true}) - if err != nil { - return fmt.Errorf("fetching keeper config: namespace=%+v keeperName=%+v %w", message.Namespace, message.KeeperName, err) - } - keeperType = string(keeperCfg.Type()) - - keeper, err := w.keeperService.KeeperForConfig(keeperCfg) - if err != nil { - return fmt.Errorf("getting keeper for config: namespace=%+v keeperName=%+v %w", message.Namespace, message.KeeperName, err) - } - logging.FromContext(ctx).Debug("retrieved keeper", "namespace", message.Namespace, "keeperName", message.KeeperName, "type", keeperCfg.Type()) - - switch message.Type { - case contracts.CreateSecretOutboxMessage: - rawSecret, err := w.encryptionManager.Decrypt(ctx, message.Namespace, []byte(message.EncryptedSecret)) - if err != nil { - return fmt.Errorf("decrypting secure value secret: %w", err) - } - - externalID, err := keeper.Store(ctx, keeperCfg, message.Namespace, string(rawSecret)) - if err != nil { - return fmt.Errorf("storing secret: message=%+v %w", message, err) - } - - if err := w.secureValueMetadataStorage.SetExternalID(ctx, xkube.Namespace(message.Namespace), message.Name, externalID); err != nil { - return fmt.Errorf("setting secret metadata externalID: externalID=%+v message=%+v %w", externalID, message, err) - } - - // Setting the status to Succeeded must be the last action - // since it acts as a fence to clients. - if err := w.secureValueMetadataStorage.SetStatus(ctx, xkube.Namespace(message.Namespace), message.Name, secretv0alpha1.SecureValueStatus{Phase: secretv0alpha1.SecureValuePhaseSucceeded}); err != nil { - return fmt.Errorf("setting secret metadata status to Succeeded: message=%+v %w", message, err) - } - - case contracts.UpdateSecretOutboxMessage: - rawSecret, err := w.encryptionManager.Decrypt(ctx, message.Namespace, []byte(message.EncryptedSecret)) - if err != nil { - return fmt.Errorf("decrypting secure value secret: %w", err) - } - - if err := keeper.Update(ctx, keeperCfg, message.Namespace, contracts.ExternalID(*message.ExternalID), string(rawSecret)); err != nil { - return fmt.Errorf("calling keeper to update secret: %w", err) - } - - // Setting the status to Succeeded must be the last action - // since it acts as a fence to clients. - if err := w.secureValueMetadataStorage.SetStatus(ctx, xkube.Namespace(message.Namespace), message.Name, secretv0alpha1.SecureValueStatus{Phase: secretv0alpha1.SecureValuePhaseSucceeded}); err != nil { - return fmt.Errorf("setting secret metadata status to Succeeded: message=%+v", message) - } - - case contracts.DeleteSecretOutboxMessage: - if err := keeper.Delete(ctx, keeperCfg, message.Namespace, contracts.ExternalID(*message.ExternalID)); err != nil { - return fmt.Errorf("calling keeper to delete secret: %w", err) - } - if err := w.secureValueMetadataStorage.Delete(ctx, xkube.Namespace(message.Namespace), message.Name); err != nil { - return fmt.Errorf("deleting secure value metadata: %+w", err) - } - - default: - return fmt.Errorf("unhandled message type: %s", message.Type) - } - - // Delete the message from the queue after completing all operations because - // if the message is deleted first, the response may be lost, - // resulting in an error, but since the message was actually deleted - // the worker would never retry. - if err := w.outboxQueue.Delete(ctx, message.MessageID); err != nil { - return fmt.Errorf("deleting message from outbox queue: %w", err) - } - - return nil -} diff --git a/pkg/registry/apis/secret/worker/worker_test.go b/pkg/registry/apis/secret/worker/worker_test.go deleted file mode 100644 index 0d20a668e52..00000000000 --- a/pkg/registry/apis/secret/worker/worker_test.go +++ /dev/null @@ -1,246 +0,0 @@ -package worker_test - -import ( - "context" - "fmt" - "testing" - "time" - - secretv0alpha1 "github.com/grafana/grafana/pkg/apis/secret/v0alpha1" - "github.com/grafana/grafana/pkg/registry/apis/secret/contracts" - "github.com/grafana/grafana/pkg/registry/apis/secret/testutils" - "github.com/grafana/grafana/pkg/registry/apis/secret/worker" - "github.com/grafana/grafana/pkg/registry/apis/secret/xkube" - "github.com/stretchr/testify/require" -) - -type fakeKeeperService struct { - keeperForConfigFunc func(cfg secretv0alpha1.KeeperConfig) (contracts.Keeper, error) -} - -func newFakeKeeperService(keeperForConfigFunc func(cfg secretv0alpha1.KeeperConfig) (contracts.Keeper, error)) *fakeKeeperService { - return &fakeKeeperService{keeperForConfigFunc: keeperForConfigFunc} -} - -func (s *fakeKeeperService) KeeperForConfig(cfg secretv0alpha1.KeeperConfig) (contracts.Keeper, error) { - return s.keeperForConfigFunc(cfg) -} - -func TestProcessMessage(t *testing.T) { - t.Parallel() - - t.Run("secure value metadata status is set to Failed when processing a message fails too many times", func(t *testing.T) { - t.Parallel() - - // Given a worker that will attempt to process a message N times - workerCfg := worker.Config{ - BatchSize: 10, - ReceiveTimeout: 1 * time.Second, - PollingInterval: time.Millisecond, - MaxMessageProcessingAttempts: 2, - } - - // And an error that keeps happening - keeperService := newFakeKeeperService(func(cfg secretv0alpha1.KeeperConfig) (contracts.Keeper, error) { - return nil, fmt.Errorf("oops") - }) - - sut := testutils.Setup(t, testutils.WithWorkerConfig(workerCfg), testutils.WithKeeperService(keeperService)) - ctx := context.Background() - - // Queue a create secure value operation - sv, err := sut.CreateSv(ctx) - require.NoError(t, err) - - for range workerCfg.MaxMessageProcessingAttempts + 1 { - // The secure value status should be Pending while the worker is trying to process the message - sv, err = sut.SecureValueMetadataStorage.Read(ctx, xkube.Namespace(sv.Namespace), sv.Name, contracts.ReadOpts{}) - require.NoError(t, err) - require.Equal(t, secretv0alpha1.SecureValuePhasePending, sv.Status.Phase) - - // Worker tries to process messages - _ = sut.Worker.ReceiveAndProcessMessages(ctx) - } - - // After the worker fails to process a message too many times, - // the secure value status is changed to Failed - sv, err = sut.SecureValueMetadataStorage.Read(ctx, xkube.Namespace(sv.Namespace), sv.Name, contracts.ReadOpts{}) - require.NoError(t, err) - require.Equal(t, secretv0alpha1.SecureValuePhaseFailed, sv.Status.Phase) - - messages, err := sut.OutboxQueue.ReceiveN(ctx, 100) - require.NoError(t, err) - require.Empty(t, messages) - }) - - t.Run("create sv: secure value metadata status is set to Succeeded when message is processed successfully", func(t *testing.T) { - t.Parallel() - - sut := testutils.Setup(t) - ctx := context.Background() - - // Queue a create secure value operation - sv, err := sut.CreateSv(ctx) - require.NoError(t, err) - - // Worker receives and processes the message - require.NoError(t, sut.Worker.ReceiveAndProcessMessages(ctx)) - - // and sets the secure value status to Succeeded - sv, err = sut.SecureValueMetadataStorage.Read(ctx, xkube.Namespace(sv.Namespace), sv.Name, contracts.ReadOpts{}) - require.NoError(t, err) - require.Equal(t, secretv0alpha1.SecureValuePhaseSucceeded, sv.Status.Phase) - - messages, err := sut.OutboxQueue.ReceiveN(ctx, 100) - require.NoError(t, err) - require.Empty(t, messages) - }) - - t.Run("update sv: secure value metadata status is set to Succeeded when message is processed successfully", func(t *testing.T) { - t.Parallel() - - sut := testutils.Setup(t) - ctx := context.Background() - - // Queue a create secure value operation - sv, err := sut.CreateSv(ctx) - require.NoError(t, err) - - // Worker receives and processes the message - require.NoError(t, sut.Worker.ReceiveAndProcessMessages(ctx)) - - // and sets the secure value status to Succeeded - sv, err = sut.SecureValueMetadataStorage.Read(ctx, xkube.Namespace(sv.Namespace), sv.Name, contracts.ReadOpts{}) - require.NoError(t, err) - require.Equal(t, secretv0alpha1.SecureValuePhaseSucceeded, sv.Status.Phase) - - sv.Spec.Description = "desc2" - sv.Spec.Value = secretv0alpha1.NewExposedSecureValue("v2") - - // Queue an update operation - sv, err = sut.UpdateSv(ctx, sv) - require.NoError(t, err) - require.Equal(t, secretv0alpha1.SecureValuePhasePending, sv.Status.Phase) - - // Worker receives and processes the message - require.NoError(t, sut.Worker.ReceiveAndProcessMessages(ctx)) - updatedSv, err := sut.SecureValueMetadataStorage.Read(ctx, xkube.Namespace(sv.Namespace), sv.Name, contracts.ReadOpts{}) - require.NoError(t, err) - require.Equal(t, secretv0alpha1.SecureValuePhaseSucceeded, updatedSv.Status.Phase) - require.Equal(t, sv.Spec.Description, updatedSv.Spec.Description) - - messages, err := sut.OutboxQueue.ReceiveN(ctx, 100) - require.NoError(t, err) - require.Empty(t, messages) - }) - - t.Run("delete sv: secure value metadata is deleted", func(t *testing.T) { - t.Parallel() - - sut := testutils.Setup(t) - ctx := context.Background() - - // Queue a create secure value operation - sv, err := sut.CreateSv(ctx) - require.NoError(t, err) - - // Worker receives and processes the message - require.NoError(t, sut.Worker.ReceiveAndProcessMessages(ctx)) - - // and sets the secure value status to Succeeded - sv, err = sut.SecureValueMetadataStorage.Read(ctx, xkube.Namespace(sv.Namespace), sv.Name, contracts.ReadOpts{}) - require.NoError(t, err) - require.Equal(t, secretv0alpha1.SecureValuePhaseSucceeded, sv.Status.Phase) - - // Queue a delete operation - updatedSv, err := sut.DeleteSv(ctx, sv.Namespace, sv.Name) - require.NoError(t, err) - require.Equal(t, secretv0alpha1.SecureValuePhasePending, updatedSv.Status.Phase) - - // Worker receives and processes the message - require.NoError(t, sut.Worker.ReceiveAndProcessMessages(ctx)) - - // The secure value has been deleted - _, err = sut.SecureValueMetadataStorage.Read(ctx, xkube.Namespace(sv.Namespace), sv.Name, contracts.ReadOpts{}) - require.ErrorIs(t, err, contracts.ErrSecureValueNotFound) - - messages, err := sut.OutboxQueue.ReceiveN(ctx, 100) - require.NoError(t, err) - require.Empty(t, messages) - }) - - t.Run("when creating a secure value, the secret is encrypted before it is added to the outbox queue", func(t *testing.T) { - t.Parallel() - - sut := testutils.Setup(t) - ctx := context.Background() - - // Queue a create secure value operation - var secret string - _, err := sut.CreateSv(ctx, func(cfg *testutils.CreateSvConfig) { - secret = string(cfg.Sv.Spec.Value) - }) - require.NoError(t, err) - - messages, err := sut.OutboxQueue.ReceiveN(ctx, 100) - require.NoError(t, err) - require.Equal(t, 1, len(messages)) - - encryptedSecret := messages[0].EncryptedSecret - require.NotEmpty(t, secret) - require.NotEmpty(t, encryptedSecret) - require.NotEqual(t, secret, encryptedSecret) - }) - - t.Run("when updating a secure value, the secret is encrypted before it is added to the outbox queue", func(t *testing.T) { - t.Parallel() - - sut := testutils.Setup(t) - ctx := context.Background() - - // Queue a create secure value operation - sv, err := sut.CreateSv(ctx) - require.NoError(t, err) - sv.Spec.Value = secretv0alpha1.NewExposedSecureValue("v2") - - require.NoError(t, sut.Worker.ReceiveAndProcessMessages(ctx)) - - newValue := "v2" - sv.Spec.Value = secretv0alpha1.NewExposedSecureValue(newValue) - - // Queue an update secure value operation - _, err = sut.UpdateSv(ctx, sv) - require.NoError(t, err) - - messages, err := sut.OutboxQueue.ReceiveN(ctx, 100) - require.NoError(t, err) - require.Equal(t, 1, len(messages)) - - encryptedSecret := messages[0].EncryptedSecret - require.NotEmpty(t, encryptedSecret) - require.NotEqual(t, newValue, encryptedSecret) - }) - - t.Run("when deleting a secure value, no value is added to the outbox message", func(t *testing.T) { - t.Parallel() - - sut := testutils.Setup(t) - ctx := context.Background() - - // Queue a create secure value operation - sv, err := sut.CreateSv(ctx) - require.NoError(t, err) - sv.Spec.Value = secretv0alpha1.NewExposedSecureValue("v2") - - require.NoError(t, sut.Worker.ReceiveAndProcessMessages(ctx)) - - // Queue a delete secure value operation - _, err = sut.DeleteSv(ctx, sv.Namespace, sv.Name) - require.NoError(t, err) - - messages, err := sut.OutboxQueue.ReceiveN(ctx, 100) - require.NoError(t, err) - require.Equal(t, 1, len(messages)) - require.Empty(t, messages[0].EncryptedSecret) - }) -} diff --git a/pkg/registry/backgroundsvcs/background_services.go b/pkg/registry/backgroundsvcs/background_services.go index d8a9010bfd2..f6ae88f9dd1 100644 --- a/pkg/registry/backgroundsvcs/background_services.go +++ b/pkg/registry/backgroundsvcs/background_services.go @@ -9,7 +9,6 @@ import ( "github.com/grafana/grafana/pkg/infra/usagestats/statscollector" "github.com/grafana/grafana/pkg/registry" apiregistry "github.com/grafana/grafana/pkg/registry/apis" - secretworker "github.com/grafana/grafana/pkg/registry/apis/secret/worker" appregistry "github.com/grafana/grafana/pkg/registry/apps" "github.com/grafana/grafana/pkg/services/accesscontrol/dualwrite" "github.com/grafana/grafana/pkg/services/anonymous/anonimpl" @@ -71,7 +70,6 @@ func ProvideBackgroundServiceRegistry( appRegistry *appregistry.Service, pluginDashboardUpdater *plugindashboardsservice.DashboardUpdater, dashboardServiceImpl *service.DashboardServiceImpl, - secretManagerWorker *secretworker.Worker, // Need to make sure these are initialized, is there a better place to put them? _ dashboardsnapshots.Service, _ serviceaccounts.Service, @@ -119,7 +117,6 @@ func ProvideBackgroundServiceRegistry( appRegistry, pluginDashboardUpdater, dashboardServiceImpl, - secretManagerWorker, ) } diff --git a/pkg/server/wire.go b/pkg/server/wire.go index efb82d04bc0..2004a813b11 100644 --- a/pkg/server/wire.go +++ b/pkg/server/wire.go @@ -46,7 +46,6 @@ import ( gsmEncryption "github.com/grafana/grafana/pkg/registry/apis/secret/encryption" encryptionManager "github.com/grafana/grafana/pkg/registry/apis/secret/encryption/manager" secretsecurevalueservice "github.com/grafana/grafana/pkg/registry/apis/secret/service" - secretworker "github.com/grafana/grafana/pkg/registry/apis/secret/worker" appregistry "github.com/grafana/grafana/pkg/registry/apps" "github.com/grafana/grafana/pkg/services/accesscontrol" "github.com/grafana/grafana/pkg/services/accesscontrol/acimpl" @@ -431,15 +430,12 @@ var wireBasicSet = wire.NewSet( secretdecrypt.ProvideDecryptAllowList, secretencryption.ProvideDataKeyStorage, secretencryption.ProvideEncryptedValueStorage, - secretmetadata.ProvideOutboxQueue, secretsecurevalueservice.ProvideSecureValueService, secretmigrator.NewWithEngine, secretdatabase.ProvideDatabase, wire.Bind(new(secretcontracts.Database), new(*secretdatabase.Database)), encryptionManager.ProvideEncryptionManager, gsmEncryption.ProvideThirdPartyProviderMap, - secretworker.ProvideWorkerConfig, - secretworker.NewWorker, // Unified storage resource.ProvideStorageMetrics, resource.ProvideIndexMetrics, diff --git a/pkg/server/wire_gen.go b/pkg/server/wire_gen.go index 166c20a19dc..6f93fc62f37 100644 --- a/pkg/server/wire_gen.go +++ b/pkg/server/wire_gen.go @@ -61,11 +61,9 @@ import ( "github.com/grafana/grafana/pkg/registry/apis/secret" "github.com/grafana/grafana/pkg/registry/apis/secret/contracts" "github.com/grafana/grafana/pkg/registry/apis/secret/decrypt" - encryption2 "github.com/grafana/grafana/pkg/registry/apis/secret/encryption" + encryption3 "github.com/grafana/grafana/pkg/registry/apis/secret/encryption" manager4 "github.com/grafana/grafana/pkg/registry/apis/secret/encryption/manager" - "github.com/grafana/grafana/pkg/registry/apis/secret/secretkeeper" service11 "github.com/grafana/grafana/pkg/registry/apis/secret/service" - "github.com/grafana/grafana/pkg/registry/apis/secret/worker" "github.com/grafana/grafana/pkg/registry/apis/userstorage" "github.com/grafana/grafana/pkg/registry/apps" advisor2 "github.com/grafana/grafana/pkg/registry/apps/advisor" @@ -114,7 +112,7 @@ import ( "github.com/grafana/grafana/pkg/services/datasources" "github.com/grafana/grafana/pkg/services/datasources/guardian" service7 "github.com/grafana/grafana/pkg/services/datasources/service" - encryption3 "github.com/grafana/grafana/pkg/services/encryption" + "github.com/grafana/grafana/pkg/services/encryption" "github.com/grafana/grafana/pkg/services/encryption/provider" service2 "github.com/grafana/grafana/pkg/services/encryption/service" "github.com/grafana/grafana/pkg/services/extsvcauth" @@ -236,7 +234,7 @@ import ( "github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/storage/legacysql/dualwrite" database5 "github.com/grafana/grafana/pkg/storage/secret/database" - "github.com/grafana/grafana/pkg/storage/secret/encryption" + encryption2 "github.com/grafana/grafana/pkg/storage/secret/encryption" "github.com/grafana/grafana/pkg/storage/secret/metadata" migrator2 "github.com/grafana/grafana/pkg/storage/secret/migrator" "github.com/grafana/grafana/pkg/storage/unified" @@ -705,38 +703,6 @@ func Initialize(cfg *setting.Cfg, opts Options, apiOpts api.ServerOptions) (*Ser } importDashboardService := service9.ProvideService(routeRegisterImpl, quotaService, service12, pluginstoreService, libraryPanelService, dashboardService, accessControl, folderimplService, featureToggles) dashboardUpdater := service6.ProvideDashboardUpdater(inProcBus, pluginstoreService, service12, importDashboardService, service11, pluginService, dashboardService) - config := worker.ProvideWorkerConfig() - databaseDatabase := database5.ProvideDatabase(sqlStore, tracer) - outboxQueue := metadata.ProvideOutboxQueue(databaseDatabase, tracer, registerer) - secureValueMetadataStorage, err := metadata.ProvideSecureValueMetadataStorage(databaseDatabase, tracer, featureToggles, registerer) - if err != nil { - return nil, err - } - keeperMetadataStorage, err := metadata.ProvideKeeperMetadataStorage(databaseDatabase, tracer, featureToggles, registerer) - if err != nil { - return nil, err - } - encryptedValueStorage, err := encryption.ProvideEncryptedValueStorage(databaseDatabase, tracer, featureToggles) - if err != nil { - return nil, err - } - dataKeyStorage, err := encryption.ProvideDataKeyStorage(databaseDatabase, tracer, featureToggles, registerer) - if err != nil { - return nil, err - } - providerMap := encryption2.ProvideThirdPartyProviderMap() - encryptionManager, err := manager4.ProvideEncryptionManager(tracer, dataKeyStorage, cfg, usageStats, providerMap) - if err != nil { - return nil, err - } - ossKeeperService, err := secretkeeper.ProvideService(tracer, encryptedValueStorage, encryptionManager, registerer) - if err != nil { - return nil, err - } - workerWorker, err := worker.NewWorker(config, tracer, databaseDatabase, outboxQueue, secureValueMetadataStorage, keeperMetadataStorage, ossKeeperService, encryptionManager, featureToggles, registerer) - if err != nil { - return nil, err - } sanitizerProvider := sanitizer.ProvideService(renderingService) healthService, err := grpcserver.ProvideHealthService(cfg, grpcserverProvider) if err != nil { @@ -803,7 +769,7 @@ func Initialize(cfg *setting.Cfg, opts Options, apiOpts api.ServerOptions) (*Ser } ossUserProtectionImpl := authinfoimpl.ProvideOSSUserProtectionService() registration := authnimpl.ProvideRegistration(cfg, authnService, orgService, userAuthTokenService, acimplService, permissionRegistry, apikeyService, userService, authService, ossUserProtectionImpl, loginattemptimplService, quotaService, authinfoimplService, renderingService, featureToggles, oauthtokenService, socialService, remoteCache, ldapImpl, ossImpl, tracingService, tempuserService, notificationService) - backgroundServiceRegistry := backgroundsvcs.ProvideBackgroundServiceRegistry(httpServer, alertNG, cleanUpService, grafanaLive, gateway, notificationService, pluginstoreService, renderingService, userAuthTokenService, tracingService, provisioningServiceImpl, usageStats, statscollectorService, grafanaService, pluginsService, internalMetricsService, secretsService, remoteCache, storageService, searchService, entityEventsService, serviceAccountsService, grpcserverProvider, secretMigrationProviderImpl, loginattemptimplService, supportbundlesimplService, metricService, keyRetriever, angulardetectorsproviderDynamic, apiserverService, anonDeviceService, ssosettingsimplService, pluginexternalService, plugininstallerService, zanzanaReconciler, appregistryService, dashboardUpdater, dashboardServiceImpl, workerWorker, serviceImpl, serviceAccountsProxy, sanitizerProvider, healthService, reflectionService, apiService, apiregistryService, idimplService, teamAPI, ssosettingsimplService, cloudmigrationService, registration) + backgroundServiceRegistry := backgroundsvcs.ProvideBackgroundServiceRegistry(httpServer, alertNG, cleanUpService, grafanaLive, gateway, notificationService, pluginstoreService, renderingService, userAuthTokenService, tracingService, provisioningServiceImpl, usageStats, statscollectorService, grafanaService, pluginsService, internalMetricsService, secretsService, remoteCache, storageService, searchService, entityEventsService, serviceAccountsService, grpcserverProvider, secretMigrationProviderImpl, loginattemptimplService, supportbundlesimplService, metricService, keyRetriever, angulardetectorsproviderDynamic, apiserverService, anonDeviceService, ssosettingsimplService, pluginexternalService, plugininstallerService, zanzanaReconciler, appregistryService, dashboardUpdater, dashboardServiceImpl, serviceImpl, serviceAccountsProxy, sanitizerProvider, healthService, reflectionService, apiService, apiregistryService, idimplService, teamAPI, ssosettingsimplService, cloudmigrationService, registration) usageStatsProvidersRegistry := usagestatssvcs.ProvideUsageStatsProvidersRegistry(acimplService, userService) server, err := New(opts, cfg, httpServer, acimplService, provisioningServiceImpl, backgroundServiceRegistry, usageStatsProvidersRegistry, statscollectorService, registerer) if err != nil { @@ -1250,38 +1216,6 @@ func InitializeForTest(t sqlutil.ITestDB, testingT interface { } importDashboardService := service9.ProvideService(routeRegisterImpl, quotaService, service12, pluginstoreService, libraryPanelService, dashboardService, accessControl, folderimplService, featureToggles) dashboardUpdater := service6.ProvideDashboardUpdater(inProcBus, pluginstoreService, service12, importDashboardService, service11, pluginService, dashboardService) - config := worker.ProvideWorkerConfig() - databaseDatabase := database5.ProvideDatabase(sqlStore, tracer) - outboxQueue := metadata.ProvideOutboxQueue(databaseDatabase, tracer, registerer) - secureValueMetadataStorage, err := metadata.ProvideSecureValueMetadataStorage(databaseDatabase, tracer, featureToggles, registerer) - if err != nil { - return nil, err - } - keeperMetadataStorage, err := metadata.ProvideKeeperMetadataStorage(databaseDatabase, tracer, featureToggles, registerer) - if err != nil { - return nil, err - } - encryptedValueStorage, err := encryption.ProvideEncryptedValueStorage(databaseDatabase, tracer, featureToggles) - if err != nil { - return nil, err - } - dataKeyStorage, err := encryption.ProvideDataKeyStorage(databaseDatabase, tracer, featureToggles, registerer) - if err != nil { - return nil, err - } - providerMap := encryption2.ProvideThirdPartyProviderMap() - encryptionManager, err := manager4.ProvideEncryptionManager(tracer, dataKeyStorage, cfg, usageStats, providerMap) - if err != nil { - return nil, err - } - ossKeeperService, err := secretkeeper.ProvideService(tracer, encryptedValueStorage, encryptionManager, registerer) - if err != nil { - return nil, err - } - workerWorker, err := worker.NewWorker(config, tracer, databaseDatabase, outboxQueue, secureValueMetadataStorage, keeperMetadataStorage, ossKeeperService, encryptionManager, featureToggles, registerer) - if err != nil { - return nil, err - } sanitizerProvider := sanitizer.ProvideService(renderingService) healthService, err := grpcserver.ProvideHealthService(cfg, grpcserverProvider) if err != nil { @@ -1348,7 +1282,7 @@ func InitializeForTest(t sqlutil.ITestDB, testingT interface { } ossUserProtectionImpl := authinfoimpl.ProvideOSSUserProtectionService() registration := authnimpl.ProvideRegistration(cfg, authnService, orgService, userAuthTokenService, acimplService, permissionRegistry, apikeyService, userService, authService, ossUserProtectionImpl, loginattemptimplService, quotaService, authinfoimplService, renderingService, featureToggles, oauthtokentestService, socialService, remoteCache, ldapImpl, ossImpl, tracingService, tempuserService, notificationServiceMock) - backgroundServiceRegistry := backgroundsvcs.ProvideBackgroundServiceRegistry(httpServer, alertNG, cleanUpService, grafanaLive, gateway, notificationService, pluginstoreService, renderingService, userAuthTokenService, tracingService, provisioningServiceImpl, usageStats, statscollectorService, grafanaService, pluginsService, internalMetricsService, secretsService, remoteCache, storageService, searchService, entityEventsService, serviceAccountsService, grpcserverProvider, secretMigrationProviderImpl, loginattemptimplService, supportbundlesimplService, metricService, keyRetriever, angulardetectorsproviderDynamic, apiserverService, anonDeviceService, ssosettingsimplService, pluginexternalService, plugininstallerService, zanzanaReconciler, appregistryService, dashboardUpdater, dashboardServiceImpl, workerWorker, serviceImpl, serviceAccountsProxy, sanitizerProvider, healthService, reflectionService, apiService, apiregistryService, idimplService, teamAPI, ssosettingsimplService, cloudmigrationService, registration) + backgroundServiceRegistry := backgroundsvcs.ProvideBackgroundServiceRegistry(httpServer, alertNG, cleanUpService, grafanaLive, gateway, notificationService, pluginstoreService, renderingService, userAuthTokenService, tracingService, provisioningServiceImpl, usageStats, statscollectorService, grafanaService, pluginsService, internalMetricsService, secretsService, remoteCache, storageService, searchService, entityEventsService, serviceAccountsService, grpcserverProvider, secretMigrationProviderImpl, loginattemptimplService, supportbundlesimplService, metricService, keyRetriever, angulardetectorsproviderDynamic, apiserverService, anonDeviceService, ssosettingsimplService, pluginexternalService, plugininstallerService, zanzanaReconciler, appregistryService, dashboardUpdater, dashboardServiceImpl, serviceImpl, serviceAccountsProxy, sanitizerProvider, healthService, reflectionService, apiService, apiregistryService, idimplService, teamAPI, ssosettingsimplService, cloudmigrationService, registration) usageStatsProvidersRegistry := usagestatssvcs.ProvideUsageStatsProvidersRegistry(acimplService, userService) server, err := New(opts, cfg, httpServer, acimplService, provisioningServiceImpl, backgroundServiceRegistry, usageStatsProvidersRegistry, statscollectorService, registerer) if err != nil { @@ -1495,7 +1429,7 @@ var withOTelSet = wire.NewSet( otelTracer, grpcserver.ProvideService, interceptors.ProvideAuthenticator, ) -var wireBasicSet = wire.NewSet(annotationsimpl.ProvideService, wire.Bind(new(annotations.Repository), new(*annotationsimpl.RepositoryImpl)), New, api.ProvideHTTPServer, query.ProvideService, wire.Bind(new(query.Service), new(*query.ServiceImpl)), bus.ProvideBus, wire.Bind(new(bus.Bus), new(*bus.InProcBus)), rendering.ProvideService, wire.Bind(new(rendering.Service), new(*rendering.RenderingService)), routing.ProvideRegister, wire.Bind(new(routing.RouteRegister), new(*routing.RouteRegisterImpl)), hooks.ProvideService, kvstore.ProvideService, localcache.ProvideService, bundleregistry.ProvideService, wire.Bind(new(supportbundles.Service), new(*bundleregistry.Service)), updatemanager.ProvideGrafanaService, updatemanager.ProvidePluginsService, service.ProvideService, wire.Bind(new(usagestats.Service), new(*service.UsageStats)), validator2.ProvideService, legacy.ProvideLegacyMigrator, pluginsintegration.WireSet, dashboards.ProvideFileStoreManager, wire.Bind(new(dashboards.FileStore), new(*dashboards.FileStoreManager)), cloudwatch.ProvideService, cloudmonitoring.ProvideService, azuremonitor.ProvideService, postgres.ProvideService, mysql.ProvideService, mssql.ProvideService, store.ProvideEntityEventsService, dualwrite.ProvideService, httpclientprovider.New, wire.Bind(new(httpclient.Provider), new(*httpclient2.Provider)), serverlock.ProvideService, annotationsimpl.ProvideCleanupService, wire.Bind(new(annotations.Cleaner), new(*annotationsimpl.CleanupServiceImpl)), cleanup.ProvideService, shorturlimpl.ProvideService, wire.Bind(new(shorturls.Service), new(*shorturlimpl.ShortURLService)), queryhistory.ProvideService, wire.Bind(new(queryhistory.Service), new(*queryhistory.QueryHistoryService)), correlations.ProvideService, wire.Bind(new(correlations.Service), new(*correlations.CorrelationsService)), quotaimpl.ProvideService, remotecache.ProvideService, wire.Bind(new(remotecache.CacheStorage), new(*remotecache.RemoteCache)), authinfoimpl.ProvideService, wire.Bind(new(login.AuthInfoService), new(*authinfoimpl.Service)), authinfoimpl.ProvideStore, datasourceproxy.ProvideService, sort.ProvideService, search2.ProvideService, searchV2.ProvideService, searchV2.ProvideSearchHTTPService, store.ProvideService, store.ProvideSystemUsersService, live.ProvideService, pushhttp.ProvideService, contexthandler.ProvideService, service10.ProvideService, wire.Bind(new(service10.LDAP), new(*service10.LDAPImpl)), jwt.ProvideService, wire.Bind(new(jwt.JWTService), new(*jwt.AuthService)), store2.ProvideDBStore, image.ProvideDeleteExpiredService, ngalert.ProvideService, librarypanels.ProvideService, wire.Bind(new(librarypanels.Service), new(*librarypanels.LibraryPanelService)), libraryelements.ProvideService, wire.Bind(new(libraryelements.Service), new(*libraryelements.LibraryElementService)), notifications.ProvideService, notifications.ProvideSmtpService, github.ProvideFactory, tracing.ProvideService, tracing.ProvideTracingConfig, wire.Bind(new(tracing.Tracer), new(*tracing.TracingService)), withOTelSet, testdatasource.ProvideService, api4.ProvideService, opentsdb.ProvideService, socialimpl.ProvideService, influxdb.ProvideService, wire.Bind(new(social.Service), new(*socialimpl.SocialService)), tempo.ProvideService, loki.ProvideService, graphite.ProvideService, prometheus.ProvideService, elasticsearch.ProvideService, pyroscope.ProvideService, parca.ProvideService, zipkin.ProvideService, jaeger.ProvideService, service7.ProvideCacheService, wire.Bind(new(datasources.CacheService), new(*service7.CacheServiceImpl)), service2.ProvideEncryptionService, wire.Bind(new(encryption3.Internal), new(*service2.Service)), manager.ProvideSecretsService, wire.Bind(new(secrets.Service), new(*manager.SecretsService)), database.ProvideSecretsStore, wire.Bind(new(secrets.Store), new(*database.SecretsStoreImpl)), grafanads.ProvideService, wire.Bind(new(dashboardsnapshots.Store), new(*database4.DashboardSnapshotStore)), database4.ProvideStore, wire.Bind(new(dashboardsnapshots.Service), new(*service8.ServiceImpl)), service8.ProvideService, service7.ProvideService, wire.Bind(new(datasources.DataSourceService), new(*service7.Service)), service7.ProvideLegacyDataSourceLookup, retriever.ProvideService, wire.Bind(new(serviceaccounts.ServiceAccountRetriever), new(*retriever.Service)), ossaccesscontrol.ProvideServiceAccountPermissions, wire.Bind(new(accesscontrol.ServiceAccountPermissionsService), new(*ossaccesscontrol.ServiceAccountPermissionsService)), manager2.ProvideServiceAccountsService, proxy.ProvideServiceAccountsProxy, wire.Bind(new(serviceaccounts.Service), new(*proxy.ServiceAccountsProxy)), expr.ProvideService, featuremgmt.ProvideManagerService, featuremgmt.ProvideToggles, featuremgmt.ProvideOpenFeatureService, featuremgmt.ProvideStaticEvaluator, service5.ProvideDashboardServiceImpl, wire.Bind(new(dashboards2.PermissionsRegistrationService), new(*service5.DashboardServiceImpl)), service5.ProvideDashboardService, service5.ProvideDashboardProvisioningService, service5.ProvideDashboardPluginService, database2.ProvideDashboardStore, folderimpl.ProvideService, wire.Bind(new(folder.Service), new(*folderimpl.Service)), folderimpl.ProvideStore, wire.Bind(new(folder.Store), new(*folderimpl.FolderStoreImpl)), folderimpl.ProvideDashboardFolderStore, wire.Bind(new(folder.FolderStore), new(*folderimpl.DashboardFolderStoreImpl)), service9.ProvideService, wire.Bind(new(dashboardimport.Service), new(*service9.ImportDashboardService)), service6.ProvideService, wire.Bind(new(plugindashboards.Service), new(*service6.Service)), service6.ProvideDashboardUpdater, sanitizer.ProvideService, kvstore2.ProvideService, avatar.ProvideAvatarCacheServer, statscollector.ProvideService, csrf.ProvideCSRFFilter, wire.Bind(new(csrf.Service), new(*csrf.CSRF)), ossaccesscontrol.ProvideTeamPermissions, wire.Bind(new(accesscontrol.TeamPermissionsService), new(*ossaccesscontrol.TeamPermissionsService)), ossaccesscontrol.ProvideFolderPermissions, wire.Bind(new(accesscontrol.FolderPermissionsService), new(*ossaccesscontrol.FolderPermissionsService)), ossaccesscontrol.ProvideDashboardPermissions, wire.Bind(new(accesscontrol.DashboardPermissionsService), new(*ossaccesscontrol.DashboardPermissionsService)), ossaccesscontrol.ProvideReceiverPermissionsService, wire.Bind(new(accesscontrol.ReceiverPermissionsService), new(*ossaccesscontrol.ReceiverPermissionsService)), starimpl.ProvideService, playlistimpl.ProvideService, apikeyimpl.ProvideService, dashverimpl.ProvideService, service3.ProvideService, wire.Bind(new(publicdashboards.Service), new(*service3.PublicDashboardServiceImpl)), database3.ProvideStore, wire.Bind(new(publicdashboards.Store), new(*database3.PublicDashboardStoreImpl)), metric.ProvideService, api2.ProvideApi, api3.ProvideApi, userimpl.ProvideService, orgimpl.ProvideService, orgimpl.ProvideDeletionService, statsimpl.ProvideService, grpccontext.ProvideContextHandler, grpcserver.ProvideHealthService, grpcserver.ProvideReflectionService, resolver.ProvideEntityReferenceResolver, teamimpl.ProvideService, teamapi.ProvideTeamAPI, tempuserimpl.ProvideService, loginattemptimpl.ProvideService, wire.Bind(new(loginattempt.Service), new(*loginattemptimpl.Service)), migrations2.ProvideDataSourceMigrationService, migrations2.ProvideSecretMigrationProvider, wire.Bind(new(migrations2.SecretMigrationProvider), new(*migrations2.SecretMigrationProviderImpl)), resourcepermissions.NewActionSetService, wire.Bind(new(accesscontrol.ActionResolver), new(resourcepermissions.ActionSetService)), wire.Bind(new(pluginaccesscontrol.ActionSetRegistry), new(resourcepermissions.ActionSetService)), permreg.ProvidePermissionRegistry, acimpl.ProvideAccessControl, dualwrite2.ProvideZanzanaReconciler, navtreeimpl.ProvideService, wire.Bind(new(accesscontrol.AccessControl), new(*acimpl.AccessControl)), wire.Bind(new(notifications.TempUserStore), new(tempuser.Service)), tagimpl.ProvideService, wire.Bind(new(tag.Service), new(*tagimpl.Service)), authnimpl.ProvideService, authnimpl.ProvideIdentitySynchronizer, authnimpl.ProvideAuthnService, authnimpl.ProvideAuthnServiceAuthenticateOnly, authnimpl.ProvideRegistration, supportbundlesimpl.ProvideService, extsvcaccounts.ProvideExtSvcAccountsService, wire.Bind(new(serviceaccounts.ExtSvcAccountsService), new(*extsvcaccounts.ExtSvcAccountsService)), registry2.ProvideExtSvcRegistry, wire.Bind(new(extsvcauth.ExternalServiceRegistry), new(*registry2.Registry)), anonstore.ProvideAnonDBStore, wire.Bind(new(anonstore.AnonStore), new(*anonstore.AnonDBStore)), loggermw.Provide, slogadapter.Provide, signingkeysimpl.ProvideEmbeddedSigningKeysService, wire.Bind(new(signingkeys.Service), new(*signingkeysimpl.Service)), ssosettingsimpl.ProvideService, wire.Bind(new(ssosettings.Service), new(*ssosettingsimpl.Service)), idimpl.ProvideService, wire.Bind(new(auth.IDService), new(*idimpl.Service)), cloudmigrationimpl.ProvideService, userimpl.ProvideVerifier, connectors.ProvideOrgRoleMapper, wire.Bind(new(user.Verifier), new(*userimpl.Verifier)), authz.WireSet, metadata.ProvideSecureValueMetadataStorage, metadata.ProvideKeeperMetadataStorage, metadata.ProvideDecryptStorage, decrypt.ProvideDecryptAuthorizer, decrypt.ProvideDecryptAllowList, encryption.ProvideDataKeyStorage, encryption.ProvideEncryptedValueStorage, metadata.ProvideOutboxQueue, service11.ProvideSecureValueService, migrator2.NewWithEngine, database5.ProvideDatabase, wire.Bind(new(contracts.Database), new(*database5.Database)), manager4.ProvideEncryptionManager, encryption2.ProvideThirdPartyProviderMap, worker.ProvideWorkerConfig, worker.NewWorker, resource.ProvideStorageMetrics, resource.ProvideIndexMetrics, apiserver.WireSet, apiregistry.WireSet, appregistry.WireSet) +var wireBasicSet = wire.NewSet(annotationsimpl.ProvideService, wire.Bind(new(annotations.Repository), new(*annotationsimpl.RepositoryImpl)), New, api.ProvideHTTPServer, query.ProvideService, wire.Bind(new(query.Service), new(*query.ServiceImpl)), bus.ProvideBus, wire.Bind(new(bus.Bus), new(*bus.InProcBus)), rendering.ProvideService, wire.Bind(new(rendering.Service), new(*rendering.RenderingService)), routing.ProvideRegister, wire.Bind(new(routing.RouteRegister), new(*routing.RouteRegisterImpl)), hooks.ProvideService, kvstore.ProvideService, localcache.ProvideService, bundleregistry.ProvideService, wire.Bind(new(supportbundles.Service), new(*bundleregistry.Service)), updatemanager.ProvideGrafanaService, updatemanager.ProvidePluginsService, service.ProvideService, wire.Bind(new(usagestats.Service), new(*service.UsageStats)), validator2.ProvideService, legacy.ProvideLegacyMigrator, pluginsintegration.WireSet, dashboards.ProvideFileStoreManager, wire.Bind(new(dashboards.FileStore), new(*dashboards.FileStoreManager)), cloudwatch.ProvideService, cloudmonitoring.ProvideService, azuremonitor.ProvideService, postgres.ProvideService, mysql.ProvideService, mssql.ProvideService, store.ProvideEntityEventsService, dualwrite.ProvideService, httpclientprovider.New, wire.Bind(new(httpclient.Provider), new(*httpclient2.Provider)), serverlock.ProvideService, annotationsimpl.ProvideCleanupService, wire.Bind(new(annotations.Cleaner), new(*annotationsimpl.CleanupServiceImpl)), cleanup.ProvideService, shorturlimpl.ProvideService, wire.Bind(new(shorturls.Service), new(*shorturlimpl.ShortURLService)), queryhistory.ProvideService, wire.Bind(new(queryhistory.Service), new(*queryhistory.QueryHistoryService)), correlations.ProvideService, wire.Bind(new(correlations.Service), new(*correlations.CorrelationsService)), quotaimpl.ProvideService, remotecache.ProvideService, wire.Bind(new(remotecache.CacheStorage), new(*remotecache.RemoteCache)), authinfoimpl.ProvideService, wire.Bind(new(login.AuthInfoService), new(*authinfoimpl.Service)), authinfoimpl.ProvideStore, datasourceproxy.ProvideService, sort.ProvideService, search2.ProvideService, searchV2.ProvideService, searchV2.ProvideSearchHTTPService, store.ProvideService, store.ProvideSystemUsersService, live.ProvideService, pushhttp.ProvideService, contexthandler.ProvideService, service10.ProvideService, wire.Bind(new(service10.LDAP), new(*service10.LDAPImpl)), jwt.ProvideService, wire.Bind(new(jwt.JWTService), new(*jwt.AuthService)), store2.ProvideDBStore, image.ProvideDeleteExpiredService, ngalert.ProvideService, librarypanels.ProvideService, wire.Bind(new(librarypanels.Service), new(*librarypanels.LibraryPanelService)), libraryelements.ProvideService, wire.Bind(new(libraryelements.Service), new(*libraryelements.LibraryElementService)), notifications.ProvideService, notifications.ProvideSmtpService, github.ProvideFactory, tracing.ProvideService, tracing.ProvideTracingConfig, wire.Bind(new(tracing.Tracer), new(*tracing.TracingService)), withOTelSet, testdatasource.ProvideService, api4.ProvideService, opentsdb.ProvideService, socialimpl.ProvideService, influxdb.ProvideService, wire.Bind(new(social.Service), new(*socialimpl.SocialService)), tempo.ProvideService, loki.ProvideService, graphite.ProvideService, prometheus.ProvideService, elasticsearch.ProvideService, pyroscope.ProvideService, parca.ProvideService, zipkin.ProvideService, jaeger.ProvideService, service7.ProvideCacheService, wire.Bind(new(datasources.CacheService), new(*service7.CacheServiceImpl)), service2.ProvideEncryptionService, wire.Bind(new(encryption.Internal), new(*service2.Service)), manager.ProvideSecretsService, wire.Bind(new(secrets.Service), new(*manager.SecretsService)), database.ProvideSecretsStore, wire.Bind(new(secrets.Store), new(*database.SecretsStoreImpl)), grafanads.ProvideService, wire.Bind(new(dashboardsnapshots.Store), new(*database4.DashboardSnapshotStore)), database4.ProvideStore, wire.Bind(new(dashboardsnapshots.Service), new(*service8.ServiceImpl)), service8.ProvideService, service7.ProvideService, wire.Bind(new(datasources.DataSourceService), new(*service7.Service)), service7.ProvideLegacyDataSourceLookup, retriever.ProvideService, wire.Bind(new(serviceaccounts.ServiceAccountRetriever), new(*retriever.Service)), ossaccesscontrol.ProvideServiceAccountPermissions, wire.Bind(new(accesscontrol.ServiceAccountPermissionsService), new(*ossaccesscontrol.ServiceAccountPermissionsService)), manager2.ProvideServiceAccountsService, proxy.ProvideServiceAccountsProxy, wire.Bind(new(serviceaccounts.Service), new(*proxy.ServiceAccountsProxy)), expr.ProvideService, featuremgmt.ProvideManagerService, featuremgmt.ProvideToggles, featuremgmt.ProvideOpenFeatureService, featuremgmt.ProvideStaticEvaluator, service5.ProvideDashboardServiceImpl, wire.Bind(new(dashboards2.PermissionsRegistrationService), new(*service5.DashboardServiceImpl)), service5.ProvideDashboardService, service5.ProvideDashboardProvisioningService, service5.ProvideDashboardPluginService, database2.ProvideDashboardStore, folderimpl.ProvideService, wire.Bind(new(folder.Service), new(*folderimpl.Service)), folderimpl.ProvideStore, wire.Bind(new(folder.Store), new(*folderimpl.FolderStoreImpl)), folderimpl.ProvideDashboardFolderStore, wire.Bind(new(folder.FolderStore), new(*folderimpl.DashboardFolderStoreImpl)), service9.ProvideService, wire.Bind(new(dashboardimport.Service), new(*service9.ImportDashboardService)), service6.ProvideService, wire.Bind(new(plugindashboards.Service), new(*service6.Service)), service6.ProvideDashboardUpdater, sanitizer.ProvideService, kvstore2.ProvideService, avatar.ProvideAvatarCacheServer, statscollector.ProvideService, csrf.ProvideCSRFFilter, wire.Bind(new(csrf.Service), new(*csrf.CSRF)), ossaccesscontrol.ProvideTeamPermissions, wire.Bind(new(accesscontrol.TeamPermissionsService), new(*ossaccesscontrol.TeamPermissionsService)), ossaccesscontrol.ProvideFolderPermissions, wire.Bind(new(accesscontrol.FolderPermissionsService), new(*ossaccesscontrol.FolderPermissionsService)), ossaccesscontrol.ProvideDashboardPermissions, wire.Bind(new(accesscontrol.DashboardPermissionsService), new(*ossaccesscontrol.DashboardPermissionsService)), ossaccesscontrol.ProvideReceiverPermissionsService, wire.Bind(new(accesscontrol.ReceiverPermissionsService), new(*ossaccesscontrol.ReceiverPermissionsService)), starimpl.ProvideService, playlistimpl.ProvideService, apikeyimpl.ProvideService, dashverimpl.ProvideService, service3.ProvideService, wire.Bind(new(publicdashboards.Service), new(*service3.PublicDashboardServiceImpl)), database3.ProvideStore, wire.Bind(new(publicdashboards.Store), new(*database3.PublicDashboardStoreImpl)), metric.ProvideService, api2.ProvideApi, api3.ProvideApi, userimpl.ProvideService, orgimpl.ProvideService, orgimpl.ProvideDeletionService, statsimpl.ProvideService, grpccontext.ProvideContextHandler, grpcserver.ProvideHealthService, grpcserver.ProvideReflectionService, resolver.ProvideEntityReferenceResolver, teamimpl.ProvideService, teamapi.ProvideTeamAPI, tempuserimpl.ProvideService, loginattemptimpl.ProvideService, wire.Bind(new(loginattempt.Service), new(*loginattemptimpl.Service)), migrations2.ProvideDataSourceMigrationService, migrations2.ProvideSecretMigrationProvider, wire.Bind(new(migrations2.SecretMigrationProvider), new(*migrations2.SecretMigrationProviderImpl)), resourcepermissions.NewActionSetService, wire.Bind(new(accesscontrol.ActionResolver), new(resourcepermissions.ActionSetService)), wire.Bind(new(pluginaccesscontrol.ActionSetRegistry), new(resourcepermissions.ActionSetService)), permreg.ProvidePermissionRegistry, acimpl.ProvideAccessControl, dualwrite2.ProvideZanzanaReconciler, navtreeimpl.ProvideService, wire.Bind(new(accesscontrol.AccessControl), new(*acimpl.AccessControl)), wire.Bind(new(notifications.TempUserStore), new(tempuser.Service)), tagimpl.ProvideService, wire.Bind(new(tag.Service), new(*tagimpl.Service)), authnimpl.ProvideService, authnimpl.ProvideIdentitySynchronizer, authnimpl.ProvideAuthnService, authnimpl.ProvideAuthnServiceAuthenticateOnly, authnimpl.ProvideRegistration, supportbundlesimpl.ProvideService, extsvcaccounts.ProvideExtSvcAccountsService, wire.Bind(new(serviceaccounts.ExtSvcAccountsService), new(*extsvcaccounts.ExtSvcAccountsService)), registry2.ProvideExtSvcRegistry, wire.Bind(new(extsvcauth.ExternalServiceRegistry), new(*registry2.Registry)), anonstore.ProvideAnonDBStore, wire.Bind(new(anonstore.AnonStore), new(*anonstore.AnonDBStore)), loggermw.Provide, slogadapter.Provide, signingkeysimpl.ProvideEmbeddedSigningKeysService, wire.Bind(new(signingkeys.Service), new(*signingkeysimpl.Service)), ssosettingsimpl.ProvideService, wire.Bind(new(ssosettings.Service), new(*ssosettingsimpl.Service)), idimpl.ProvideService, wire.Bind(new(auth.IDService), new(*idimpl.Service)), cloudmigrationimpl.ProvideService, userimpl.ProvideVerifier, connectors.ProvideOrgRoleMapper, wire.Bind(new(user.Verifier), new(*userimpl.Verifier)), authz.WireSet, metadata.ProvideSecureValueMetadataStorage, metadata.ProvideKeeperMetadataStorage, metadata.ProvideDecryptStorage, decrypt.ProvideDecryptAuthorizer, decrypt.ProvideDecryptAllowList, encryption2.ProvideDataKeyStorage, encryption2.ProvideEncryptedValueStorage, service11.ProvideSecureValueService, migrator2.NewWithEngine, database5.ProvideDatabase, wire.Bind(new(contracts.Database), new(*database5.Database)), manager4.ProvideEncryptionManager, encryption3.ProvideThirdPartyProviderMap, resource.ProvideStorageMetrics, resource.ProvideIndexMetrics, apiserver.WireSet, apiregistry.WireSet, appregistry.WireSet) var wireSet = wire.NewSet( wireBasicSet, metrics.WireSet, sqlstore.ProvideService, metrics2.ProvideService, wire.Bind(new(notifications.Service), new(*notifications.NotificationService)), wire.Bind(new(notifications.WebhookSender), new(*notifications.NotificationService)), wire.Bind(new(notifications.EmailSender), new(*notifications.NotificationService)), wire.Bind(new(db.DB), new(*sqlstore.SQLStore)), prefimpl.ProvideService, oauthtoken.ProvideService, wire.Bind(new(oauthtoken.OAuthTokenService), new(*oauthtoken.Service)), wire.Bind(new(cleanup.AlertRuleService), new(*store2.DBstore)), diff --git a/pkg/storage/secret/metadata/data/secure_value_create.sql b/pkg/storage/secret/metadata/data/secure_value_create.sql index ae03dd2405e..a120feaa5e5 100644 --- a/pkg/storage/secret/metadata/data/secure_value_create.sql +++ b/pkg/storage/secret/metadata/data/secure_value_create.sql @@ -8,10 +8,8 @@ INSERT INTO {{ .Ident "secret_secure_value" }} ( {{ .Ident "created_by" }}, {{ .Ident "updated" }}, {{ .Ident "updated_by" }}, - {{ .Ident "status_phase" }}, - {{ if .Row.Message.Valid }} - {{ .Ident "status_message" }}, - {{ end }} + {{ .Ident "active" }}, + {{ .Ident "version" }}, {{ .Ident "description" }}, {{ if .Row.Keeper.Valid }} {{ .Ident "keeper" }}, @@ -33,10 +31,8 @@ INSERT INTO {{ .Ident "secret_secure_value" }} ( {{ .Arg .Row.CreatedBy }}, {{ .Arg .Row.Updated }}, {{ .Arg .Row.UpdatedBy }}, - {{ .Arg .Row.Phase }}, - {{ if .Row.Message.Valid }} - {{ .Arg .Row.Message.String }}, - {{ end }} + {{ .Arg .Row.Active }}, + {{ .Arg .Row.Version }}, {{ .Arg .Row.Description }}, {{ if .Row.Keeper.Valid }} {{ .Arg .Row.Keeper.String }}, @@ -48,4 +44,4 @@ INSERT INTO {{ .Ident "secret_secure_value" }} ( {{ .Arg .Row.Ref.String }}, {{ end }} {{ .Arg .Row.ExternalID }} -); +); \ No newline at end of file diff --git a/pkg/storage/secret/metadata/data/secure_value_delete.sql b/pkg/storage/secret/metadata/data/secure_value_delete.sql deleted file mode 100644 index 2714510c291..00000000000 --- a/pkg/storage/secret/metadata/data/secure_value_delete.sql +++ /dev/null @@ -1,4 +0,0 @@ -DELETE FROM {{ .Ident "secret_secure_value" }} -WHERE {{ .Ident "namespace" }} = {{ .Arg .Namespace }} AND - {{ .Ident "name" }} = {{ .Arg .Name }} -; diff --git a/pkg/storage/secret/metadata/data/secure_value_get_latest_version.sql b/pkg/storage/secret/metadata/data/secure_value_get_latest_version.sql new file mode 100644 index 00000000000..90319d469eb --- /dev/null +++ b/pkg/storage/secret/metadata/data/secure_value_get_latest_version.sql @@ -0,0 +1,10 @@ +SELECT + {{ .Ident "version" }} +FROM + {{ .Ident "secret_secure_value" }} +WHERE + {{ .Ident "namespace" }} = {{ .Arg .Namespace }} AND + {{ .Ident "name" }} = {{ .Arg .Name }} +ORDER BY {{ .Ident "version" }} DESC +LIMIT 1 +; \ No newline at end of file diff --git a/pkg/storage/secret/metadata/data/secure_value_list.sql b/pkg/storage/secret/metadata/data/secure_value_list.sql index db19a729ebf..9c0c604b72d 100644 --- a/pkg/storage/secret/metadata/data/secure_value_list.sql +++ b/pkg/storage/secret/metadata/data/secure_value_list.sql @@ -8,15 +8,17 @@ SELECT {{ .Ident "created_by" }}, {{ .Ident "updated" }}, {{ .Ident "updated_by" }}, - {{ .Ident "status_phase" }}, - {{ .Ident "status_message" }}, {{ .Ident "description" }}, {{ .Ident "keeper" }}, {{ .Ident "decrypters" }}, {{ .Ident "ref" }}, - {{ .Ident "external_id" }} + {{ .Ident "external_id" }}, + {{ .Ident "version" }}, + {{ .Ident "active" }} FROM {{ .Ident "secret_secure_value" }} -WHERE {{ .Ident "namespace" }} = {{ .Arg .Namespace }} +WHERE + {{ .Ident "namespace" }} = {{ .Arg .Namespace }} AND + {{ .Ident "active" }} = true ORDER BY {{ .Ident "updated" }} DESC -; +; \ No newline at end of file diff --git a/pkg/storage/secret/metadata/data/secure_value_listByName.sql b/pkg/storage/secret/metadata/data/secure_value_listByName.sql index b8158d3c0ff..7a5945e4fde 100644 --- a/pkg/storage/secret/metadata/data/secure_value_listByName.sql +++ b/pkg/storage/secret/metadata/data/secure_value_listByName.sql @@ -5,7 +5,9 @@ SELECT {{ .Ident "keeper" }} FROM {{ .Ident "secret_secure_value" }} -WHERE {{ .Ident "namespace" }} = {{ .Arg .Namespace }} AND - {{ .Ident "name" }} IN ({{ .ArgList .UsedSecureValues }}) +WHERE + {{ .Ident "namespace" }} = {{ .Arg .Namespace }} AND + {{ .Ident "name" }} IN ({{ .ArgList .UsedSecureValues }}) AND + {{ .Ident "active" }} = true {{ .SelectFor "UPDATE" }} ; diff --git a/pkg/storage/secret/metadata/data/secure_value_outbox_append.sql b/pkg/storage/secret/metadata/data/secure_value_outbox_append.sql deleted file mode 100644 index e541cec3140..00000000000 --- a/pkg/storage/secret/metadata/data/secure_value_outbox_append.sql +++ /dev/null @@ -1,33 +0,0 @@ -INSERT INTO {{ .Ident "secret_secure_value_outbox" }} ( - {{ .Ident "request_id" }}, - {{ .Ident "message_type" }}, - {{ .Ident "name" }}, - {{ .Ident "namespace" }}, -{{ if .Row.EncryptedSecret.Valid }} - {{ .Ident "encrypted_secret" }}, -{{ end }} -{{ if .Row.KeeperName.Valid }} - {{ .Ident "keeper_name" }}, -{{ end }} -{{ if .Row.ExternalID.Valid }} - {{ .Ident "external_id" }}, -{{ end }} - {{ .Ident "receive_count" }}, - {{ .Ident "created" }} -) VALUES ( - {{ .Arg .Row.RequestID }}, - {{ .Arg .Row.MessageType }}, - {{ .Arg .Row.Name }}, - {{ .Arg .Row.Namespace }}, -{{ if .Row.EncryptedSecret.Valid }} - {{ .Arg .Row.EncryptedSecret.String }}, -{{ end }} -{{ if .Row.KeeperName.Valid }} - {{ .Arg .Row.KeeperName.String }}, -{{ end }} -{{ if .Row.ExternalID.Valid }} - {{ .Arg .Row.ExternalID.String }}, -{{ end }} - {{ .Arg .Row.ReceiveCount }}, - {{ .Arg .Row.Created }} -); diff --git a/pkg/storage/secret/metadata/data/secure_value_outbox_delete.sql b/pkg/storage/secret/metadata/data/secure_value_outbox_delete.sql deleted file mode 100644 index d23f3808f9c..00000000000 --- a/pkg/storage/secret/metadata/data/secure_value_outbox_delete.sql +++ /dev/null @@ -1,5 +0,0 @@ -DELETE FROM - {{ .Ident "secret_secure_value_outbox" }} -WHERE - {{ .Ident "id" }} = {{ .Arg .MessageID }} -; diff --git a/pkg/storage/secret/metadata/data/secure_value_outbox_fetch_message_ids.sql b/pkg/storage/secret/metadata/data/secure_value_outbox_fetch_message_ids.sql deleted file mode 100644 index 2c53c2223fd..00000000000 --- a/pkg/storage/secret/metadata/data/secure_value_outbox_fetch_message_ids.sql +++ /dev/null @@ -1,6 +0,0 @@ -SELECT - {{ .Ident "id" }} -FROM {{ .Ident "secret_secure_value_outbox" }} -ORDER BY id ASC -LIMIT {{ .Arg .ReceiveLimit }} -; diff --git a/pkg/storage/secret/metadata/data/secure_value_outbox_query_timestamp.sql b/pkg/storage/secret/metadata/data/secure_value_outbox_query_timestamp.sql deleted file mode 100644 index 8e525ca9009..00000000000 --- a/pkg/storage/secret/metadata/data/secure_value_outbox_query_timestamp.sql +++ /dev/null @@ -1,8 +0,0 @@ -SELECT - {{ .Ident "created" }}, - {{ .Ident "message_type" }} -FROM - {{ .Ident "secret_secure_value_outbox" }} -WHERE - {{ .Ident "id" }} = {{ .Arg .MessageID }} -; diff --git a/pkg/storage/secret/metadata/data/secure_value_outbox_receiveN.sql b/pkg/storage/secret/metadata/data/secure_value_outbox_receiveN.sql deleted file mode 100644 index 254cb3d3f3d..00000000000 --- a/pkg/storage/secret/metadata/data/secure_value_outbox_receiveN.sql +++ /dev/null @@ -1,19 +0,0 @@ -SELECT - {{ .Ident "request_id" }}, - {{ .Ident "id" }}, - {{ .Ident "message_type" }}, - {{ .Ident "name" }}, - {{ .Ident "namespace" }}, - {{ .Ident "encrypted_secret" }}, - {{ .Ident "keeper_name" }}, - {{ .Ident "external_id" }}, - {{ .Ident "receive_count" }}, - {{ .Ident "created" }} -FROM - {{ .Ident "secret_secure_value_outbox" }} -WHERE - {{ .Ident "id" }} IN ({{ .ArgList .MessageIDs }}) -ORDER BY - {{ .Ident "id" }} ASC -{{ .SelectFor "UPDATE SKIP LOCKED" }} -; diff --git a/pkg/storage/secret/metadata/data/secure_value_outbox_update_receive_count.sql b/pkg/storage/secret/metadata/data/secure_value_outbox_update_receive_count.sql deleted file mode 100644 index 610f29695a8..00000000000 --- a/pkg/storage/secret/metadata/data/secure_value_outbox_update_receive_count.sql +++ /dev/null @@ -1,7 +0,0 @@ -UPDATE - {{ .Ident "secret_secure_value_outbox" }} -SET - {{ .Ident "receive_count" }} = {{ .Ident "receive_count" }} + 1 -WHERE - {{ .Ident "id" }} IN ({{ .ArgList .MessageIDs }}) -; diff --git a/pkg/storage/secret/metadata/data/secure_value_read.sql b/pkg/storage/secret/metadata/data/secure_value_read.sql index 3453abb08e4..b90d54b4a5f 100644 --- a/pkg/storage/secret/metadata/data/secure_value_read.sql +++ b/pkg/storage/secret/metadata/data/secure_value_read.sql @@ -8,18 +8,20 @@ SELECT {{ .Ident "created_by" }}, {{ .Ident "updated" }}, {{ .Ident "updated_by" }}, - {{ .Ident "status_phase" }}, - {{ .Ident "status_message" }}, {{ .Ident "description" }}, {{ .Ident "keeper" }}, {{ .Ident "decrypters" }}, {{ .Ident "ref" }}, - {{ .Ident "external_id" }} + {{ .Ident "external_id" }}, + {{ .Ident "active" }}, + {{ .Ident "version" }} FROM {{ .Ident "secret_secure_value" }} -WHERE {{ .Ident "namespace" }} = {{ .Arg .Namespace }} AND - {{ .Ident "name" }} = {{ .Arg .Name }} +WHERE + {{ .Ident "namespace" }} = {{ .Arg .Namespace }} AND + {{ .Ident "name" }} = {{ .Arg .Name }} AND + {{ .Ident "active" }} = true {{ if .IsForUpdate }} {{ .SelectFor "UPDATE" }} {{ end }} -; +; \ No newline at end of file diff --git a/pkg/storage/secret/metadata/data/secure_value_read_for_decrypt.sql b/pkg/storage/secret/metadata/data/secure_value_read_for_decrypt.sql index 14080fa0507..975c00d9f3b 100644 --- a/pkg/storage/secret/metadata/data/secure_value_read_for_decrypt.sql +++ b/pkg/storage/secret/metadata/data/secure_value_read_for_decrypt.sql @@ -2,9 +2,12 @@ SELECT {{ .Ident "keeper" }}, {{ .Ident "decrypters" }}, {{ .Ident "ref" }}, - {{ .Ident "external_id" }} + {{ .Ident "external_id" }}, + {{ .Ident "active" }} FROM {{ .Ident "secret_secure_value" }} -WHERE {{ .Ident "namespace" }} = {{ .Arg .Namespace }} AND - {{ .Ident "name" }} = {{ .Arg .Name }} -; +WHERE + {{ .Ident "namespace" }} = {{ .Arg .Namespace }} AND + {{ .Ident "name" }} = {{ .Arg .Name }} AND + {{ .Ident "active" }} = true +; \ No newline at end of file diff --git a/pkg/storage/secret/metadata/data/secure_value_set_version_to_active.sql b/pkg/storage/secret/metadata/data/secure_value_set_version_to_active.sql new file mode 100644 index 00000000000..bf069441ac3 --- /dev/null +++ b/pkg/storage/secret/metadata/data/secure_value_set_version_to_active.sql @@ -0,0 +1,8 @@ +UPDATE + {{ .Ident "secret_secure_value" }} +SET + {{ .Ident "active" }} = ({{ .Ident "version" }} = {{ .Arg .Version}}) +WHERE + {{ .Ident "namespace" }} = {{ .Arg .Namespace }} AND + {{ .Ident "name" }} = {{ .Arg .Name }} +; \ No newline at end of file diff --git a/pkg/storage/secret/metadata/data/secure_value_set_version_to_inactive.sql b/pkg/storage/secret/metadata/data/secure_value_set_version_to_inactive.sql new file mode 100644 index 00000000000..608bb813c4f --- /dev/null +++ b/pkg/storage/secret/metadata/data/secure_value_set_version_to_inactive.sql @@ -0,0 +1,9 @@ +UPDATE + {{ .Ident "secret_secure_value" }} +SET + {{ .Ident "active" }} = false +WHERE + {{ .Ident "namespace" }} = {{ .Arg .Namespace }} AND + {{ .Ident "name" }} = {{ .Arg .Name }} AND + {{ .Ident "version" }} = {{ .Arg .Version }} +; \ No newline at end of file diff --git a/pkg/storage/secret/metadata/data/secure_value_update.sql b/pkg/storage/secret/metadata/data/secure_value_update.sql deleted file mode 100644 index 90fc4946611..00000000000 --- a/pkg/storage/secret/metadata/data/secure_value_update.sql +++ /dev/null @@ -1,30 +0,0 @@ -UPDATE - {{ .Ident "secret_secure_value" }} -SET - {{ .Ident "guid" }} = {{ .Arg .Row.GUID }}, - {{ .Ident "name" }} = {{ .Arg .Row.Name }}, - {{ .Ident "namespace" }} = {{ .Arg .Row.Namespace }}, - {{ .Ident "annotations" }} = {{ .Arg .Row.Annotations }}, - {{ .Ident "labels" }} = {{ .Arg .Row.Labels }}, - {{ .Ident "created" }} = {{ .Arg .Row.Created }}, - {{ .Ident "created_by" }} = {{ .Arg .Row.CreatedBy }}, - {{ .Ident "updated" }} = {{ .Arg .Row.Updated }}, - {{ .Ident "updated_by" }} = {{ .Arg .Row.UpdatedBy }}, - {{ .Ident "status_phase" }} = {{ .Arg .Row.Phase }}, - {{ if .Row.Message.Valid }} - {{ .Ident "status_message" }} = {{ .Arg .Row.Message.String }}, - {{ end }} - {{ .Ident "description" }} = {{ .Arg .Row.Description }}, - {{ if .Row.Keeper.Valid }} - {{ .Ident "keeper" }} = {{ .Arg .Row.Keeper.String }}, - {{ end }} - {{ if .Row.Decrypters.Valid }} - {{ .Ident "decrypters" }} = {{ .Arg .Row.Decrypters.String }}, - {{ end }} - {{ if .Row.Ref.Valid }} - {{ .Ident "ref" }} = {{ .Arg .Row.Ref.String }}, - {{ end }} - {{ .Ident "external_id" }} = {{ .Arg .Row.ExternalID }} -WHERE {{ .Ident "namespace" }} = {{ .Arg .Row.Namespace }} AND - {{ .Ident "name" }} = {{ .Arg .Row.Name }} -; diff --git a/pkg/storage/secret/metadata/data/secure_value_updateExternalId.sql b/pkg/storage/secret/metadata/data/secure_value_updateExternalId.sql index 9b2927802e6..fb891badaf5 100644 --- a/pkg/storage/secret/metadata/data/secure_value_updateExternalId.sql +++ b/pkg/storage/secret/metadata/data/secure_value_updateExternalId.sql @@ -2,6 +2,8 @@ UPDATE {{ .Ident "secret_secure_value" }} SET {{ .Ident "external_id" }} = {{ .Arg .ExternalID }} -WHERE {{ .Ident "namespace" }} = {{ .Arg .Namespace }} AND - {{ .Ident "name" }} = {{ .Arg .Name }} -; +WHERE + {{ .Ident "namespace" }} = {{ .Arg .Namespace }} AND + {{ .Ident "name" }} = {{ .Arg .Name }} AND + {{ .Ident "version" }} = {{ .Arg .Version }} +; \ No newline at end of file diff --git a/pkg/storage/secret/metadata/data/secure_value_updateStatus.sql b/pkg/storage/secret/metadata/data/secure_value_updateStatus.sql deleted file mode 100644 index dfba1960ce0..00000000000 --- a/pkg/storage/secret/metadata/data/secure_value_updateStatus.sql +++ /dev/null @@ -1,8 +0,0 @@ -UPDATE - {{ .Ident "secret_secure_value" }} -SET - {{ .Ident "status_phase" }} = {{ .Arg .Phase }}, - {{ .Ident "status_message" }} = {{ .Arg .Message }} -WHERE {{ .Ident "namespace" }} = {{ .Arg .Namespace }} AND - {{ .Ident "name" }} = {{ .Arg .Name }} -; diff --git a/pkg/storage/secret/metadata/decrypt_store_test.go b/pkg/storage/secret/metadata/decrypt_store_test.go index 69a178c01cf..5ebbb2f9466 100644 --- a/pkg/storage/secret/metadata/decrypt_store_test.go +++ b/pkg/storage/secret/metadata/decrypt_store_test.go @@ -1,4 +1,4 @@ -package metadata +package metadata_test import ( "context" @@ -7,23 +7,11 @@ import ( "github.com/grafana/authlib/authn" "github.com/grafana/authlib/types" "github.com/stretchr/testify/require" - "go.opentelemetry.io/otel/trace/noop" "github.com/grafana/grafana/pkg/apimachinery/identity" secretv0alpha1 "github.com/grafana/grafana/pkg/apis/secret/v0alpha1" - "github.com/grafana/grafana/pkg/infra/usagestats" "github.com/grafana/grafana/pkg/registry/apis/secret/contracts" - "github.com/grafana/grafana/pkg/registry/apis/secret/decrypt" - "github.com/grafana/grafana/pkg/registry/apis/secret/encryption" - encryptionmanager "github.com/grafana/grafana/pkg/registry/apis/secret/encryption/manager" - "github.com/grafana/grafana/pkg/registry/apis/secret/secretkeeper" - "github.com/grafana/grafana/pkg/registry/apis/secret/xkube" - "github.com/grafana/grafana/pkg/services/featuremgmt" - "github.com/grafana/grafana/pkg/services/sqlstore" - "github.com/grafana/grafana/pkg/setting" - "github.com/grafana/grafana/pkg/storage/secret/database" - encryptionstorage "github.com/grafana/grafana/pkg/storage/secret/encryption" - "github.com/grafana/grafana/pkg/storage/secret/migrator" + "github.com/grafana/grafana/pkg/registry/apis/secret/testutils" ) func TestIntegrationDecrypt(t *testing.T) { @@ -39,9 +27,9 @@ func TestIntegrationDecrypt(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) t.Cleanup(cancel) - decryptSvc, _, _, _ := setupDecryptTestService(t, nil) + sut := testutils.Setup(t) - exposed, err := decryptSvc.Decrypt(ctx, "default", "name") + exposed, err := sut.DecryptStorage.Decrypt(ctx, "default", "name") require.Error(t, err) require.Empty(t, exposed) }) @@ -55,9 +43,11 @@ func TestIntegrationDecrypt(t *testing.T) { // Create auth context with proper permissions authCtx := createAuthContext(ctx, "default", []string{"secret.grafana.app/securevalues/group1:decrypt"}, "svc", types.TypeUser) - decryptSvc, _, _, _ := setupDecryptTestService(t, map[string]struct{}{"group1": {}}) + sut := testutils.Setup(t, testutils.WithMutateCfg(func(sc *testutils.SetupConfig) { + sc.AllowList = map[string]struct{}{"group1": {}} + })) - exposed, err := decryptSvc.Decrypt(authCtx, "default", "non-existent-value") + exposed, err := sut.DecryptStorage.Decrypt(authCtx, "default", "non-existent-value") require.ErrorIs(t, err, contracts.ErrDecryptNotFound) require.Empty(t, exposed) }) @@ -78,7 +68,9 @@ func TestIntegrationDecrypt(t *testing.T) { allowList := map[string]struct{}{"allowed-group": {}} // Setup service - decryptSvc, secureValueMetadataStorage, keeperService, keeperMetadataService := setupDecryptTestService(t, allowList) + sut := testutils.Setup(t, testutils.WithMutateCfg(func(sc *testutils.SetupConfig) { + sc.AllowList = allowList + })) // Create a secure value that is not in the allowlist spec := secretv0alpha1.SecureValueSpec{ @@ -90,9 +82,10 @@ func TestIntegrationDecrypt(t *testing.T) { sv.Name = svName sv.Namespace = "default" - newTestSecureValue(authCtx, t, secureValueMetadataStorage, keeperService, keeperMetadataService, sv, "actor-uid") + _, err := sut.CreateSv(authCtx, testutils.CreateSvWithSv(sv)) + require.NoError(t, err) - exposed, err := decryptSvc.Decrypt(authCtx, "default", svName) + exposed, err := sut.DecryptStorage.Decrypt(authCtx, "default", svName) require.ErrorIs(t, err, contracts.ErrDecryptNotAuthorized) require.Empty(t, exposed) }) @@ -112,7 +105,9 @@ func TestIntegrationDecrypt(t *testing.T) { allowList := map[string]struct{}{svcIdentity: {}} // Setup service - decryptSvc, secureValueMetadataStorage, keeperService, keeperMetadataService := setupDecryptTestService(t, allowList) + sut := testutils.Setup(t, testutils.WithMutateCfg(func(sc *testutils.SetupConfig) { + sc.AllowList = allowList + })) // Create a secure value that is in the allowlist spec := secretv0alpha1.SecureValueSpec{ @@ -124,9 +119,10 @@ func TestIntegrationDecrypt(t *testing.T) { sv.Name = "sv-test" sv.Namespace = "default" - newTestSecureValue(authCtx, t, secureValueMetadataStorage, keeperService, keeperMetadataService, sv, "actor-uid") + _, err := sut.CreateSv(authCtx, testutils.CreateSvWithSv(sv)) + require.NoError(t, err) - exposed, err := decryptSvc.Decrypt(authCtx, "default", "sv-test") + exposed, err := sut.DecryptStorage.Decrypt(authCtx, "default", "sv-test") require.NoError(t, err) require.NotEmpty(t, exposed) require.Equal(t, "value", exposed.DangerouslyExposeAndConsumeValue()) @@ -148,7 +144,9 @@ func TestIntegrationDecrypt(t *testing.T) { allowList := map[string]struct{}{svcIdentity: {}} // Setup service - decryptSvc, secureValueMetadataStorage, keeperService, keeperMetadataService := setupDecryptTestService(t, allowList) + sut := testutils.Setup(t, testutils.WithMutateCfg(func(sc *testutils.SetupConfig) { + sc.AllowList = allowList + })) // Create a secure value that is in the allowlist spec := secretv0alpha1.SecureValueSpec{ @@ -160,9 +158,10 @@ func TestIntegrationDecrypt(t *testing.T) { sv.Name = svName sv.Namespace = "default" - newTestSecureValue(authCtx, t, secureValueMetadataStorage, keeperService, keeperMetadataService, sv, "actor-uid") + _, err := sut.CreateSv(authCtx, testutils.CreateSvWithSv(sv)) + require.NoError(t, err) - exposed, err := decryptSvc.Decrypt(authCtx, "default", svName) + exposed, err := sut.DecryptStorage.Decrypt(authCtx, "default", svName) require.ErrorIs(t, err, contracts.ErrDecryptNotAuthorized) require.Empty(t, exposed) }) @@ -179,7 +178,7 @@ func TestIntegrationDecrypt(t *testing.T) { authCtx := createAuthContext(ctx, "default", []string{"secret.grafana.app/securevalues"}, svcIdentity, types.TypeUser) // Setup service - decryptSvc, secureValueMetadataStorage, keeperService, keeperMetadataService := setupDecryptTestService(t, map[string]struct{}{svcIdentity: {}}) + sut := testutils.Setup(t) // Create a secure value spec := secretv0alpha1.SecureValueSpec{ @@ -191,9 +190,10 @@ func TestIntegrationDecrypt(t *testing.T) { sv.Name = "sv-test" sv.Namespace = "default" - newTestSecureValue(authCtx, t, secureValueMetadataStorage, keeperService, keeperMetadataService, sv, "actor-uid") + _, err := sut.CreateSv(authCtx, testutils.CreateSvWithSv(sv)) + require.NoError(t, err) - exposed, err := decryptSvc.Decrypt(authCtx, "default", "sv-test") + exposed, err := sut.DecryptStorage.Decrypt(authCtx, "default", "sv-test") require.ErrorIs(t, err, contracts.ErrDecryptNotAuthorized) require.Empty(t, exposed) }) @@ -211,7 +211,7 @@ func TestIntegrationDecrypt(t *testing.T) { authCtx := createAuthContext(ctx, "default", []string{"secret.grafana.app/securevalues/" + svName + ":read"}, svcIdentity, types.TypeUser) // Setup service - decryptSvc, secureValueMetadataStorage, keeperService, keeperMetadataService := setupDecryptTestService(t, map[string]struct{}{svcIdentity: {}}) + sut := testutils.Setup(t) // Create a secure value spec := secretv0alpha1.SecureValueSpec{ @@ -223,9 +223,10 @@ func TestIntegrationDecrypt(t *testing.T) { sv.Name = svName sv.Namespace = "default" - newTestSecureValue(authCtx, t, secureValueMetadataStorage, keeperService, keeperMetadataService, sv, "actor-uid") + _, err := sut.CreateSv(authCtx, testutils.CreateSvWithSv(sv)) + require.NoError(t, err) - exposed, err := decryptSvc.Decrypt(authCtx, "default", svName) + exposed, err := sut.DecryptStorage.Decrypt(authCtx, "default", svName) require.ErrorIs(t, err, contracts.ErrDecryptNotAuthorized) require.Empty(t, exposed) }) @@ -242,7 +243,7 @@ func TestIntegrationDecrypt(t *testing.T) { authCtx := createAuthContext(ctx, "default", []string{"secret.grafana.app/securevalues/:decrypt"}, svcIdentity, types.TypeUser) // Setup service - decryptSvc, secureValueMetadataStorage, keeperService, keeperMetadataService := setupDecryptTestService(t, map[string]struct{}{svcIdentity: {}}) + sut := testutils.Setup(t) // Create a secure value spec := secretv0alpha1.SecureValueSpec{ @@ -254,9 +255,10 @@ func TestIntegrationDecrypt(t *testing.T) { sv.Name = "sv-test" sv.Namespace = "default" - newTestSecureValue(authCtx, t, secureValueMetadataStorage, keeperService, keeperMetadataService, sv, "actor-uid") + _, err := sut.CreateSv(authCtx, testutils.CreateSvWithSv(sv)) + require.NoError(t, err) - exposed, err := decryptSvc.Decrypt(authCtx, "default", "sv-test") + exposed, err := sut.DecryptStorage.Decrypt(authCtx, "default", "sv-test") require.ErrorIs(t, err, contracts.ErrDecryptNotAuthorized) require.Empty(t, exposed) }) @@ -274,7 +276,7 @@ func TestIntegrationDecrypt(t *testing.T) { authCtx := createAuthContext(ctx, "default", []string{"wrong.group/securevalues/" + svName + ":decrypt"}, svcIdentity, types.TypeUser) // Setup service - decryptSvc, secureValueMetadataStorage, keeperService, keeperMetadataService := setupDecryptTestService(t, map[string]struct{}{svcIdentity: {}}) + sut := testutils.Setup(t) // Create a secure value spec := secretv0alpha1.SecureValueSpec{ @@ -286,9 +288,10 @@ func TestIntegrationDecrypt(t *testing.T) { sv.Name = svName sv.Namespace = "default" - newTestSecureValue(authCtx, t, secureValueMetadataStorage, keeperService, keeperMetadataService, sv, "actor-uid") + _, err := sut.CreateSv(authCtx, testutils.CreateSvWithSv(sv)) + require.NoError(t, err) - exposed, err := decryptSvc.Decrypt(authCtx, "default", svName) + exposed, err := sut.DecryptStorage.Decrypt(authCtx, "default", svName) require.Error(t, err) require.Equal(t, err.Error(), "not authorized") require.Empty(t, exposed) @@ -297,62 +300,6 @@ func TestIntegrationDecrypt(t *testing.T) { // TODO: add more tests for keeper failure scenarios, lets see how the async work will change this though. } -func setupDecryptTestService(t *testing.T, allowList map[string]struct{}) (*decryptStorage, contracts.SecureValueMetadataStorage, *secretkeeper.OSSKeeperService, contracts.KeeperMetadataStorage) { - t.Helper() - - // Initialize infra dependencies - cfg := &setting.Cfg{ - SecretsManagement: setting.SecretsManagerSettings{ - SecretKey: "sdDkslslld", - EncryptionProvider: "secretKey.v1", - }, - } - - features := featuremgmt.WithFeatures( - featuremgmt.FlagGrafanaAPIServerWithExperimentalAPIs, - featuremgmt.FlagSecretsManagementAppPlatform, - ) - - db := sqlstore.NewTestStore(t, sqlstore.WithMigrator(migrator.New())) - tracer := noop.NewTracerProvider().Tracer("test") - database := database.ProvideDatabase(db, tracer) - - // Initialize encryption manager and storage - dataKeyStore, err := encryptionstorage.ProvideDataKeyStorage(database, tracer, features, nil) - require.NoError(t, err) - - encValueStore, err := encryptionstorage.ProvideEncryptedValueStorage(database, tracer, features) - require.NoError(t, err) - - encryptionManager, err := encryptionmanager.ProvideEncryptionManager( - tracer, - dataKeyStore, - cfg, - &usagestats.UsageStatsMock{}, - encryption.ProviderMap{}, - ) - require.NoError(t, err) - - // Initialize the keeper service - keeperService, err := secretkeeper.ProvideService(tracer, encValueStore, encryptionManager, nil) - require.NoError(t, err) - - keeperMetadataStorage, err := ProvideKeeperMetadataStorage(database, tracer, features, nil) - require.NoError(t, err) - - // Initialize the secure value storage - secureValueMetadataStorage, err := ProvideSecureValueMetadataStorage(database, tracer, features, nil) - require.NoError(t, err) - - decryptAuthorizer := decrypt.ProvideDecryptAuthorizer(tracer, allowList) - - // Initialize the decrypt storage - decryptSvc, err := ProvideDecryptStorage(features, tracer, keeperService, keeperMetadataStorage, secureValueMetadataStorage, decryptAuthorizer, nil) - require.NoError(t, err) - - return decryptSvc.(*decryptStorage), secureValueMetadataStorage, keeperService, keeperMetadataStorage -} - func createAuthContext(ctx context.Context, namespace string, permissions []string, svc string, identityType types.IdentityType) context.Context { requester := &identity.StaticRequester{ Type: identityType, @@ -371,32 +318,3 @@ func createAuthContext(ctx context.Context, namespace string, permissions []stri return types.WithAuthInfo(ctx, requester) } - -// This helper will also delete the secureValue from the db when the test is done. -func newTestSecureValue(ctx context.Context, t *testing.T, db contracts.SecureValueMetadataStorage, keeperService *secretkeeper.OSSKeeperService, keeperMetadataStorage contracts.KeeperMetadataStorage, sv *secretv0alpha1.SecureValue, actorUID string) { - t.Helper() - - _, err := db.Create(ctx, sv, actorUID) - require.NoError(t, err) - - require.NoError(t, err) - - // Since creating secrets is async, store the secret in the keeper synchronously to make testing easier - cfg, err := keeperMetadataStorage.GetKeeperConfig(ctx, sv.Namespace, sv.Spec.Keeper, contracts.ReadOpts{}) - require.NoError(t, err) - - keeper, err := keeperService.KeeperForConfig(cfg) - require.NoError(t, err) - - externalID, err := keeper.Store(ctx, cfg, sv.Namespace, sv.Spec.Value.DangerouslyExposeAndConsumeValue()) - require.NoError(t, err) - - // Set external id for the secure value - err = db.SetExternalID(ctx, xkube.Namespace(sv.Namespace), sv.Name, externalID) - require.NoError(t, err) - - t.Cleanup(func() { - require.NoError(t, keeper.Delete(ctx, cfg, sv.Namespace, externalID)) - require.NoError(t, db.Delete(ctx, xkube.Namespace(sv.Namespace), sv.Name)) - }) -} diff --git a/pkg/storage/secret/metadata/keeper_store_test.go b/pkg/storage/secret/metadata/keeper_store_test.go index 644b3ccf714..c5da14eaf2d 100644 --- a/pkg/storage/secret/metadata/keeper_store_test.go +++ b/pkg/storage/secret/metadata/keeper_store_test.go @@ -1,4 +1,4 @@ -package metadata +package metadata_test import ( "context" @@ -10,6 +10,7 @@ import ( "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/storage/secret/database" + "github.com/grafana/grafana/pkg/storage/secret/metadata" "github.com/grafana/grafana/pkg/storage/secret/migrator" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/trace/noop" @@ -340,7 +341,7 @@ func initStorage(t *testing.T) contracts.KeeperMetadataStorage { features := featuremgmt.WithFeatures(featuremgmt.FlagGrafanaAPIServerWithExperimentalAPIs, featuremgmt.FlagSecretsManagementAppPlatform) // Initialize the keeper storage - keeperMetadataStorage, err := ProvideKeeperMetadataStorage(db, tracer, features, nil) + keeperMetadataStorage, err := metadata.ProvideKeeperMetadataStorage(db, tracer, features, nil) require.NoError(t, err) return keeperMetadataStorage } diff --git a/pkg/storage/secret/metadata/metrics/metrics.go b/pkg/storage/secret/metadata/metrics/metrics.go index bffbaebc604..bedaa03b4f8 100644 --- a/pkg/storage/secret/metadata/metrics/metrics.go +++ b/pkg/storage/secret/metadata/metrics/metrics.go @@ -13,16 +13,6 @@ const ( // StorageMetrics is a struct that contains all the metrics for all operations of secrets storage. type StorageMetrics struct { - OutboxAppendDuration *prometheus.HistogramVec - OutboxReceiveDuration prometheus.Histogram - OutboxAppendCount *prometheus.CounterVec - OutboxReceiveCount prometheus.Counter - OutboxDeleteDuration prometheus.Histogram - OutboxDeleteCount prometheus.Counter - OutboxIncrementReceiveCountDuration prometheus.Histogram - OutboxIncrementReceiveCountCount prometheus.Counter - OutboxTotalMessageLifetimeDuration *prometheus.HistogramVec - KeeperMetadataCreateDuration *prometheus.HistogramVec KeeperMetadataCreateCount *prometheus.CounterVec KeeperMetadataUpdateDuration *prometheus.HistogramVec @@ -55,67 +45,6 @@ type StorageMetrics struct { func newStorageMetrics() *StorageMetrics { return &StorageMetrics{ - // Outbox metrics - OutboxAppendDuration: prometheus.NewHistogramVec(prometheus.HistogramOpts{ - Namespace: namespace, - Subsystem: subsystem, - Name: "outbox_append_duration_seconds", - Help: "Duration of outbox message append operations", - Buckets: prometheus.DefBuckets, - }, []string{"message_type"}), - OutboxAppendCount: prometheus.NewCounterVec(prometheus.CounterOpts{ - Namespace: namespace, - Subsystem: subsystem, - Name: "outbox_append_count", - Help: "Count of outbox message append operations", - }, []string{"message_type"}), - OutboxReceiveDuration: prometheus.NewHistogram(prometheus.HistogramOpts{ - Namespace: namespace, - Subsystem: subsystem, - Name: "outbox_receive_duration_seconds", - Help: "Duration of outbox message receive operations", - Buckets: prometheus.DefBuckets, - }), - OutboxReceiveCount: prometheus.NewCounter(prometheus.CounterOpts{ - Namespace: namespace, - Subsystem: subsystem, - Name: "outbox_receive_count", - Help: "Count of outbox message receive operations", - }), - OutboxDeleteDuration: prometheus.NewHistogram(prometheus.HistogramOpts{ - Namespace: namespace, - Subsystem: subsystem, - Name: "outbox_delete_duration_seconds", - Help: "Duration of outbox message delete operations", - Buckets: prometheus.DefBuckets, - }), - OutboxDeleteCount: prometheus.NewCounter(prometheus.CounterOpts{ - Namespace: namespace, - Subsystem: subsystem, - Name: "outbox_delete_count", - Help: "Count of outbox message delete operations", - }), - OutboxIncrementReceiveCountDuration: prometheus.NewHistogram(prometheus.HistogramOpts{ - Namespace: namespace, - Subsystem: subsystem, - Name: "outbox_increment_receive_count_duration_seconds", - Help: "Duration of outbox message increment receive count operations", - Buckets: prometheus.DefBuckets, - }), - OutboxIncrementReceiveCountCount: prometheus.NewCounter(prometheus.CounterOpts{ - Namespace: namespace, - Subsystem: subsystem, - Name: "outbox_increment_receive_count_count", - Help: "Count of outbox message increment receive count operations", - }), - OutboxTotalMessageLifetimeDuration: prometheus.NewHistogramVec(prometheus.HistogramOpts{ - Namespace: namespace, - Subsystem: subsystem, - Name: "outbox_total_message_lifetime_duration_seconds", - Help: "Total duration of outbox message lifetime", - Buckets: prometheus.DefBuckets, - }, []string{"message_type"}), - // Keeper metrics KeeperMetadataCreateDuration: prometheus.NewHistogramVec(prometheus.HistogramOpts{ Namespace: namespace, @@ -307,15 +236,6 @@ func NewStorageMetrics(reg prometheus.Registerer) *StorageMetrics { if reg != nil { reg.MustRegister( - m.OutboxAppendDuration, - m.OutboxAppendCount, - m.OutboxReceiveDuration, - m.OutboxReceiveCount, - m.OutboxDeleteDuration, - m.OutboxDeleteCount, - m.OutboxIncrementReceiveCountDuration, - m.OutboxIncrementReceiveCountCount, - m.OutboxTotalMessageLifetimeDuration, m.KeeperMetadataCreateDuration, m.KeeperMetadataCreateCount, m.KeeperMetadataUpdateDuration, diff --git a/pkg/storage/secret/metadata/outbox_store.go b/pkg/storage/secret/metadata/outbox_store.go deleted file mode 100644 index efe569384f4..00000000000 --- a/pkg/storage/secret/metadata/outbox_store.go +++ /dev/null @@ -1,397 +0,0 @@ -package metadata - -import ( - "context" - "database/sql" - "fmt" - "time" - - "github.com/grafana/grafana/pkg/storage/secret/metadata/metrics" - unifiedsql "github.com/grafana/grafana/pkg/storage/unified/sql" - "github.com/prometheus/client_golang/prometheus" - "go.opentelemetry.io/otel/attribute" - "go.opentelemetry.io/otel/codes" - "go.opentelemetry.io/otel/trace" - - "github.com/grafana/grafana/pkg/registry/apis/secret/assert" - "github.com/grafana/grafana/pkg/registry/apis/secret/contracts" - "github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate" -) - -type outboxStore struct { - db contracts.Database - dialect sqltemplate.Dialect - tracer trace.Tracer - metrics *metrics.StorageMetrics -} - -func ProvideOutboxQueue( - db contracts.Database, - tracer trace.Tracer, - reg prometheus.Registerer, -) contracts.OutboxQueue { - return &outboxStore{ - db: db, - dialect: sqltemplate.DialectForDriver(db.DriverName()), - metrics: metrics.NewStorageMetrics(reg), - tracer: tracer, - } -} - -type outboxMessageDB struct { - RequestID string - MessageID int64 - MessageType contracts.OutboxMessageType - Name string - Namespace string - EncryptedSecret sql.NullString - KeeperName sql.NullString - ExternalID sql.NullString - ReceiveCount int - Created int64 -} - -func (s *outboxStore) Append(ctx context.Context, input contracts.AppendOutboxMessage) (messageID int64, err error) { - ctx, span := s.tracer.Start(ctx, "outboxStore.Append", trace.WithAttributes( - attribute.String("name", input.Name), - attribute.String("namespace", input.Namespace), - attribute.String("type", string(input.Type)), - attribute.String("requestID", input.RequestID), - )) - defer span.End() - - defer func() { - if err != nil { - span.SetStatus(codes.Error, "failed to append outbox message") - span.RecordError(err) - } - - if messageID != 0 { - span.SetAttributes(attribute.Int64("messageID", messageID)) - } - }() - - assert.True(input.Type != "", "outboxStore.Append: outbox message type is required") - - start := time.Now() - messageID, err = s.insertMessage(ctx, input) - if err != nil { - return messageID, fmt.Errorf("inserting message into outbox table: %+w", err) - } - - s.metrics.OutboxAppendDuration.WithLabelValues(string(input.Type)).Observe(time.Since(start).Seconds()) - s.metrics.OutboxAppendCount.WithLabelValues(string(input.Type)).Inc() - - return messageID, nil -} - -func (s *outboxStore) insertMessage(ctx context.Context, input contracts.AppendOutboxMessage) (int64, error) { - keeperName := sql.NullString{} - if input.KeeperName != nil { - keeperName = sql.NullString{ - Valid: true, - String: *input.KeeperName, - } - } - - externalID := sql.NullString{} - if input.ExternalID != nil { - externalID = sql.NullString{ - Valid: true, - String: *input.ExternalID, - } - } - - encryptedSecret := sql.NullString{} - if input.Type == contracts.CreateSecretOutboxMessage || input.Type == contracts.UpdateSecretOutboxMessage { - encryptedSecret = sql.NullString{ - Valid: true, - String: input.EncryptedSecret, - } - } - - req := appendSecureValueOutbox{ - SQLTemplate: sqltemplate.New(s.dialect), - Row: &outboxMessageDB{ - RequestID: input.RequestID, - MessageType: input.Type, - Name: input.Name, - Namespace: input.Namespace, - EncryptedSecret: encryptedSecret, - KeeperName: keeperName, - ExternalID: externalID, - ReceiveCount: 0, - Created: time.Now().UTC().UnixMilli(), - }, - } - - query, err := sqltemplate.Execute(sqlSecureValueOutboxAppend, req) - if err != nil { - return 0, fmt.Errorf("execute template %q: %w", sqlSecureValueOutboxAppend.Name(), err) - } - - result, err := s.db.ExecContext(ctx, query, req.GetArgs()...) - if err != nil { - if unifiedsql.IsRowAlreadyExistsError(err) { - return 0, contracts.ErrSecureValueOperationInProgress - } - return 0, fmt.Errorf("inserting message into secure value outbox table: %w", err) - } - - rowsAffected, err := result.RowsAffected() - if err != nil { - return 0, fmt.Errorf("get rows affected: %w", err) - } - - if rowsAffected != 1 { - return 0, fmt.Errorf("expected to affect 1 row, but affected %d", rowsAffected) - } - - id, err := result.LastInsertId() - if err != nil { - return id, fmt.Errorf("fetching last inserted id: %w", err) - } - - return id, nil -} - -func (s *outboxStore) ReceiveN(ctx context.Context, limit uint) ([]contracts.OutboxMessage, error) { - messageIDs, err := s.fetchMessageIdsInQueue(ctx, limit) - if err != nil { - return nil, fmt.Errorf("fetching message ids from queue: %w", err) - } - // If queue is empty - if len(messageIDs) == 0 { - return nil, nil - } - req := receiveNSecureValueOutbox{ - SQLTemplate: sqltemplate.New(s.dialect), - MessageIDs: messageIDs, - } - - start := time.Now() - query, err := sqltemplate.Execute(sqlSecureValueOutboxReceiveN, req) - if err != nil { - return nil, fmt.Errorf("execute template %q: %w", sqlSecureValueOutboxReceiveN.Name(), err) - } - - rows, err := s.db.QueryContext(ctx, query, req.GetArgs()...) - if err != nil { - return nil, fmt.Errorf("fetching rows from secure value outbox table: %w", err) - } - defer func() { _ = rows.Close() }() - - messages := make([]contracts.OutboxMessage, 0) - - for rows.Next() { - var row outboxMessageDB - if err := rows.Scan( - &row.RequestID, - &row.MessageID, - &row.MessageType, - &row.Name, - &row.Namespace, - &row.EncryptedSecret, - &row.KeeperName, - &row.ExternalID, - &row.ReceiveCount, - &row.Created, - ); err != nil { - return nil, fmt.Errorf("scanning row from secure value outbox table: %w", err) - } - - var keeperName *string - if row.KeeperName.Valid { - keeperName = &row.KeeperName.String - } - - var externalID *string - if row.ExternalID.Valid { - externalID = &row.ExternalID.String - } - - msg := contracts.OutboxMessage{ - RequestID: row.RequestID, - Type: row.MessageType, - MessageID: row.MessageID, - Name: row.Name, - Namespace: row.Namespace, - KeeperName: keeperName, - ExternalID: externalID, - ReceiveCount: row.ReceiveCount, - Created: row.Created, - } - - if row.MessageType != contracts.DeleteSecretOutboxMessage && row.EncryptedSecret.Valid { - msg.EncryptedSecret = row.EncryptedSecret.String - } - - messages = append(messages, msg) - } - - if err := rows.Err(); err != nil { - return messages, fmt.Errorf("reading rows: %w", err) - } - - s.metrics.OutboxReceiveDuration.Observe(time.Since(start).Seconds()) - s.metrics.OutboxReceiveCount.Add(float64(len(messages))) - - return messages, nil -} - -func (s *outboxStore) fetchMessageIdsInQueue(ctx context.Context, limit uint) ([]int64, error) { - req := fetchMessageIDsOutbox{ - SQLTemplate: sqltemplate.New(s.dialect), - ReceiveLimit: limit, - } - - query, err := sqltemplate.Execute(sqlSecureValueOutboxFetchMessageIDs, req) - if err != nil { - return nil, fmt.Errorf("execute template %q: %w", sqlSecureValueOutboxFetchMessageIDs.Name(), err) - } - - rows, err := s.db.QueryContext(ctx, query, req.GetArgs()...) - if err != nil { - return nil, fmt.Errorf("fetching rows from secure value outbox table: %w", err) - } - defer func() { _ = rows.Close() }() - - messageIDs := make([]int64, 0, limit) - - for rows.Next() { - var id int64 - if err := rows.Scan(&id); err != nil { - return nil, fmt.Errorf("scanning row; %w", err) - } - messageIDs = append(messageIDs, id) - } - - if err := rows.Err(); err != nil { - return nil, fmt.Errorf("reading rows: %w", err) - } - - return messageIDs, nil -} - -func (s *outboxStore) Delete(ctx context.Context, messageID int64) (err error) { - ctx, span := s.tracer.Start(ctx, "outboxStore.Append", trace.WithAttributes( - attribute.Int64("messageID", messageID), - )) - defer span.End() - - defer func() { - if err != nil { - span.SetStatus(codes.Error, "failed to delete message from outbox") - span.RecordError(err) - } - }() - - assert.True(messageID != 0, "outboxStore.Delete: messageID is required") - - start := time.Now() - if err := s.deleteMessage(ctx, messageID); err != nil { - return fmt.Errorf("deleting message from outbox table %+w", err) - } - - s.metrics.OutboxDeleteDuration.Observe(time.Since(start).Seconds()) - s.metrics.OutboxDeleteCount.Inc() - - return nil -} - -func (s *outboxStore) deleteMessage(ctx context.Context, messageID int64) error { - tsReq := getOutboxMessageTimestamp{ - SQLTemplate: sqltemplate.New(s.dialect), - MessageID: messageID, - } - - // First query the object so we can get the timestamp and calculate the total lifetime - timestampQuery, err := sqltemplate.Execute(sqlSecureValueOutboxQueryTimestamp, tsReq) - if err != nil { - return fmt.Errorf("execute template %q: %w", sqlSecureValueOutboxQueryTimestamp.Name(), err) - } - - rows, err := s.db.QueryContext(ctx, timestampQuery, tsReq.GetArgs()...) - if err != nil { - return fmt.Errorf("querying timestamp from secure value outbox table: %w", err) - } - - if !rows.Next() { - _ = rows.Close() - return fmt.Errorf("no row found for message id=%v", messageID) - } - - var timestamp int64 - var messageType string - if err := rows.Scan(×tamp, &messageType); err != nil { - _ = rows.Close() - return fmt.Errorf("scanning timestamp: %w", err) - } - - // Explicitly close rows and check for errors before proceeding - if err := rows.Close(); err != nil { - return fmt.Errorf("closing rows: %w", err) - } - - if err := rows.Err(); err != nil { - return fmt.Errorf("rows error: %w", err) - } - - totalLifetime := time.Since(time.UnixMilli(timestamp)) - s.metrics.OutboxTotalMessageLifetimeDuration.WithLabelValues(messageType).Observe(totalLifetime.Seconds()) - - // Then delete the object - delReq := deleteSecureValueOutbox{ - SQLTemplate: sqltemplate.New(s.dialect), - MessageID: messageID, - } - - query, err := sqltemplate.Execute(sqlSecureValueOutboxDelete, delReq) - if err != nil { - return fmt.Errorf("execute template %q: %w", sqlSecureValueOutboxDelete.Name(), err) - } - - result, err := s.db.ExecContext(ctx, query, delReq.GetArgs()...) - if err != nil { - return fmt.Errorf("deleting message id=%v from secure value outbox table: %w", messageID, err) - } - - rowsAffected, err := result.RowsAffected() - if err != nil { - return fmt.Errorf("get rows affected: %w", err) - } - - // TODO: Presumably it's a bug if we delete 0 rows? - if rowsAffected > 1 { - return fmt.Errorf("bug: deleted more than one row from the outbox table, should delete only one at a time: deleted=%v", rowsAffected) - } - - return nil -} - -func (s *outboxStore) IncrementReceiveCount(ctx context.Context, messageIDs []int64) error { - if len(messageIDs) == 0 { - return nil - } - - req := incrementReceiveCountOutbox{ - SQLTemplate: sqltemplate.New(s.dialect), - MessageIDs: messageIDs, - } - - start := time.Now() - query, err := sqltemplate.Execute(sqlSecureValueOutboxUpdateReceiveCount, req) - if err != nil { - return fmt.Errorf("execute template %q: %w", sqlSecureValueOutboxUpdateReceiveCount.Name(), err) - } - - _, err = s.db.ExecContext(ctx, query, req.GetArgs()...) - if err != nil { - return fmt.Errorf("updating outbox messages receive count: %w", err) - } - - s.metrics.OutboxIncrementReceiveCountDuration.Observe(time.Since(start).Seconds()) - s.metrics.OutboxIncrementReceiveCountCount.Add(float64(len(messageIDs))) - - return nil -} diff --git a/pkg/storage/secret/metadata/outbox_store_test.go b/pkg/storage/secret/metadata/outbox_store_test.go deleted file mode 100644 index f757e8b6b38..00000000000 --- a/pkg/storage/secret/metadata/outbox_store_test.go +++ /dev/null @@ -1,269 +0,0 @@ -package metadata - -import ( - "context" - "fmt" - "math/rand" - "slices" - "testing" - "time" - - "github.com/grafana/grafana/pkg/registry/apis/secret/contracts" - "github.com/grafana/grafana/pkg/services/sqlstore" - "github.com/grafana/grafana/pkg/storage/secret/database" - "github.com/grafana/grafana/pkg/storage/secret/migrator" - "github.com/stretchr/testify/require" - "go.opentelemetry.io/otel/trace/noop" -) - -type outboxStoreModel struct { - rows []contracts.OutboxMessage -} - -func newOutboxStoreModel() *outboxStoreModel { - return &outboxStoreModel{} -} - -func (model *outboxStoreModel) Append(messageID int64, message contracts.AppendOutboxMessage) { - model.rows = append(model.rows, contracts.OutboxMessage{ - Type: message.Type, - MessageID: messageID, - Name: message.Name, - Namespace: message.Namespace, - EncryptedSecret: message.EncryptedSecret, - KeeperName: message.KeeperName, - ExternalID: message.ExternalID, - }) -} - -func (model *outboxStoreModel) ReceiveN(n uint) []contracts.OutboxMessage { - maxMessages := min(len(model.rows), int(n)) - if maxMessages == 0 { - return nil - } - return model.rows[:maxMessages] -} - -func (model *outboxStoreModel) Delete(messageID int64) { - oldLen := len(model.rows) - model.rows = slices.DeleteFunc(model.rows, func(m contracts.OutboxMessage) bool { - return m.MessageID == messageID - }) - if len(model.rows) != oldLen-1 { - panic("Delete: deleted more than one message") - } -} - -func TestOutboxStoreModel(t *testing.T) { - t.Parallel() - - model := newOutboxStoreModel() - - require.Empty(t, model.ReceiveN(10)) - - appendOutboxMessage := contracts.AppendOutboxMessage{ - Type: contracts.CreateSecretOutboxMessage, - Name: "s-1", - Namespace: "n-1", - EncryptedSecret: "value", - ExternalID: nil, - } - - outboxMessage1 := contracts.OutboxMessage{ - MessageID: 1, - Type: contracts.CreateSecretOutboxMessage, - Name: "s-1", - Namespace: "n-1", - EncryptedSecret: "value", - ExternalID: nil, - } - - outboxMessage2 := contracts.OutboxMessage{ - MessageID: 2, - Type: contracts.CreateSecretOutboxMessage, - Name: "s-1", - Namespace: "n-1", - EncryptedSecret: "value", - ExternalID: nil, - } - - model.Append(1, appendOutboxMessage) - - require.Equal(t, []contracts.OutboxMessage{outboxMessage1}, model.ReceiveN(10)) - - model.Append(2, appendOutboxMessage) - - require.Equal(t, []contracts.OutboxMessage{outboxMessage1, outboxMessage2}, model.ReceiveN(10)) - - model.Delete(outboxMessage1.MessageID) - - require.Equal(t, []contracts.OutboxMessage{outboxMessage2}, model.ReceiveN(5)) - - model.Delete(outboxMessage2.MessageID) - - require.Empty(t, model.ReceiveN(1)) -} - -func TestOutboxStoreSecureValueOperationInProgress(t *testing.T) { - t.Parallel() - - t.Run("Append returns error when the queue already contains an operation for the secure value", func(t *testing.T) { - t.Parallel() - - testDB := sqlstore.NewTestStore(t, sqlstore.WithMigrator(migrator.New())) - tracer := noop.NewTracerProvider().Tracer("test") - - ctx := context.Background() - - outbox := ProvideOutboxQueue(database.ProvideDatabase(testDB, tracer), tracer, nil) - - _, err := outbox.Append(ctx, contracts.AppendOutboxMessage{ - RequestID: "1", - Type: contracts.CreateSecretOutboxMessage, - Name: "name1", - Namespace: "ns1", - EncryptedSecret: "v1", - KeeperName: nil, - ExternalID: nil, - }) - require.NoError(t, err) - - _, err = outbox.Append(ctx, contracts.AppendOutboxMessage{ - RequestID: "1", - Type: contracts.UpdateSecretOutboxMessage, - Name: "name1", - Namespace: "ns1", - EncryptedSecret: "v1", - KeeperName: nil, - ExternalID: nil, - }) - - require.ErrorIs(t, err, contracts.ErrSecureValueOperationInProgress) - }) -} - -func TestOutboxStore(t *testing.T) { - testDB := sqlstore.NewTestStore(t, sqlstore.WithMigrator(migrator.New())) - tracer := noop.NewTracerProvider().Tracer("test") - - ctx := context.Background() - - outbox := ProvideOutboxQueue(database.ProvideDatabase(testDB, tracer), tracer, nil) - - m1 := contracts.AppendOutboxMessage{ - Type: contracts.CreateSecretOutboxMessage, - Name: "s-1", - Namespace: "n-1", - EncryptedSecret: "value", - ExternalID: nil, - } - m2 := contracts.AppendOutboxMessage{ - Type: contracts.CreateSecretOutboxMessage, - Name: "s-1", - Namespace: "n-2", - EncryptedSecret: "value", - ExternalID: nil, - } - - messages, err := outbox.ReceiveN(ctx, 10) - require.NoError(t, err) - require.Empty(t, messages) - - messageID1, err := outbox.Append(ctx, m1) - require.NoError(t, err) - - for range 2 { - messages, err = outbox.ReceiveN(ctx, 10) - require.NoError(t, err) - require.Equal(t, 1, len(messages)) - require.Equal(t, messageID1, messages[0].MessageID) - } - - messageID2, err := outbox.Append(ctx, m2) - require.NoError(t, err) - - messages, err = outbox.ReceiveN(ctx, 3) - require.NoError(t, err) - require.Equal(t, 2, len(messages)) - require.Equal(t, messageID1, messages[0].MessageID) - require.Equal(t, messageID2, messages[1].MessageID) - - require.NoError(t, outbox.Delete(ctx, messageID1)) - messages, err = outbox.ReceiveN(ctx, 10) - require.NoError(t, err) - require.Equal(t, 1, len(messages)) - require.Equal(t, messageID2, messages[0].MessageID) - - require.NoError(t, outbox.Delete(ctx, messageID2)) - - messages, err = outbox.ReceiveN(ctx, 100) - require.NoError(t, err) - require.Empty(t, messages) -} - -func TestOutboxStoreProperty(t *testing.T) { - seed := time.Now().UnixMicro() - rng := rand.New(rand.NewSource(seed)) - - defer func() { - if t.Failed() { - fmt.Printf("TestOutboxStoreProperty: SEED=%+v\n\n", seed) - } - }() - - // The number of iterations was decided arbitrarily based on the time the test takes to run - for range 10 { - testDB := sqlstore.NewTestStore(t, sqlstore.WithMigrator(migrator.New())) - tracer := noop.NewTracerProvider().Tracer("test") - - outbox := ProvideOutboxQueue(database.ProvideDatabase(testDB, tracer), tracer, nil) - - model := newOutboxStoreModel() - - ctx := context.Background() - - for i := range 100 { - n := rng.Intn(3) - switch n { - case 0: - time.Sleep(1 * time.Microsecond) - message := contracts.AppendOutboxMessage{ - Type: contracts.CreateSecretOutboxMessage, - Name: fmt.Sprintf("s-%d", i), - Namespace: fmt.Sprintf("n-%d", i), - EncryptedSecret: "value", - ExternalID: nil, - } - messageID, err := outbox.Append(ctx, message) - require.NoError(t, err) - - model.Append(messageID, message) - - case 1: - n := uint(rng.Intn(10)) - messages, err := outbox.ReceiveN(ctx, n) - require.NoError(t, err) - - modelMessages := model.ReceiveN(n) - - require.Equal(t, len(modelMessages), len(messages)) - for i := range len(modelMessages) { - require.Equal(t, modelMessages[i].MessageID, messages[i].MessageID) - } - - case 2: - if len(model.rows) == 0 { - continue - } - - message := model.rows[rng.Intn(len(model.rows))] - - model.Delete(message.MessageID) - require.NoError(t, outbox.Delete(ctx, message.MessageID)) - - default: - panic(fmt.Sprintf("unhandled action: %+v", n)) - } - } - } -} diff --git a/pkg/storage/secret/metadata/query.go b/pkg/storage/secret/metadata/query.go index 907a4d6cbea..2c85d762b87 100644 --- a/pkg/storage/secret/metadata/query.go +++ b/pkg/storage/secret/metadata/query.go @@ -27,18 +27,12 @@ var ( sqlSecureValueRead = mustTemplate("secure_value_read.sql") sqlSecureValueList = mustTemplate("secure_value_list.sql") sqlSecureValueCreate = mustTemplate("secure_value_create.sql") - sqlSecureValueDelete = mustTemplate("secure_value_delete.sql") - sqlSecureValueUpdate = mustTemplate("secure_value_update.sql") sqlSecureValueUpdateExternalId = mustTemplate("secure_value_updateExternalId.sql") - sqlSecureValueUpdateStatus = mustTemplate("secure_value_updateStatus.sql") sqlSecureValueReadForDecrypt = mustTemplate("secure_value_read_for_decrypt.sql") - sqlSecureValueOutboxAppend = mustTemplate("secure_value_outbox_append.sql") - sqlSecureValueOutboxFetchMessageIDs = mustTemplate("secure_value_outbox_fetch_message_ids.sql") - sqlSecureValueOutboxReceiveN = mustTemplate("secure_value_outbox_receiveN.sql") - sqlSecureValueOutboxDelete = mustTemplate("secure_value_outbox_delete.sql") - sqlSecureValueOutboxUpdateReceiveCount = mustTemplate("secure_value_outbox_update_receive_count.sql") - sqlSecureValueOutboxQueryTimestamp = mustTemplate("secure_value_outbox_query_timestamp.sql") + sqlGetLatestSecureValueVersion = mustTemplate("secure_value_get_latest_version.sql") + sqlSecureValueSetVersionToActive = mustTemplate("secure_value_set_version_to_active.sql") + sqlSecureValueSetVersionToInactive = mustTemplate("secure_value_set_version_to_inactive.sql") ) func mustTemplate(filename string) *template.Template { @@ -150,75 +144,69 @@ func (r readSecureValue) Validate() error { return nil // TODO } -type listSecureValue struct { +type getLatestSecureValueVersion struct { sqltemplate.SQLTemplate Namespace string + Name string } -// Validate is only used if we use `dbutil` from `unifiedstorage` -func (r listSecureValue) Validate() error { - return nil // TODO +func (r getLatestSecureValueVersion) Validate() error { + return nil } -type createSecureValue struct { +type secureValueSetVersionToActive struct { sqltemplate.SQLTemplate - Row *secureValueDB + Namespace string + Name string + Version int64 } -// Validate is only used if we use `dbutil` from `unifiedstorage` -func (r createSecureValue) Validate() error { - return nil // TODO +func (r secureValueSetVersionToActive) Validate() error { + return nil } -// Delete -type deleteSecureValue struct { +type secureValueSetVersionToInactive struct { sqltemplate.SQLTemplate Namespace string Name string + Version int64 } -// Validate is only used if we use `dbutil` from `unifiedstorage` -func (r deleteSecureValue) Validate() error { - return nil // TODO +func (r secureValueSetVersionToInactive) Validate() error { + return nil } -// Update externalId -type updateExternalIdSecureValue struct { +type listSecureValue struct { sqltemplate.SQLTemplate - Namespace string - Name string - ExternalID string + Namespace string } // Validate is only used if we use `dbutil` from `unifiedstorage` -func (r updateExternalIdSecureValue) Validate() error { +func (r listSecureValue) Validate() error { return nil // TODO } -// Update secure value -type updateSecureValue struct { +type createSecureValue struct { sqltemplate.SQLTemplate - Namespace string - Name string - Row *secureValueDB + Row *secureValueDB } // Validate is only used if we use `dbutil` from `unifiedstorage` -func (r updateSecureValue) Validate() error { +func (r createSecureValue) Validate() error { return nil // TODO } -// update status message -type updateStatusSecureValue struct { +// Update externalId +type updateExternalIdSecureValue struct { sqltemplate.SQLTemplate - Namespace string - Name string - Phase string - Message string + Namespace string + Name string + Version int64 + ExternalID string } // Validate is only used if we use `dbutil` from `unifiedstorage` -func (r updateStatusSecureValue) Validate() error { +func (r updateExternalIdSecureValue) Validate() error { return nil // TODO } @@ -229,48 +217,3 @@ type readSecureValueForDecrypt struct { } func (r readSecureValueForDecrypt) Validate() error { return nil } - -/*************************************/ -/**-- Secure Value Outbox Queries --**/ -/*************************************/ -type appendSecureValueOutbox struct { - sqltemplate.SQLTemplate - Row *outboxMessageDB -} - -func (appendSecureValueOutbox) Validate() error { return nil } - -type receiveNSecureValueOutbox struct { - sqltemplate.SQLTemplate - MessageIDs []int64 -} - -func (receiveNSecureValueOutbox) Validate() error { return nil } - -type fetchMessageIDsOutbox struct { - sqltemplate.SQLTemplate - ReceiveLimit uint -} - -func (fetchMessageIDsOutbox) Validate() error { return nil } - -type deleteSecureValueOutbox struct { - sqltemplate.SQLTemplate - MessageID int64 -} - -func (deleteSecureValueOutbox) Validate() error { return nil } - -type getOutboxMessageTimestamp struct { - sqltemplate.SQLTemplate - MessageID int64 -} - -func (getOutboxMessageTimestamp) Validate() error { return nil } - -type incrementReceiveCountOutbox struct { - sqltemplate.SQLTemplate - MessageIDs []int64 -} - -func (incrementReceiveCountOutbox) Validate() error { return nil } diff --git a/pkg/storage/secret/metadata/query_test.go b/pkg/storage/secret/metadata/query_test.go index 8a5ff0e6a9a..dce469d6d87 100644 --- a/pkg/storage/secret/metadata/query_test.go +++ b/pkg/storage/secret/metadata/query_test.go @@ -1,7 +1,6 @@ package metadata import ( - "database/sql" "testing" "text/template" @@ -123,6 +122,27 @@ func TestSecureValueQueries(t *testing.T) { mocks.CheckQuerySnapshots(t, mocks.TemplateTestSetup{ RootDir: "testdata", Templates: map[*template.Template][]mocks.TemplateTestCase{ + sqlGetLatestSecureValueVersion: { + { + Name: "get latest secure value version", + Data: &getLatestSecureValueVersion{ + SQLTemplate: mocks.NewTestingSQLTemplate(), + Name: "name", + Namespace: "ns", + }, + }, + }, + sqlSecureValueSetVersionToActive: { + { + Name: "set secure value version to active", + Data: &secureValueSetVersionToActive{ + SQLTemplate: mocks.NewTestingSQLTemplate(), + Name: "name", + Namespace: "ns", + Version: 1, + }, + }, + }, sqlSecureValueRead: { { Name: "read", @@ -166,8 +186,7 @@ func TestSecureValueQueries(t *testing.T) { CreatedBy: "user:ryan", Updated: 5678, UpdatedBy: "user:cameron", - Phase: "creating", - Message: toNullString(nil), + Version: 1, Description: "description", Keeper: toNullString(nil), Decrypters: toNullString(nil), @@ -190,72 +209,7 @@ func TestSecureValueQueries(t *testing.T) { CreatedBy: "user:ryan", Updated: 5678, UpdatedBy: "user:cameron", - Phase: "creating", - Message: toNullString(ptr.To("message_test")), - Description: "description", - Keeper: toNullString(ptr.To("keeper_test")), - Decrypters: toNullString(ptr.To("decrypters_test")), - Ref: toNullString(ptr.To("ref_test")), - ExternalID: "extId", - }, - }, - }, - }, - sqlSecureValueDelete: { - { - Name: "delete", - Data: &deleteSecureValue{ - SQLTemplate: mocks.NewTestingSQLTemplate(), - Name: "name", - Namespace: "ns", - }, - }, - }, - sqlSecureValueUpdate: { - { - Name: "update-null", - Data: &updateSecureValue{ - SQLTemplate: mocks.NewTestingSQLTemplate(), - Name: "name", - Namespace: "ns", - Row: &secureValueDB{ - GUID: "abc", - Name: "name", - Namespace: "ns", - Annotations: `{"x":"XXXX"}`, - Labels: `{"a":"AAA", "b", "BBBB"}`, - Created: 1234, - CreatedBy: "user:ryan", - Updated: 5678, - UpdatedBy: "user:cameron", - Phase: "creating", - Message: toNullString(nil), - Description: "description", - Keeper: toNullString(nil), - Decrypters: toNullString(nil), - Ref: toNullString(nil), - ExternalID: "extId", - }, - }, - }, - { - Name: "update-not-null", - Data: &updateSecureValue{ - SQLTemplate: mocks.NewTestingSQLTemplate(), - Name: "name", - Namespace: "ns", - Row: &secureValueDB{ - GUID: "abc", - Name: "name", - Namespace: "ns", - Annotations: `{"x":"XXXX"}`, - Labels: `{"a":"AAA", "b", "BBBB"}`, - Created: 1234, - CreatedBy: "user:ryan", - Updated: 5678, - UpdatedBy: "user:cameron", - Phase: "creating", - Message: toNullString(ptr.To("message_test")), + Version: 1, Description: "description", Keeper: toNullString(ptr.To("keeper_test")), Decrypters: toNullString(ptr.To("decrypters_test")), @@ -276,18 +230,6 @@ func TestSecureValueQueries(t *testing.T) { }, }, }, - sqlSecureValueUpdateStatus: { - { - Name: "updateStatus", - Data: &updateStatusSecureValue{ - SQLTemplate: mocks.NewTestingSQLTemplate(), - Name: "name", - Namespace: "ns", - Phase: "Succeeded", - Message: "message-1", - }, - }, - }, sqlSecureValueReadForDecrypt: { { Name: "read-for-decrypt", @@ -301,111 +243,3 @@ func TestSecureValueQueries(t *testing.T) { }, }) } - -func TestSecureValueOutboxQueries(t *testing.T) { - mocks.CheckQuerySnapshots(t, mocks.TemplateTestSetup{ - RootDir: "testdata", - Templates: map[*template.Template][]mocks.TemplateTestCase{ - sqlSecureValueOutboxUpdateReceiveCount: { - { - - Name: "update-receive-count", - Data: &incrementReceiveCountOutbox{ - SQLTemplate: mocks.NewTestingSQLTemplate(), - MessageIDs: []int64{1, 2, 3}, - }, - }, - }, - sqlSecureValueOutboxAppend: { - { - Name: "no-encrypted-secret", - Data: &appendSecureValueOutbox{ - SQLTemplate: mocks.NewTestingSQLTemplate(), - Row: &outboxMessageDB{ - MessageID: 1, - MessageType: "some-type", - Name: "name", - Namespace: "namespace", - ExternalID: sql.NullString{Valid: true, String: "external-id"}, - KeeperName: sql.NullString{Valid: true, String: "keeper"}, - Created: 1234, - }, - }, - }, - { - Name: "no-external-id", - Data: &appendSecureValueOutbox{ - SQLTemplate: mocks.NewTestingSQLTemplate(), - Row: &outboxMessageDB{ - MessageID: 1, - MessageType: "some-type", - Name: "name", - Namespace: "namespace", - EncryptedSecret: sql.NullString{Valid: true, String: "encrypted"}, - KeeperName: sql.NullString{Valid: true, String: "keeper"}, - Created: 1234, - }, - }, - }, - { - Name: "no-keeper-name", - Data: &appendSecureValueOutbox{ - SQLTemplate: mocks.NewTestingSQLTemplate(), - Row: &outboxMessageDB{ - MessageID: 1, - MessageType: "some-type", - Name: "name", - Namespace: "namespace", - EncryptedSecret: sql.NullString{Valid: true, String: "encrypted"}, - ExternalID: sql.NullString{Valid: true, String: "external-id"}, - Created: 1234, - }, - }, - }, - { - Name: "all-fields-present", - Data: &appendSecureValueOutbox{ - SQLTemplate: mocks.NewTestingSQLTemplate(), - Row: &outboxMessageDB{ - MessageID: 1, - MessageType: "some-type", - Name: "name", - Namespace: "namespace", - EncryptedSecret: sql.NullString{Valid: true, String: "encrypted"}, - ExternalID: sql.NullString{Valid: true, String: ""}, // can be empty string - KeeperName: sql.NullString{Valid: true, String: "keeper"}, - Created: 1234, - }, - }, - }, - }, - sqlSecureValueOutboxFetchMessageIDs: { - { - Name: "basic", - Data: &fetchMessageIDsOutbox{ - SQLTemplate: mocks.NewTestingSQLTemplate(), - ReceiveLimit: 10, - }, - }, - }, - sqlSecureValueOutboxReceiveN: { - { - Name: "basic", - Data: &receiveNSecureValueOutbox{ - SQLTemplate: mocks.NewTestingSQLTemplate(), - MessageIDs: []int64{1, 2, 3}, - }, - }, - }, - sqlSecureValueOutboxDelete: { - { - Name: "basic", - Data: &deleteSecureValueOutbox{ - SQLTemplate: mocks.NewTestingSQLTemplate(), - MessageID: 1, - }, - }, - }, - }, - }) -} diff --git a/pkg/storage/secret/metadata/secure_value_model.go b/pkg/storage/secret/metadata/secure_value_model.go index d90beaa6782..134128f8a25 100644 --- a/pkg/storage/secret/metadata/secure_value_model.go +++ b/pkg/storage/secret/metadata/secure_value_model.go @@ -29,8 +29,8 @@ type secureValueDB struct { UpdatedBy string // Kubernetes Status - Phase string - Message sql.NullString + Active bool + Version int64 // Spec Description string @@ -74,8 +74,8 @@ func (sv *secureValueDB) toKubernetes() (*secretv0alpha1.SecureValue, error) { Decrypters: decrypters, }, Status: secretv0alpha1.SecureValueStatus{ - Phase: secretv0alpha1.SecureValuePhase(sv.Phase), ExternalID: sv.ExternalID, + Version: sv.Version, }, } @@ -85,10 +85,7 @@ func (sv *secureValueDB) toKubernetes() (*secretv0alpha1.SecureValue, error) { if sv.Ref.Valid { resource.Spec.Ref = &sv.Ref.String } - if sv.Message.Valid { - resource.Status.Message = sv.Message.String - } - resource.Status.Phase = secretv0alpha1.SecureValuePhase(sv.Phase) + resource.Status.ExternalID = sv.ExternalID // Set all meta fields here for consistency. @@ -131,24 +128,6 @@ func toCreateRow(sv *secretv0alpha1.SecureValue, actorUID string) (*secureValueD return row, nil } -// toUpdateRow maps a Kubernetes resource into a DB row for existing resources being updated. -func toUpdateRow(currentRow *secureValueDB, newSecureValue *secretv0alpha1.SecureValue, actorUID, externalID string) (*secureValueDB, error) { - row, err := toRow(newSecureValue, externalID) - if err != nil { - return nil, fmt.Errorf("failed to create: %w", err) - } - - now := time.Now().UTC().Unix() - - row.GUID = currentRow.GUID - row.Created = currentRow.Created - row.CreatedBy = currentRow.CreatedBy - row.Updated = now - row.UpdatedBy = actorUID - - return row, nil -} - // toRow maps a Kubernetes resource into a DB row. func toRow(sv *secretv0alpha1.SecureValue, externalID string) (*secureValueDB, error) { var annotations string @@ -201,11 +180,6 @@ func toRow(sv *secretv0alpha1.SecureValue, externalID string) (*secureValueDB, e return nil, fmt.Errorf("failed to get resource version: %w", err) } - var statusMessage *string - if sv.Status.Message != "" { - statusMessage = &sv.Status.Message - } - return &secureValueDB{ GUID: string(sv.UID), Name: sv.Name, @@ -217,8 +191,7 @@ func toRow(sv *secretv0alpha1.SecureValue, externalID string) (*secureValueDB, e Updated: updatedTimestamp, UpdatedBy: meta.GetUpdatedBy(), - Phase: string(sv.Status.Phase), - Message: toNullString(statusMessage), + Version: sv.Status.Version, Description: sv.Spec.Description, Keeper: toNullString(sv.Spec.Keeper), @@ -233,6 +206,7 @@ type secureValueForDecrypt struct { Keeper sql.NullString Decrypters sql.NullString Ref sql.NullString + Active bool ExternalID string } diff --git a/pkg/storage/secret/metadata/secure_value_store.go b/pkg/storage/secret/metadata/secure_value_store.go index 6f79dfbd353..ecc22df28bd 100644 --- a/pkg/storage/secret/metadata/secure_value_store.go +++ b/pkg/storage/secret/metadata/secure_value_store.go @@ -55,33 +55,18 @@ func (s *secureValueMetadataStorage) Create(ctx context.Context, sv *secretv0alp )) defer span.End() - sv.Status.Phase = secretv0alpha1.SecureValuePhasePending - sv.Status.Message = "Creating secure value" + // Set inside of the transaction callback + var row *secureValueDB - row, err := toCreateRow(sv, actorUID) - if err != nil { - return nil, fmt.Errorf("to create row: %w", err) - } - - req := createSecureValue{ - SQLTemplate: sqltemplate.New(s.dialect), - Row: row, - } - - query, err := sqltemplate.Execute(sqlSecureValueCreate, req) - if err != nil { - return nil, fmt.Errorf("execute template %q: %w", sqlSecureValueCreate.Name(), err) - } - - err = s.db.Transaction(ctx, func(ctx context.Context) error { - if row.Keeper.Valid { + err := s.db.Transaction(ctx, func(ctx context.Context) error { + if sv.Spec.Keeper != nil { // Validate before inserting that the chosen `keeper` exists. // -- This is a copy of KeeperMetadataStore.read, which is not public at the moment, and is not defined in contract.KeeperMetadataStorage req := &readKeeper{ SQLTemplate: sqltemplate.New(s.dialect), - Namespace: row.Namespace, - Name: row.Keeper.String, + Namespace: sv.Namespace, + Name: *sv.Spec.Keeper, IsForUpdate: true, } @@ -101,23 +86,61 @@ func (s *secureValueMetadataStorage) Create(ctx context.Context, sv *secretv0alp } } - res, err := s.db.ExecContext(ctx, query, req.GetArgs()...) + latestVersion, err := s.getLatestVersion(ctx, xkube.Namespace(sv.Namespace), sv.Name) if err != nil { - if sql.IsRowAlreadyExistsError(err) { - return fmt.Errorf("namespace=%+v name=%+v %w", sv.Namespace, sv.Name, contracts.ErrSecureValueAlreadyExists) - } - return fmt.Errorf("inserting row: %w", err) + return fmt.Errorf("fetching latest secure value version: %w", err) } - rowsAffected, err := res.RowsAffected() - if err != nil { - return fmt.Errorf("getting rows affected: %w", err) + version := int64(1) + if latestVersion != nil { + version = *latestVersion + 1 } - if rowsAffected != 1 { - return fmt.Errorf("expected 1 row affected, got %d for %s on %s", rowsAffected, row.Name, row.Namespace) + // Some other concurrent request may have created the version we're trying to create, + // if that's the case, we'll retry with a new version up to max attempts. + maxAttempts := 3 + attempts := 0 + for { + sv.Status.Version = version + + row, err = toCreateRow(sv, actorUID) + if err != nil { + return fmt.Errorf("to create row: %w", err) + } + + req := createSecureValue{ + SQLTemplate: sqltemplate.New(s.dialect), + Row: row, + } + + query, err := sqltemplate.Execute(sqlSecureValueCreate, req) + if err != nil { + return fmt.Errorf("execute template %q: %w", sqlSecureValueCreate.Name(), err) + } + + res, err := s.db.ExecContext(ctx, query, req.GetArgs()...) + if err != nil { + if sql.IsRowAlreadyExistsError(err) { + if attempts < maxAttempts { + attempts += 1 + version += 1 + continue + } + return fmt.Errorf("namespace=%+v name=%+v %w", sv.Namespace, sv.Name, contracts.ErrSecureValueAlreadyExists) + } + return fmt.Errorf("inserting row: %w", err) + } + + rowsAffected, err := res.RowsAffected() + if err != nil { + return fmt.Errorf("getting rows affected: %w", err) + } + + if rowsAffected != 1 { + return fmt.Errorf("expected 1 row affected, got %d for %s on %s", rowsAffected, row.Name, row.Namespace) + } + return nil } - return nil }) if err != nil { return nil, fmt.Errorf("db failure: %w", err) @@ -134,157 +157,161 @@ func (s *secureValueMetadataStorage) Create(ctx context.Context, sv *secretv0alp return createdSecureValue, nil } -func (s *secureValueMetadataStorage) Read(ctx context.Context, namespace xkube.Namespace, name string, opts contracts.ReadOpts) (*secretv0alpha1.SecureValue, error) { - start := time.Now() - ctx, span := s.tracer.Start(ctx, "SecureValueMetadataStorage.Read", trace.WithAttributes( +func (s *secureValueMetadataStorage) getLatestVersion(ctx context.Context, namespace xkube.Namespace, name string) (*int64, error) { + ctx, span := s.tracer.Start(ctx, "SecureValueMetadataStorage.getLatestVersion", trace.WithAttributes( attribute.String("name", name), attribute.String("namespace", namespace.String()), - attribute.Bool("isForUpdate", opts.ForUpdate), )) defer span.End() - secureValue, err := s.read(ctx, namespace, name, opts) + req := getLatestSecureValueVersion{ + SQLTemplate: sqltemplate.New(s.dialect), + Namespace: namespace.String(), + Name: name, + } + + q, err := sqltemplate.Execute(sqlGetLatestSecureValueVersion, req) if err != nil { - return nil, err + return nil, fmt.Errorf("execute template %q: %w", sqlGetLatestSecureValueVersion.Name(), err) } - secureValueKub, err := secureValue.toKubernetes() + rows, err := s.db.QueryContext(ctx, q, req.GetArgs()...) if err != nil { - return nil, fmt.Errorf("convert to kubernetes object: %w", err) + return nil, fmt.Errorf("fetching latest version for secure value: namespace=%+v name=%+v %w", namespace, name, err) } + defer func() { _ = rows.Close() }() - s.metrics.SecureValueMetadataGetDuration.Observe(time.Since(start).Seconds()) - s.metrics.SecureValueMetadataGetCount.Inc() + if err := rows.Err(); err != nil { + return nil, fmt.Errorf("error executing query: %w", err) + } - return secureValueKub, nil + if !rows.Next() { + return nil, nil + } + + var version int64 + if err := rows.Scan(&version); err != nil { + return nil, fmt.Errorf("scanning version from returned rows: %w", err) + } + + return &version, nil } -func (s *secureValueMetadataStorage) Update(ctx context.Context, newSecureValue *secretv0alpha1.SecureValue, actorUID string) (*secretv0alpha1.SecureValue, error) { +func (s *secureValueMetadataStorage) ReadForDecrypt(ctx context.Context, namespace xkube.Namespace, name string) (*contracts.DecryptSecureValue, error) { start := time.Now() - ctx, span := s.tracer.Start(ctx, "SecureValueMetadataStorage.Update", trace.WithAttributes( - attribute.String("name", newSecureValue.GetName()), - attribute.String("namespace", newSecureValue.GetNamespace()), - attribute.String("actorUID", actorUID), + ctx, span := s.tracer.Start(ctx, "SecureValueMetadataStorage.ReadForDecrypt", trace.WithAttributes( + attribute.String("name", name), + attribute.String("namespace", namespace.String()), )) defer span.End() - var newRow *secureValueDB - - err := s.db.Transaction(ctx, func(ctx context.Context) error { - read, err := s.read(ctx, xkube.Namespace(newSecureValue.Namespace), newSecureValue.Name, contracts.ReadOpts{ForUpdate: true}) - if err != nil { - return fmt.Errorf("reading secure value: %w", err) - } - - // TODO: Confirm the ExternalID should come from the read model. - var updateErr error - newRow, updateErr = toUpdateRow(&read, newSecureValue, actorUID, read.ExternalID) - if updateErr != nil { - return fmt.Errorf("model to update row: %w", updateErr) - } - - if newRow.Keeper.Valid { - // Validate before updating that the new `keeper` exists. + req := readSecureValueForDecrypt{ + SQLTemplate: sqltemplate.New(s.dialect), + Namespace: namespace.String(), + Name: name, + } - // -- This is a copy of KeeperMetadataStore.read, which is not public at the moment, and is not defined in contract.KeeperMetadataStorage - req := &readKeeper{ - SQLTemplate: sqltemplate.New(s.dialect), - Namespace: newRow.Namespace, - Name: newRow.Keeper.String, - IsForUpdate: true, - } + query, err := sqltemplate.Execute(sqlSecureValueReadForDecrypt, req) + if err != nil { + return nil, fmt.Errorf("execute template %q: %w", sqlSecureValueReadForDecrypt.Name(), err) + } - query, err := sqltemplate.Execute(sqlKeeperRead, req) - if err != nil { - return fmt.Errorf("execute template %q: %w", sqlKeeperRead.Name(), err) - } + res, err := s.db.QueryContext(ctx, query, req.GetArgs()...) + if err != nil { + return nil, fmt.Errorf("reading row: %w", err) + } + defer func() { _ = res.Close() }() - res, err := s.db.QueryContext(ctx, query, req.GetArgs()...) - if err != nil { - return fmt.Errorf("getting row: %w", err) - } - defer func() { _ = res.Close() }() + var row secureValueForDecrypt + if !res.Next() { + return nil, contracts.ErrSecureValueNotFound + } + if err := res.Scan( + &row.Keeper, &row.Decrypters, + &row.Ref, &row.ExternalID, &row.Active); err != nil { + return nil, fmt.Errorf("failed to scan secure value row: %w", err) + } - if !res.Next() { - return contracts.ErrKeeperNotFound - } - } + if err := res.Err(); err != nil { + return nil, fmt.Errorf("read rows error: %w", err) + } - req := &updateSecureValue{ - SQLTemplate: sqltemplate.New(s.dialect), - Namespace: newRow.Namespace, - Name: newRow.Name, - Row: newRow, - } + if !row.Active { + return nil, fmt.Errorf("bug: read an inactive version: row=%+v", row) + } - query, err := sqltemplate.Execute(sqlSecureValueUpdate, req) - if err != nil { - return fmt.Errorf("execute template %q: %w", sqlSecureValueUpdate.Name(), err) - } + secureValue, err := row.toDecrypt() + if err != nil { + return nil, fmt.Errorf("convert to kubernetes object: %w", err) + } - result, err := s.db.ExecContext(ctx, query, req.GetArgs()...) - if err != nil { - return fmt.Errorf("updating row: %w", err) - } + s.metrics.SecureValueGetForDecryptDuration.Observe(time.Since(start).Seconds()) - rowsAffected, err := result.RowsAffected() - if err != nil { - return fmt.Errorf("getting rows affected: %w", err) - } + return secureValue, nil +} - if rowsAffected != 1 { - return fmt.Errorf("expected 1 row affected, got %d for %s on %s", rowsAffected, newRow.Name, newRow.Namespace) - } +func (s *secureValueMetadataStorage) readActiveVersion(ctx context.Context, namespace xkube.Namespace, name string, opts contracts.ReadOpts) (secureValueDB, error) { + req := readSecureValue{ + SQLTemplate: sqltemplate.New(s.dialect), + Namespace: namespace.String(), + Name: name, + IsForUpdate: opts.ForUpdate, + } - return nil - }) + query, err := sqltemplate.Execute(sqlSecureValueRead, req) if err != nil { - return nil, fmt.Errorf("db failure: %w", err) + return secureValueDB{}, fmt.Errorf("execute template %q: %w", sqlSecureValueRead.Name(), err) } - secureValue, err := newRow.toKubernetes() + res, err := s.db.QueryContext(ctx, query, req.GetArgs()...) if err != nil { - return nil, fmt.Errorf("convert to kubernetes object: %w", err) + return secureValueDB{}, fmt.Errorf("reading row: %w", err) } + defer func() { _ = res.Close() }() - s.metrics.SecureValueMetadataUpdateDuration.Observe(time.Since(start).Seconds()) - s.metrics.SecureValueMetadataUpdateCount.Inc() + var secureValue secureValueDB + if !res.Next() { + return secureValueDB{}, contracts.ErrSecureValueNotFound + } + + if err := res.Scan( + &secureValue.GUID, &secureValue.Name, &secureValue.Namespace, + &secureValue.Annotations, &secureValue.Labels, + &secureValue.Created, &secureValue.CreatedBy, + &secureValue.Updated, &secureValue.UpdatedBy, + &secureValue.Description, &secureValue.Keeper, &secureValue.Decrypters, &secureValue.Ref, &secureValue.ExternalID, &secureValue.Active, &secureValue.Version); err != nil { + return secureValueDB{}, fmt.Errorf("failed to scan secure value row: %w", err) + } + if err := res.Err(); err != nil { + return secureValueDB{}, fmt.Errorf("read rows error: %w", err) + } return secureValue, nil } -func (s *secureValueMetadataStorage) Delete(ctx context.Context, namespace xkube.Namespace, name string) error { +func (s *secureValueMetadataStorage) Read(ctx context.Context, namespace xkube.Namespace, name string, opts contracts.ReadOpts) (*secretv0alpha1.SecureValue, error) { start := time.Now() - ctx, span := s.tracer.Start(ctx, "SecureValueMetadataStorage.Delete", trace.WithAttributes( + ctx, span := s.tracer.Start(ctx, "SecureValueMetadataStorage.Read", trace.WithAttributes( attribute.String("name", name), attribute.String("namespace", namespace.String()), + attribute.Bool("isForUpdate", opts.ForUpdate), )) defer span.End() - req := deleteSecureValue{ - SQLTemplate: sqltemplate.New(s.dialect), - Namespace: namespace.String(), - Name: name, - } - - query, err := sqltemplate.Execute(sqlSecureValueDelete, req) + secureValue, err := s.readActiveVersion(ctx, namespace, name, opts) if err != nil { - return fmt.Errorf("execute template %q: %w", sqlSecureValueDelete.Name(), err) + return nil, err } - res, err := s.db.ExecContext(ctx, query, req.GetArgs()...) + secureValueKub, err := secureValue.toKubernetes() if err != nil { - return fmt.Errorf("deleting secure value row: %w", err) - } - - if rowsAffected, err := res.RowsAffected(); err != nil || rowsAffected != 1 { - return fmt.Errorf("deleting secure value rowsAffected=%d error=%w", rowsAffected, err) + return nil, fmt.Errorf("convert to kubernetes object: %w", err) } - s.metrics.SecureValueMetadataDeleteDuration.Observe(time.Since(start).Seconds()) - s.metrics.SecureValueMetadataDeleteCount.Inc() + s.metrics.SecureValueMetadataGetDuration.Observe(time.Since(start).Seconds()) + s.metrics.SecureValueMetadataGetCount.Inc() - return nil + return secureValueKub, nil } func (s *secureValueMetadataStorage) List(ctx context.Context, namespace xkube.Namespace) (svList []secretv0alpha1.SecureValue, error error) { @@ -323,15 +350,18 @@ func (s *secureValueMetadataStorage) List(ctx context.Context, namespace xkube.N &row.Labels, &row.Created, &row.CreatedBy, &row.Updated, &row.UpdatedBy, - &row.Phase, &row.Message, &row.Description, &row.Keeper, &row.Decrypters, - &row.Ref, &row.ExternalID, + &row.Ref, &row.ExternalID, &row.Version, &row.Active, ) if err != nil { return nil, fmt.Errorf("error reading secure value row: %w", err) } + if !row.Active { + return nil, fmt.Errorf("bug: read an inactive version: row=%+v", row) + } + secureValue, err := row.toKubernetes() if err != nil { return nil, fmt.Errorf("convert to kubernetes object: %w", err) @@ -349,172 +379,116 @@ func (s *secureValueMetadataStorage) List(ctx context.Context, namespace xkube.N return secureValues, nil } -func (s *secureValueMetadataStorage) SetExternalID(ctx context.Context, namespace xkube.Namespace, name string, externalID contracts.ExternalID) error { - start := time.Now() +func (s *secureValueMetadataStorage) SetVersionToActive(ctx context.Context, namespace xkube.Namespace, name string, version int64) error { ctx, span := s.tracer.Start(ctx, "SecureValueMetadataStorage.SetExternalID", trace.WithAttributes( attribute.String("name", name), attribute.String("namespace", namespace.String()), - attribute.String("externalID", externalID.String()), + attribute.Int64("version", version), )) defer span.End() - req := updateExternalIdSecureValue{ + req := secureValueSetVersionToActive{ SQLTemplate: sqltemplate.New(s.dialect), Namespace: namespace.String(), Name: name, - ExternalID: externalID.String(), + Version: version, } - q, err := sqltemplate.Execute(sqlSecureValueUpdateExternalId, req) + q, err := sqltemplate.Execute(sqlSecureValueSetVersionToActive, req) if err != nil { - return fmt.Errorf("execute template %q: %w", sqlSecureValueUpdateExternalId.Name(), err) + return fmt.Errorf("execute template %q: %w", sqlSecureValueSetVersionToActive.Name(), err) } res, err := s.db.ExecContext(ctx, q, req.GetArgs()...) if err != nil { - return fmt.Errorf("setting secure value external id: namespace=%+v name=%+v externalID=%+v %w", namespace, name, externalID, err) + return fmt.Errorf("setting secure value version to active: namespace=%+v name=%+v version=%+v %w", namespace, name, version, err) } // validate modified cound modifiedCount, err := res.RowsAffected() if err != nil { - return fmt.Errorf("getting updated rows update external id secure value: %w", err) + return fmt.Errorf("fetching number of modified rows: %w", err) } - if modifiedCount > 1 { - return fmt.Errorf("secureValueMetadataStorage.SetExternalID: modified more than one secret, this is a bug, check the where condition: modifiedCount=%d", modifiedCount) + if modifiedCount == 0 { + return fmt.Errorf("expected to modify at least one row but modified 0: modifiedCount=%d", modifiedCount) } - s.metrics.SecureValueSetExternalIDDuration.Observe(time.Since(start).Seconds()) return nil } -func (s *secureValueMetadataStorage) SetStatus(ctx context.Context, namespace xkube.Namespace, name string, status secretv0alpha1.SecureValueStatus) error { - start := time.Now() - ctx, span := s.tracer.Start(ctx, "SecureValueMetadataStorage.SetStatus", trace.WithAttributes( +func (s *secureValueMetadataStorage) SetVersionToInactive(ctx context.Context, namespace xkube.Namespace, name string, version int64) error { + ctx, span := s.tracer.Start(ctx, "SecureValueMetadataStorage.SetExternalID", trace.WithAttributes( attribute.String("name", name), attribute.String("namespace", namespace.String()), - attribute.String("status.phase", string(status.Phase)), - attribute.String("status.message", status.Message), - attribute.String("status.externalID", status.ExternalID), + attribute.Int64("version", version), )) defer span.End() - req := updateStatusSecureValue{ + req := secureValueSetVersionToInactive{ SQLTemplate: sqltemplate.New(s.dialect), Namespace: namespace.String(), Name: name, - Phase: string(status.Phase), - Message: status.Message, + Version: version, } - q, err := sqltemplate.Execute(sqlSecureValueUpdateStatus, req) + q, err := sqltemplate.Execute(sqlSecureValueSetVersionToInactive, req) if err != nil { - return fmt.Errorf("execute template %q: %w", sqlSecureValueUpdateStatus.Name(), err) + return fmt.Errorf("execute template %q: %w", sqlSecureValueSetVersionToInactive.Name(), err) } res, err := s.db.ExecContext(ctx, q, req.GetArgs()...) if err != nil { - return fmt.Errorf("setting secure value status to Succeeded id: namespace=%+v name=%+v %w", namespace, name, err) + return fmt.Errorf("setting secure value version to active: namespace=%+v name=%+v version=%+v %w", namespace, name, version, err) } - // validate modified cound modifiedCount, err := res.RowsAffected() if err != nil { - return fmt.Errorf("getting updated rows update status secure value: %w", err) + return fmt.Errorf("fetching number of modified rows: %w", err) } if modifiedCount > 1 { - return fmt.Errorf("secureValueMetadataStorage.SetExternalID: modified more than one secret, this is a bug, check the where condition: modifiedCount=%d", modifiedCount) + return fmt.Errorf("expected to modify at at most one row but modified more: modifiedCount=%d", modifiedCount) } - s.metrics.SecureValueSetStatusDuration.Observe(time.Since(start).Seconds()) return nil } -func (s *secureValueMetadataStorage) ReadForDecrypt(ctx context.Context, namespace xkube.Namespace, name string) (*contracts.DecryptSecureValue, error) { +func (s *secureValueMetadataStorage) SetExternalID(ctx context.Context, namespace xkube.Namespace, name string, version int64, externalID contracts.ExternalID) error { start := time.Now() - ctx, span := s.tracer.Start(ctx, "SecureValueMetadataStorage.ReadForDecrypt", trace.WithAttributes( + ctx, span := s.tracer.Start(ctx, "SecureValueMetadataStorage.SetExternalID", trace.WithAttributes( attribute.String("name", name), attribute.String("namespace", namespace.String()), + attribute.String("externalID", externalID.String()), + attribute.Int64("version", version), )) defer span.End() - req := readSecureValueForDecrypt{ + req := updateExternalIdSecureValue{ SQLTemplate: sqltemplate.New(s.dialect), Namespace: namespace.String(), Name: name, + Version: version, + ExternalID: externalID.String(), } - query, err := sqltemplate.Execute(sqlSecureValueReadForDecrypt, req) - if err != nil { - return nil, fmt.Errorf("execute template %q: %w", sqlSecureValueReadForDecrypt.Name(), err) - } - - res, err := s.db.QueryContext(ctx, query, req.GetArgs()...) - if err != nil { - return nil, fmt.Errorf("reading row: %w", err) - } - defer func() { _ = res.Close() }() - - var row secureValueForDecrypt - if !res.Next() { - return nil, contracts.ErrSecureValueNotFound - } - if err := res.Scan( - &row.Keeper, &row.Decrypters, - &row.Ref, &row.ExternalID); err != nil { - return nil, fmt.Errorf("failed to scan secure value row: %w", err) - } - - if err := res.Err(); err != nil { - return nil, fmt.Errorf("read rows error: %w", err) - } - - secureValue, err := row.toDecrypt() + q, err := sqltemplate.Execute(sqlSecureValueUpdateExternalId, req) if err != nil { - return nil, fmt.Errorf("convert to kubernetes object: %w", err) - } - - s.metrics.SecureValueGetForDecryptDuration.Observe(time.Since(start).Seconds()) - - return secureValue, nil -} - -func (s *secureValueMetadataStorage) read(ctx context.Context, namespace xkube.Namespace, name string, opts contracts.ReadOpts) (secureValueDB, error) { - req := readSecureValue{ - SQLTemplate: sqltemplate.New(s.dialect), - Namespace: namespace.String(), - Name: name, - IsForUpdate: opts.ForUpdate, + return fmt.Errorf("execute template %q: %w", sqlSecureValueUpdateExternalId.Name(), err) } - query, err := sqltemplate.Execute(sqlSecureValueRead, req) + res, err := s.db.ExecContext(ctx, q, req.GetArgs()...) if err != nil { - return secureValueDB{}, fmt.Errorf("execute template %q: %w", sqlSecureValueRead.Name(), err) + return fmt.Errorf("setting secure value external id: namespace=%+v name=%+v externalID=%+v %w", namespace, name, externalID, err) } - res, err := s.db.QueryContext(ctx, query, req.GetArgs()...) + // validate modified cound + modifiedCount, err := res.RowsAffected() if err != nil { - return secureValueDB{}, fmt.Errorf("reading row: %w", err) - } - defer func() { _ = res.Close() }() - - var secureValue secureValueDB - if !res.Next() { - return secureValueDB{}, contracts.ErrSecureValueNotFound + return fmt.Errorf("getting updated rows update external id secure value: %w", err) } - - if err := res.Scan( - &secureValue.GUID, &secureValue.Name, &secureValue.Namespace, - &secureValue.Annotations, &secureValue.Labels, - &secureValue.Created, &secureValue.CreatedBy, - &secureValue.Updated, &secureValue.UpdatedBy, - &secureValue.Phase, &secureValue.Message, - &secureValue.Description, &secureValue.Keeper, &secureValue.Decrypters, &secureValue.Ref, &secureValue.ExternalID); err != nil { - return secureValueDB{}, fmt.Errorf("failed to scan secure value row: %w", err) + if modifiedCount > 1 { + return fmt.Errorf("secureValueMetadataStorage.SetExternalID: modified more than one secret, this is a bug, check the where condition: modifiedCount=%d", modifiedCount) } + s.metrics.SecureValueSetExternalIDDuration.Observe(time.Since(start).Seconds()) - if err := res.Err(); err != nil { - return secureValueDB{}, fmt.Errorf("read rows error: %w", err) - } - return secureValue, nil + return nil } diff --git a/pkg/storage/secret/metadata/secure_value_store_test.go b/pkg/storage/secret/metadata/secure_value_store_test.go index b9ec0023430..1de2dbf73f1 100644 --- a/pkg/storage/secret/metadata/secure_value_store_test.go +++ b/pkg/storage/secret/metadata/secure_value_store_test.go @@ -1,4 +1,4 @@ -package metadata +package metadata_test import ( "context" @@ -10,6 +10,7 @@ import ( "github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/sqlstore" "github.com/grafana/grafana/pkg/storage/secret/database" + "github.com/grafana/grafana/pkg/storage/secret/metadata" "github.com/grafana/grafana/pkg/storage/secret/migrator" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/trace/noop" @@ -43,11 +44,11 @@ func Test_SecureValueMetadataStorage_CreateAndRead(t *testing.T) { features := featuremgmt.WithFeatures(featuremgmt.FlagGrafanaAPIServerWithExperimentalAPIs, featuremgmt.FlagSecretsManagementAppPlatform) // Initialize the secure value storage - secureValueStorage, err := ProvideSecureValueMetadataStorage(db, tracer, features, nil) + secureValueStorage, err := metadata.ProvideSecureValueMetadataStorage(db, tracer, features, nil) require.NoError(t, err) // Initialize the keeper storage - keeperStorage, err := ProvideKeeperMetadataStorage(db, tracer, features, nil) + keeperStorage, err := metadata.ProvideKeeperMetadataStorage(db, tracer, features, nil) require.NoError(t, err) t.Run("create and read a secure value", func(t *testing.T) { @@ -73,7 +74,8 @@ func Test_SecureValueMetadataStorage_CreateAndRead(t *testing.T) { require.Equal(t, "default", createdSecureValue.Namespace) require.Equal(t, "test description", createdSecureValue.Spec.Description) require.Equal(t, keeperName, *createdSecureValue.Spec.Keeper) - require.Equal(t, secretv0alpha1.SecureValuePhasePending, createdSecureValue.Status.Phase) + + require.NoError(t, secureValueStorage.SetVersionToActive(ctx, xkube.Namespace(createdSecureValue.Namespace), createdSecureValue.Name, createdSecureValue.Status.Version)) // Read the secure value back readSecureValue, err := secureValueStorage.Read(ctx, xkube.Namespace("default"), "sv-test", contracts.ReadOpts{}) @@ -83,7 +85,6 @@ func Test_SecureValueMetadataStorage_CreateAndRead(t *testing.T) { require.Equal(t, "default", readSecureValue.Namespace) require.Equal(t, "test description", readSecureValue.Spec.Description) require.Equal(t, keeperName, *readSecureValue.Spec.Keeper) - require.Equal(t, secretv0alpha1.SecureValuePhasePending, readSecureValue.Status.Phase) // List secure values and verify our value is in the list secureValues, err := secureValueStorage.List(ctx, xkube.Namespace("default")) @@ -98,7 +99,6 @@ func Test_SecureValueMetadataStorage_CreateAndRead(t *testing.T) { require.Equal(t, "default", sv.Namespace) require.Equal(t, "test description", sv.Spec.Description) require.Equal(t, keeperName, *sv.Spec.Keeper) - require.Equal(t, secretv0alpha1.SecureValuePhasePending, sv.Status.Phase) break } } @@ -125,6 +125,8 @@ func Test_SecureValueMetadataStorage_CreateAndRead(t *testing.T) { require.NoError(t, err) require.NotNil(t, createdSecureValue) + require.NoError(t, secureValueStorage.SetVersionToActive(ctx, xkube.Namespace(createdSecureValue.Namespace), createdSecureValue.Name, createdSecureValue.Status.Version)) + // Read the secure value to verify it exists readSecureValue, err := secureValueStorage.Read(ctx, xkube.Namespace("default"), "sv-test-2", contracts.ReadOpts{}) require.NoError(t, err) @@ -132,7 +134,7 @@ func Test_SecureValueMetadataStorage_CreateAndRead(t *testing.T) { require.Equal(t, "sv-test-2", readSecureValue.Name) // Delete the secure value - err = secureValueStorage.Delete(ctx, xkube.Namespace("default"), "sv-test-2") + err = secureValueStorage.SetVersionToInactive(ctx, xkube.Namespace("default"), "sv-test-2", readSecureValue.Status.Version) require.NoError(t, err) // Try to read the deleted secure value - should return error diff --git a/pkg/storage/secret/metadata/testdata/mysql--secure_value_create-create-not-null.sql b/pkg/storage/secret/metadata/testdata/mysql--secure_value_create-create-not-null.sql index 8dea7db9fa8..aadea1d47a9 100755 --- a/pkg/storage/secret/metadata/testdata/mysql--secure_value_create-create-not-null.sql +++ b/pkg/storage/secret/metadata/testdata/mysql--secure_value_create-create-not-null.sql @@ -8,8 +8,8 @@ INSERT INTO `secret_secure_value` ( `created_by`, `updated`, `updated_by`, - `status_phase`, - `status_message`, + `active`, + `version`, `description`, `keeper`, `decrypters`, @@ -25,8 +25,8 @@ INSERT INTO `secret_secure_value` ( 'user:ryan', 5678, 'user:cameron', - 'creating', - 'message_test', + FALSE, + 1, 'description', 'keeper_test', 'decrypters_test', diff --git a/pkg/storage/secret/metadata/testdata/mysql--secure_value_create-create-null.sql b/pkg/storage/secret/metadata/testdata/mysql--secure_value_create-create-null.sql index fcaa4271d49..ff0875fc55c 100755 --- a/pkg/storage/secret/metadata/testdata/mysql--secure_value_create-create-null.sql +++ b/pkg/storage/secret/metadata/testdata/mysql--secure_value_create-create-null.sql @@ -8,7 +8,8 @@ INSERT INTO `secret_secure_value` ( `created_by`, `updated`, `updated_by`, - `status_phase`, + `active`, + `version`, `description`, `external_id` ) VALUES ( @@ -21,7 +22,8 @@ INSERT INTO `secret_secure_value` ( 'user:ryan', 5678, 'user:cameron', - 'creating', + FALSE, + 1, 'description', 'extId' ); diff --git a/pkg/storage/secret/metadata/testdata/mysql--secure_value_delete-delete.sql b/pkg/storage/secret/metadata/testdata/mysql--secure_value_delete-delete.sql deleted file mode 100755 index e8597c9fc8b..00000000000 --- a/pkg/storage/secret/metadata/testdata/mysql--secure_value_delete-delete.sql +++ /dev/null @@ -1,4 +0,0 @@ -DELETE FROM `secret_secure_value` -WHERE `namespace` = 'ns' AND - `name` = 'name' -; diff --git a/pkg/storage/secret/metadata/testdata/mysql--secure_value_get_latest_version-get latest secure value version.sql b/pkg/storage/secret/metadata/testdata/mysql--secure_value_get_latest_version-get latest secure value version.sql new file mode 100755 index 00000000000..8118fc81489 --- /dev/null +++ b/pkg/storage/secret/metadata/testdata/mysql--secure_value_get_latest_version-get latest secure value version.sql @@ -0,0 +1,10 @@ +SELECT + `version` +FROM + `secret_secure_value` +WHERE + `namespace` = 'ns' AND + `name` = 'name' +ORDER BY `version` DESC +LIMIT 1 +; diff --git a/pkg/storage/secret/metadata/testdata/mysql--secure_value_list-list.sql b/pkg/storage/secret/metadata/testdata/mysql--secure_value_list-list.sql index c47a02c16b2..d73828bfae8 100755 --- a/pkg/storage/secret/metadata/testdata/mysql--secure_value_list-list.sql +++ b/pkg/storage/secret/metadata/testdata/mysql--secure_value_list-list.sql @@ -8,15 +8,17 @@ SELECT `created_by`, `updated`, `updated_by`, - `status_phase`, - `status_message`, `description`, `keeper`, `decrypters`, `ref`, - `external_id` + `external_id`, + `version`, + `active` FROM `secret_secure_value` -WHERE `namespace` = 'ns' +WHERE + `namespace` = 'ns' AND + `active` = true ORDER BY `updated` DESC ; diff --git a/pkg/storage/secret/metadata/testdata/mysql--secure_value_listByName-list.sql b/pkg/storage/secret/metadata/testdata/mysql--secure_value_listByName-list.sql index 91ac79af6ae..91850979fdb 100755 --- a/pkg/storage/secret/metadata/testdata/mysql--secure_value_listByName-list.sql +++ b/pkg/storage/secret/metadata/testdata/mysql--secure_value_listByName-list.sql @@ -3,7 +3,9 @@ SELECT `keeper` FROM `secret_secure_value` -WHERE `namespace` = 'ns' AND - `name` IN ('a', 'b') +WHERE + `namespace` = 'ns' AND + `name` IN ('a', 'b') AND + `active` = true FOR UPDATE ; diff --git a/pkg/storage/secret/metadata/testdata/mysql--secure_value_outbox_append-all-fields-present.sql b/pkg/storage/secret/metadata/testdata/mysql--secure_value_outbox_append-all-fields-present.sql deleted file mode 100755 index a1cff11dd5d..00000000000 --- a/pkg/storage/secret/metadata/testdata/mysql--secure_value_outbox_append-all-fields-present.sql +++ /dev/null @@ -1,21 +0,0 @@ -INSERT INTO `secret_secure_value_outbox` ( - `request_id`, - `message_type`, - `name`, - `namespace`, - `encrypted_secret`, - `keeper_name`, - `external_id`, - `receive_count`, - `created` -) VALUES ( - '', - 'some-type', - 'name', - 'namespace', - 'encrypted', - 'keeper', - '', - 0, - 1234 -); diff --git a/pkg/storage/secret/metadata/testdata/mysql--secure_value_outbox_append-no-encrypted-secret.sql b/pkg/storage/secret/metadata/testdata/mysql--secure_value_outbox_append-no-encrypted-secret.sql deleted file mode 100755 index 139d262d49a..00000000000 --- a/pkg/storage/secret/metadata/testdata/mysql--secure_value_outbox_append-no-encrypted-secret.sql +++ /dev/null @@ -1,19 +0,0 @@ -INSERT INTO `secret_secure_value_outbox` ( - `request_id`, - `message_type`, - `name`, - `namespace`, - `keeper_name`, - `external_id`, - `receive_count`, - `created` -) VALUES ( - '', - 'some-type', - 'name', - 'namespace', - 'keeper', - 'external-id', - 0, - 1234 -); diff --git a/pkg/storage/secret/metadata/testdata/mysql--secure_value_outbox_append-no-external-id.sql b/pkg/storage/secret/metadata/testdata/mysql--secure_value_outbox_append-no-external-id.sql deleted file mode 100755 index 62af967a284..00000000000 --- a/pkg/storage/secret/metadata/testdata/mysql--secure_value_outbox_append-no-external-id.sql +++ /dev/null @@ -1,19 +0,0 @@ -INSERT INTO `secret_secure_value_outbox` ( - `request_id`, - `message_type`, - `name`, - `namespace`, - `encrypted_secret`, - `keeper_name`, - `receive_count`, - `created` -) VALUES ( - '', - 'some-type', - 'name', - 'namespace', - 'encrypted', - 'keeper', - 0, - 1234 -); diff --git a/pkg/storage/secret/metadata/testdata/mysql--secure_value_outbox_append-no-keeper-name.sql b/pkg/storage/secret/metadata/testdata/mysql--secure_value_outbox_append-no-keeper-name.sql deleted file mode 100755 index 924b7d6277f..00000000000 --- a/pkg/storage/secret/metadata/testdata/mysql--secure_value_outbox_append-no-keeper-name.sql +++ /dev/null @@ -1,19 +0,0 @@ -INSERT INTO `secret_secure_value_outbox` ( - `request_id`, - `message_type`, - `name`, - `namespace`, - `encrypted_secret`, - `external_id`, - `receive_count`, - `created` -) VALUES ( - '', - 'some-type', - 'name', - 'namespace', - 'encrypted', - 'external-id', - 0, - 1234 -); diff --git a/pkg/storage/secret/metadata/testdata/mysql--secure_value_outbox_delete-basic.sql b/pkg/storage/secret/metadata/testdata/mysql--secure_value_outbox_delete-basic.sql deleted file mode 100755 index 2a6fc52ea18..00000000000 --- a/pkg/storage/secret/metadata/testdata/mysql--secure_value_outbox_delete-basic.sql +++ /dev/null @@ -1,5 +0,0 @@ -DELETE FROM - `secret_secure_value_outbox` -WHERE - `id` = 1 -; diff --git a/pkg/storage/secret/metadata/testdata/mysql--secure_value_outbox_fetch_message_ids-basic.sql b/pkg/storage/secret/metadata/testdata/mysql--secure_value_outbox_fetch_message_ids-basic.sql deleted file mode 100755 index 47b006df9e3..00000000000 --- a/pkg/storage/secret/metadata/testdata/mysql--secure_value_outbox_fetch_message_ids-basic.sql +++ /dev/null @@ -1,6 +0,0 @@ -SELECT - `id` -FROM `secret_secure_value_outbox` -ORDER BY id ASC -LIMIT 10 -; diff --git a/pkg/storage/secret/metadata/testdata/mysql--secure_value_outbox_receiveN-basic.sql b/pkg/storage/secret/metadata/testdata/mysql--secure_value_outbox_receiveN-basic.sql deleted file mode 100755 index 710f96bf187..00000000000 --- a/pkg/storage/secret/metadata/testdata/mysql--secure_value_outbox_receiveN-basic.sql +++ /dev/null @@ -1,19 +0,0 @@ -SELECT - `request_id`, - `id`, - `message_type`, - `name`, - `namespace`, - `encrypted_secret`, - `keeper_name`, - `external_id`, - `receive_count`, - `created` -FROM - `secret_secure_value_outbox` -WHERE - `id` IN (1, 2, 3) -ORDER BY - `id` ASC -FOR UPDATE SKIP LOCKED -; diff --git a/pkg/storage/secret/metadata/testdata/mysql--secure_value_outbox_update_receive_count-update-receive-count.sql b/pkg/storage/secret/metadata/testdata/mysql--secure_value_outbox_update_receive_count-update-receive-count.sql deleted file mode 100755 index e9df2c03014..00000000000 --- a/pkg/storage/secret/metadata/testdata/mysql--secure_value_outbox_update_receive_count-update-receive-count.sql +++ /dev/null @@ -1,7 +0,0 @@ -UPDATE - `secret_secure_value_outbox` -SET - `receive_count` = `receive_count` + 1 -WHERE - `id` IN (1, 2, 3) -; diff --git a/pkg/storage/secret/metadata/testdata/mysql--secure_value_read-read-for-update.sql b/pkg/storage/secret/metadata/testdata/mysql--secure_value_read-read-for-update.sql index 8f433497d22..4d8525dd0a0 100755 --- a/pkg/storage/secret/metadata/testdata/mysql--secure_value_read-read-for-update.sql +++ b/pkg/storage/secret/metadata/testdata/mysql--secure_value_read-read-for-update.sql @@ -8,16 +8,18 @@ SELECT `created_by`, `updated`, `updated_by`, - `status_phase`, - `status_message`, `description`, `keeper`, `decrypters`, `ref`, - `external_id` + `external_id`, + `active`, + `version` FROM `secret_secure_value` -WHERE `namespace` = 'ns' AND - `name` = 'name' +WHERE + `namespace` = 'ns' AND + `name` = 'name' AND + `active` = true FOR UPDATE ; diff --git a/pkg/storage/secret/metadata/testdata/mysql--secure_value_read-read.sql b/pkg/storage/secret/metadata/testdata/mysql--secure_value_read-read.sql index b45713eb594..c42fd0037c5 100755 --- a/pkg/storage/secret/metadata/testdata/mysql--secure_value_read-read.sql +++ b/pkg/storage/secret/metadata/testdata/mysql--secure_value_read-read.sql @@ -8,15 +8,17 @@ SELECT `created_by`, `updated`, `updated_by`, - `status_phase`, - `status_message`, `description`, `keeper`, `decrypters`, `ref`, - `external_id` + `external_id`, + `active`, + `version` FROM `secret_secure_value` -WHERE `namespace` = 'ns' AND - `name` = 'name' +WHERE + `namespace` = 'ns' AND + `name` = 'name' AND + `active` = true ; diff --git a/pkg/storage/secret/metadata/testdata/mysql--secure_value_read_for_decrypt-read-for-decrypt.sql b/pkg/storage/secret/metadata/testdata/mysql--secure_value_read_for_decrypt-read-for-decrypt.sql index 2694f0376d8..9d9095cf1e7 100755 --- a/pkg/storage/secret/metadata/testdata/mysql--secure_value_read_for_decrypt-read-for-decrypt.sql +++ b/pkg/storage/secret/metadata/testdata/mysql--secure_value_read_for_decrypt-read-for-decrypt.sql @@ -2,9 +2,12 @@ SELECT `keeper`, `decrypters`, `ref`, - `external_id` + `external_id`, + `active` FROM `secret_secure_value` -WHERE `namespace` = 'ns' AND - `name` = 'name' +WHERE + `namespace` = 'ns' AND + `name` = 'name' AND + `active` = true ; diff --git a/pkg/storage/secret/metadata/testdata/mysql--secure_value_set_version_to_active-set secure value version to active.sql b/pkg/storage/secret/metadata/testdata/mysql--secure_value_set_version_to_active-set secure value version to active.sql new file mode 100755 index 00000000000..ce98578b8b5 --- /dev/null +++ b/pkg/storage/secret/metadata/testdata/mysql--secure_value_set_version_to_active-set secure value version to active.sql @@ -0,0 +1,8 @@ +UPDATE + `secret_secure_value` +SET + `active` = (`version` = 1) +WHERE + `namespace` = 'ns' AND + `name` = 'name' +; diff --git a/pkg/storage/secret/metadata/testdata/mysql--secure_value_update-update-not-null.sql b/pkg/storage/secret/metadata/testdata/mysql--secure_value_update-update-not-null.sql deleted file mode 100755 index 6b39e09d23f..00000000000 --- a/pkg/storage/secret/metadata/testdata/mysql--secure_value_update-update-not-null.sql +++ /dev/null @@ -1,22 +0,0 @@ -UPDATE - `secret_secure_value` -SET - `guid` = 'abc', - `name` = 'name', - `namespace` = 'ns', - `annotations` = '{"x":"XXXX"}', - `labels` = '{"a":"AAA", "b", "BBBB"}', - `created` = 1234, - `created_by` = 'user:ryan', - `updated` = 5678, - `updated_by` = 'user:cameron', - `status_phase` = 'creating', - `status_message` = 'message_test', - `description` = 'description', - `keeper` = 'keeper_test', - `decrypters` = 'decrypters_test', - `ref` = 'ref_test', - `external_id` = 'extId' -WHERE `namespace` = 'ns' AND - `name` = 'name' -; diff --git a/pkg/storage/secret/metadata/testdata/mysql--secure_value_update-update-null.sql b/pkg/storage/secret/metadata/testdata/mysql--secure_value_update-update-null.sql deleted file mode 100755 index 378a2934ec3..00000000000 --- a/pkg/storage/secret/metadata/testdata/mysql--secure_value_update-update-null.sql +++ /dev/null @@ -1,18 +0,0 @@ -UPDATE - `secret_secure_value` -SET - `guid` = 'abc', - `name` = 'name', - `namespace` = 'ns', - `annotations` = '{"x":"XXXX"}', - `labels` = '{"a":"AAA", "b", "BBBB"}', - `created` = 1234, - `created_by` = 'user:ryan', - `updated` = 5678, - `updated_by` = 'user:cameron', - `status_phase` = 'creating', - `description` = 'description', - `external_id` = 'extId' -WHERE `namespace` = 'ns' AND - `name` = 'name' -; diff --git a/pkg/storage/secret/metadata/testdata/mysql--secure_value_updateExternalId-updateExternalId.sql b/pkg/storage/secret/metadata/testdata/mysql--secure_value_updateExternalId-updateExternalId.sql index d6d7db45247..eb862fcb072 100755 --- a/pkg/storage/secret/metadata/testdata/mysql--secure_value_updateExternalId-updateExternalId.sql +++ b/pkg/storage/secret/metadata/testdata/mysql--secure_value_updateExternalId-updateExternalId.sql @@ -2,6 +2,8 @@ UPDATE `secret_secure_value` SET `external_id` = 'extId' -WHERE `namespace` = 'ns' AND - `name` = 'name' +WHERE + `namespace` = 'ns' AND + `name` = 'name' AND + `version` = 0 ; diff --git a/pkg/storage/secret/metadata/testdata/mysql--secure_value_updateStatus-updateStatus.sql b/pkg/storage/secret/metadata/testdata/mysql--secure_value_updateStatus-updateStatus.sql deleted file mode 100755 index 25815855c68..00000000000 --- a/pkg/storage/secret/metadata/testdata/mysql--secure_value_updateStatus-updateStatus.sql +++ /dev/null @@ -1,8 +0,0 @@ -UPDATE - `secret_secure_value` -SET - `status_phase` = 'Succeeded', - `status_message` = 'message-1' -WHERE `namespace` = 'ns' AND - `name` = 'name' -; diff --git a/pkg/storage/secret/metadata/testdata/postgres--secure_value_create-create-not-null.sql b/pkg/storage/secret/metadata/testdata/postgres--secure_value_create-create-not-null.sql index d9f191a9c63..cf43e0c130c 100755 --- a/pkg/storage/secret/metadata/testdata/postgres--secure_value_create-create-not-null.sql +++ b/pkg/storage/secret/metadata/testdata/postgres--secure_value_create-create-not-null.sql @@ -8,8 +8,8 @@ INSERT INTO "secret_secure_value" ( "created_by", "updated", "updated_by", - "status_phase", - "status_message", + "active", + "version", "description", "keeper", "decrypters", @@ -25,8 +25,8 @@ INSERT INTO "secret_secure_value" ( 'user:ryan', 5678, 'user:cameron', - 'creating', - 'message_test', + FALSE, + 1, 'description', 'keeper_test', 'decrypters_test', diff --git a/pkg/storage/secret/metadata/testdata/postgres--secure_value_create-create-null.sql b/pkg/storage/secret/metadata/testdata/postgres--secure_value_create-create-null.sql index 69dd74be229..564c5728f14 100755 --- a/pkg/storage/secret/metadata/testdata/postgres--secure_value_create-create-null.sql +++ b/pkg/storage/secret/metadata/testdata/postgres--secure_value_create-create-null.sql @@ -8,7 +8,8 @@ INSERT INTO "secret_secure_value" ( "created_by", "updated", "updated_by", - "status_phase", + "active", + "version", "description", "external_id" ) VALUES ( @@ -21,7 +22,8 @@ INSERT INTO "secret_secure_value" ( 'user:ryan', 5678, 'user:cameron', - 'creating', + FALSE, + 1, 'description', 'extId' ); diff --git a/pkg/storage/secret/metadata/testdata/postgres--secure_value_delete-delete.sql b/pkg/storage/secret/metadata/testdata/postgres--secure_value_delete-delete.sql deleted file mode 100755 index f2fbdc59f70..00000000000 --- a/pkg/storage/secret/metadata/testdata/postgres--secure_value_delete-delete.sql +++ /dev/null @@ -1,4 +0,0 @@ -DELETE FROM "secret_secure_value" -WHERE "namespace" = 'ns' AND - "name" = 'name' -; diff --git a/pkg/storage/secret/metadata/testdata/postgres--secure_value_get_latest_version-get latest secure value version.sql b/pkg/storage/secret/metadata/testdata/postgres--secure_value_get_latest_version-get latest secure value version.sql new file mode 100755 index 00000000000..1549114582d --- /dev/null +++ b/pkg/storage/secret/metadata/testdata/postgres--secure_value_get_latest_version-get latest secure value version.sql @@ -0,0 +1,10 @@ +SELECT + "version" +FROM + "secret_secure_value" +WHERE + "namespace" = 'ns' AND + "name" = 'name' +ORDER BY "version" DESC +LIMIT 1 +; diff --git a/pkg/storage/secret/metadata/testdata/postgres--secure_value_list-list.sql b/pkg/storage/secret/metadata/testdata/postgres--secure_value_list-list.sql index 681ee5708cd..40ee42ebcf7 100755 --- a/pkg/storage/secret/metadata/testdata/postgres--secure_value_list-list.sql +++ b/pkg/storage/secret/metadata/testdata/postgres--secure_value_list-list.sql @@ -8,15 +8,17 @@ SELECT "created_by", "updated", "updated_by", - "status_phase", - "status_message", "description", "keeper", "decrypters", "ref", - "external_id" + "external_id", + "version", + "active" FROM "secret_secure_value" -WHERE "namespace" = 'ns' +WHERE + "namespace" = 'ns' AND + "active" = true ORDER BY "updated" DESC ; diff --git a/pkg/storage/secret/metadata/testdata/postgres--secure_value_listByName-list.sql b/pkg/storage/secret/metadata/testdata/postgres--secure_value_listByName-list.sql index 93a449fa17a..d476e297129 100755 --- a/pkg/storage/secret/metadata/testdata/postgres--secure_value_listByName-list.sql +++ b/pkg/storage/secret/metadata/testdata/postgres--secure_value_listByName-list.sql @@ -3,7 +3,9 @@ SELECT "keeper" FROM "secret_secure_value" -WHERE "namespace" = 'ns' AND - "name" IN ('a', 'b') +WHERE + "namespace" = 'ns' AND + "name" IN ('a', 'b') AND + "active" = true FOR UPDATE ; diff --git a/pkg/storage/secret/metadata/testdata/postgres--secure_value_outbox_append-all-fields-present.sql b/pkg/storage/secret/metadata/testdata/postgres--secure_value_outbox_append-all-fields-present.sql deleted file mode 100755 index 3c2b2588c08..00000000000 --- a/pkg/storage/secret/metadata/testdata/postgres--secure_value_outbox_append-all-fields-present.sql +++ /dev/null @@ -1,21 +0,0 @@ -INSERT INTO "secret_secure_value_outbox" ( - "request_id", - "message_type", - "name", - "namespace", - "encrypted_secret", - "keeper_name", - "external_id", - "receive_count", - "created" -) VALUES ( - '', - 'some-type', - 'name', - 'namespace', - 'encrypted', - 'keeper', - '', - 0, - 1234 -); diff --git a/pkg/storage/secret/metadata/testdata/postgres--secure_value_outbox_append-no-encrypted-secret.sql b/pkg/storage/secret/metadata/testdata/postgres--secure_value_outbox_append-no-encrypted-secret.sql deleted file mode 100755 index bcecf30a749..00000000000 --- a/pkg/storage/secret/metadata/testdata/postgres--secure_value_outbox_append-no-encrypted-secret.sql +++ /dev/null @@ -1,19 +0,0 @@ -INSERT INTO "secret_secure_value_outbox" ( - "request_id", - "message_type", - "name", - "namespace", - "keeper_name", - "external_id", - "receive_count", - "created" -) VALUES ( - '', - 'some-type', - 'name', - 'namespace', - 'keeper', - 'external-id', - 0, - 1234 -); diff --git a/pkg/storage/secret/metadata/testdata/postgres--secure_value_outbox_append-no-external-id.sql b/pkg/storage/secret/metadata/testdata/postgres--secure_value_outbox_append-no-external-id.sql deleted file mode 100755 index 81eb522e3a8..00000000000 --- a/pkg/storage/secret/metadata/testdata/postgres--secure_value_outbox_append-no-external-id.sql +++ /dev/null @@ -1,19 +0,0 @@ -INSERT INTO "secret_secure_value_outbox" ( - "request_id", - "message_type", - "name", - "namespace", - "encrypted_secret", - "keeper_name", - "receive_count", - "created" -) VALUES ( - '', - 'some-type', - 'name', - 'namespace', - 'encrypted', - 'keeper', - 0, - 1234 -); diff --git a/pkg/storage/secret/metadata/testdata/postgres--secure_value_outbox_append-no-keeper-name.sql b/pkg/storage/secret/metadata/testdata/postgres--secure_value_outbox_append-no-keeper-name.sql deleted file mode 100755 index 3c0e3abf5e8..00000000000 --- a/pkg/storage/secret/metadata/testdata/postgres--secure_value_outbox_append-no-keeper-name.sql +++ /dev/null @@ -1,19 +0,0 @@ -INSERT INTO "secret_secure_value_outbox" ( - "request_id", - "message_type", - "name", - "namespace", - "encrypted_secret", - "external_id", - "receive_count", - "created" -) VALUES ( - '', - 'some-type', - 'name', - 'namespace', - 'encrypted', - 'external-id', - 0, - 1234 -); diff --git a/pkg/storage/secret/metadata/testdata/postgres--secure_value_outbox_delete-basic.sql b/pkg/storage/secret/metadata/testdata/postgres--secure_value_outbox_delete-basic.sql deleted file mode 100755 index f0c8984c8a0..00000000000 --- a/pkg/storage/secret/metadata/testdata/postgres--secure_value_outbox_delete-basic.sql +++ /dev/null @@ -1,5 +0,0 @@ -DELETE FROM - "secret_secure_value_outbox" -WHERE - "id" = 1 -; diff --git a/pkg/storage/secret/metadata/testdata/postgres--secure_value_outbox_fetch_message_ids-basic.sql b/pkg/storage/secret/metadata/testdata/postgres--secure_value_outbox_fetch_message_ids-basic.sql deleted file mode 100755 index 4c590706948..00000000000 --- a/pkg/storage/secret/metadata/testdata/postgres--secure_value_outbox_fetch_message_ids-basic.sql +++ /dev/null @@ -1,6 +0,0 @@ -SELECT - "id" -FROM "secret_secure_value_outbox" -ORDER BY id ASC -LIMIT 10 -; diff --git a/pkg/storage/secret/metadata/testdata/postgres--secure_value_outbox_receiveN-basic.sql b/pkg/storage/secret/metadata/testdata/postgres--secure_value_outbox_receiveN-basic.sql deleted file mode 100755 index f4602caba07..00000000000 --- a/pkg/storage/secret/metadata/testdata/postgres--secure_value_outbox_receiveN-basic.sql +++ /dev/null @@ -1,19 +0,0 @@ -SELECT - "request_id", - "id", - "message_type", - "name", - "namespace", - "encrypted_secret", - "keeper_name", - "external_id", - "receive_count", - "created" -FROM - "secret_secure_value_outbox" -WHERE - "id" IN (1, 2, 3) -ORDER BY - "id" ASC -FOR UPDATE SKIP LOCKED -; diff --git a/pkg/storage/secret/metadata/testdata/postgres--secure_value_outbox_update_receive_count-update-receive-count.sql b/pkg/storage/secret/metadata/testdata/postgres--secure_value_outbox_update_receive_count-update-receive-count.sql deleted file mode 100755 index d9404fd8212..00000000000 --- a/pkg/storage/secret/metadata/testdata/postgres--secure_value_outbox_update_receive_count-update-receive-count.sql +++ /dev/null @@ -1,7 +0,0 @@ -UPDATE - "secret_secure_value_outbox" -SET - "receive_count" = "receive_count" + 1 -WHERE - "id" IN (1, 2, 3) -; diff --git a/pkg/storage/secret/metadata/testdata/postgres--secure_value_read-read-for-update.sql b/pkg/storage/secret/metadata/testdata/postgres--secure_value_read-read-for-update.sql index 76ca4a8c155..cce38e6db7a 100755 --- a/pkg/storage/secret/metadata/testdata/postgres--secure_value_read-read-for-update.sql +++ b/pkg/storage/secret/metadata/testdata/postgres--secure_value_read-read-for-update.sql @@ -8,16 +8,18 @@ SELECT "created_by", "updated", "updated_by", - "status_phase", - "status_message", "description", "keeper", "decrypters", "ref", - "external_id" + "external_id", + "active", + "version" FROM "secret_secure_value" -WHERE "namespace" = 'ns' AND - "name" = 'name' +WHERE + "namespace" = 'ns' AND + "name" = 'name' AND + "active" = true FOR UPDATE ; diff --git a/pkg/storage/secret/metadata/testdata/postgres--secure_value_read-read.sql b/pkg/storage/secret/metadata/testdata/postgres--secure_value_read-read.sql index d7fbc77a21b..2d16c211a85 100755 --- a/pkg/storage/secret/metadata/testdata/postgres--secure_value_read-read.sql +++ b/pkg/storage/secret/metadata/testdata/postgres--secure_value_read-read.sql @@ -8,15 +8,17 @@ SELECT "created_by", "updated", "updated_by", - "status_phase", - "status_message", "description", "keeper", "decrypters", "ref", - "external_id" + "external_id", + "active", + "version" FROM "secret_secure_value" -WHERE "namespace" = 'ns' AND - "name" = 'name' +WHERE + "namespace" = 'ns' AND + "name" = 'name' AND + "active" = true ; diff --git a/pkg/storage/secret/metadata/testdata/postgres--secure_value_read_for_decrypt-read-for-decrypt.sql b/pkg/storage/secret/metadata/testdata/postgres--secure_value_read_for_decrypt-read-for-decrypt.sql index 999e79c2fa1..2a764e2677a 100755 --- a/pkg/storage/secret/metadata/testdata/postgres--secure_value_read_for_decrypt-read-for-decrypt.sql +++ b/pkg/storage/secret/metadata/testdata/postgres--secure_value_read_for_decrypt-read-for-decrypt.sql @@ -2,9 +2,12 @@ SELECT "keeper", "decrypters", "ref", - "external_id" + "external_id", + "active" FROM "secret_secure_value" -WHERE "namespace" = 'ns' AND - "name" = 'name' +WHERE + "namespace" = 'ns' AND + "name" = 'name' AND + "active" = true ; diff --git a/pkg/storage/secret/metadata/testdata/postgres--secure_value_set_version_to_active-set secure value version to active.sql b/pkg/storage/secret/metadata/testdata/postgres--secure_value_set_version_to_active-set secure value version to active.sql new file mode 100755 index 00000000000..d659f944431 --- /dev/null +++ b/pkg/storage/secret/metadata/testdata/postgres--secure_value_set_version_to_active-set secure value version to active.sql @@ -0,0 +1,8 @@ +UPDATE + "secret_secure_value" +SET + "active" = ("version" = 1) +WHERE + "namespace" = 'ns' AND + "name" = 'name' +; diff --git a/pkg/storage/secret/metadata/testdata/postgres--secure_value_update-update-not-null.sql b/pkg/storage/secret/metadata/testdata/postgres--secure_value_update-update-not-null.sql deleted file mode 100755 index 7371f13f6e5..00000000000 --- a/pkg/storage/secret/metadata/testdata/postgres--secure_value_update-update-not-null.sql +++ /dev/null @@ -1,22 +0,0 @@ -UPDATE - "secret_secure_value" -SET - "guid" = 'abc', - "name" = 'name', - "namespace" = 'ns', - "annotations" = '{"x":"XXXX"}', - "labels" = '{"a":"AAA", "b", "BBBB"}', - "created" = 1234, - "created_by" = 'user:ryan', - "updated" = 5678, - "updated_by" = 'user:cameron', - "status_phase" = 'creating', - "status_message" = 'message_test', - "description" = 'description', - "keeper" = 'keeper_test', - "decrypters" = 'decrypters_test', - "ref" = 'ref_test', - "external_id" = 'extId' -WHERE "namespace" = 'ns' AND - "name" = 'name' -; diff --git a/pkg/storage/secret/metadata/testdata/postgres--secure_value_update-update-null.sql b/pkg/storage/secret/metadata/testdata/postgres--secure_value_update-update-null.sql deleted file mode 100755 index 0524e525096..00000000000 --- a/pkg/storage/secret/metadata/testdata/postgres--secure_value_update-update-null.sql +++ /dev/null @@ -1,18 +0,0 @@ -UPDATE - "secret_secure_value" -SET - "guid" = 'abc', - "name" = 'name', - "namespace" = 'ns', - "annotations" = '{"x":"XXXX"}', - "labels" = '{"a":"AAA", "b", "BBBB"}', - "created" = 1234, - "created_by" = 'user:ryan', - "updated" = 5678, - "updated_by" = 'user:cameron', - "status_phase" = 'creating', - "description" = 'description', - "external_id" = 'extId' -WHERE "namespace" = 'ns' AND - "name" = 'name' -; diff --git a/pkg/storage/secret/metadata/testdata/postgres--secure_value_updateExternalId-updateExternalId.sql b/pkg/storage/secret/metadata/testdata/postgres--secure_value_updateExternalId-updateExternalId.sql index 3d9f474776e..29bedaa7afe 100755 --- a/pkg/storage/secret/metadata/testdata/postgres--secure_value_updateExternalId-updateExternalId.sql +++ b/pkg/storage/secret/metadata/testdata/postgres--secure_value_updateExternalId-updateExternalId.sql @@ -2,6 +2,8 @@ UPDATE "secret_secure_value" SET "external_id" = 'extId' -WHERE "namespace" = 'ns' AND - "name" = 'name' +WHERE + "namespace" = 'ns' AND + "name" = 'name' AND + "version" = 0 ; diff --git a/pkg/storage/secret/metadata/testdata/postgres--secure_value_updateStatus-updateStatus.sql b/pkg/storage/secret/metadata/testdata/postgres--secure_value_updateStatus-updateStatus.sql deleted file mode 100755 index c5cf29a5e7a..00000000000 --- a/pkg/storage/secret/metadata/testdata/postgres--secure_value_updateStatus-updateStatus.sql +++ /dev/null @@ -1,8 +0,0 @@ -UPDATE - "secret_secure_value" -SET - "status_phase" = 'Succeeded', - "status_message" = 'message-1' -WHERE "namespace" = 'ns' AND - "name" = 'name' -; diff --git a/pkg/storage/secret/metadata/testdata/sqlite--secure_value_create-create-not-null.sql b/pkg/storage/secret/metadata/testdata/sqlite--secure_value_create-create-not-null.sql index d9f191a9c63..cf43e0c130c 100755 --- a/pkg/storage/secret/metadata/testdata/sqlite--secure_value_create-create-not-null.sql +++ b/pkg/storage/secret/metadata/testdata/sqlite--secure_value_create-create-not-null.sql @@ -8,8 +8,8 @@ INSERT INTO "secret_secure_value" ( "created_by", "updated", "updated_by", - "status_phase", - "status_message", + "active", + "version", "description", "keeper", "decrypters", @@ -25,8 +25,8 @@ INSERT INTO "secret_secure_value" ( 'user:ryan', 5678, 'user:cameron', - 'creating', - 'message_test', + FALSE, + 1, 'description', 'keeper_test', 'decrypters_test', diff --git a/pkg/storage/secret/metadata/testdata/sqlite--secure_value_create-create-null.sql b/pkg/storage/secret/metadata/testdata/sqlite--secure_value_create-create-null.sql index 69dd74be229..564c5728f14 100755 --- a/pkg/storage/secret/metadata/testdata/sqlite--secure_value_create-create-null.sql +++ b/pkg/storage/secret/metadata/testdata/sqlite--secure_value_create-create-null.sql @@ -8,7 +8,8 @@ INSERT INTO "secret_secure_value" ( "created_by", "updated", "updated_by", - "status_phase", + "active", + "version", "description", "external_id" ) VALUES ( @@ -21,7 +22,8 @@ INSERT INTO "secret_secure_value" ( 'user:ryan', 5678, 'user:cameron', - 'creating', + FALSE, + 1, 'description', 'extId' ); diff --git a/pkg/storage/secret/metadata/testdata/sqlite--secure_value_delete-delete.sql b/pkg/storage/secret/metadata/testdata/sqlite--secure_value_delete-delete.sql deleted file mode 100755 index f2fbdc59f70..00000000000 --- a/pkg/storage/secret/metadata/testdata/sqlite--secure_value_delete-delete.sql +++ /dev/null @@ -1,4 +0,0 @@ -DELETE FROM "secret_secure_value" -WHERE "namespace" = 'ns' AND - "name" = 'name' -; diff --git a/pkg/storage/secret/metadata/testdata/sqlite--secure_value_get_latest_version-get latest secure value version.sql b/pkg/storage/secret/metadata/testdata/sqlite--secure_value_get_latest_version-get latest secure value version.sql new file mode 100755 index 00000000000..1549114582d --- /dev/null +++ b/pkg/storage/secret/metadata/testdata/sqlite--secure_value_get_latest_version-get latest secure value version.sql @@ -0,0 +1,10 @@ +SELECT + "version" +FROM + "secret_secure_value" +WHERE + "namespace" = 'ns' AND + "name" = 'name' +ORDER BY "version" DESC +LIMIT 1 +; diff --git a/pkg/storage/secret/metadata/testdata/sqlite--secure_value_list-list.sql b/pkg/storage/secret/metadata/testdata/sqlite--secure_value_list-list.sql index 681ee5708cd..40ee42ebcf7 100755 --- a/pkg/storage/secret/metadata/testdata/sqlite--secure_value_list-list.sql +++ b/pkg/storage/secret/metadata/testdata/sqlite--secure_value_list-list.sql @@ -8,15 +8,17 @@ SELECT "created_by", "updated", "updated_by", - "status_phase", - "status_message", "description", "keeper", "decrypters", "ref", - "external_id" + "external_id", + "version", + "active" FROM "secret_secure_value" -WHERE "namespace" = 'ns' +WHERE + "namespace" = 'ns' AND + "active" = true ORDER BY "updated" DESC ; diff --git a/pkg/storage/secret/metadata/testdata/sqlite--secure_value_listByName-list.sql b/pkg/storage/secret/metadata/testdata/sqlite--secure_value_listByName-list.sql index 48ae01800ae..22d2006de82 100755 --- a/pkg/storage/secret/metadata/testdata/sqlite--secure_value_listByName-list.sql +++ b/pkg/storage/secret/metadata/testdata/sqlite--secure_value_listByName-list.sql @@ -3,6 +3,8 @@ SELECT "keeper" FROM "secret_secure_value" -WHERE "namespace" = 'ns' AND - "name" IN ('a', 'b') +WHERE + "namespace" = 'ns' AND + "name" IN ('a', 'b') AND + "active" = true ; diff --git a/pkg/storage/secret/metadata/testdata/sqlite--secure_value_outbox_append-all-fields-present.sql b/pkg/storage/secret/metadata/testdata/sqlite--secure_value_outbox_append-all-fields-present.sql deleted file mode 100755 index 3c2b2588c08..00000000000 --- a/pkg/storage/secret/metadata/testdata/sqlite--secure_value_outbox_append-all-fields-present.sql +++ /dev/null @@ -1,21 +0,0 @@ -INSERT INTO "secret_secure_value_outbox" ( - "request_id", - "message_type", - "name", - "namespace", - "encrypted_secret", - "keeper_name", - "external_id", - "receive_count", - "created" -) VALUES ( - '', - 'some-type', - 'name', - 'namespace', - 'encrypted', - 'keeper', - '', - 0, - 1234 -); diff --git a/pkg/storage/secret/metadata/testdata/sqlite--secure_value_outbox_append-no-encrypted-secret.sql b/pkg/storage/secret/metadata/testdata/sqlite--secure_value_outbox_append-no-encrypted-secret.sql deleted file mode 100755 index bcecf30a749..00000000000 --- a/pkg/storage/secret/metadata/testdata/sqlite--secure_value_outbox_append-no-encrypted-secret.sql +++ /dev/null @@ -1,19 +0,0 @@ -INSERT INTO "secret_secure_value_outbox" ( - "request_id", - "message_type", - "name", - "namespace", - "keeper_name", - "external_id", - "receive_count", - "created" -) VALUES ( - '', - 'some-type', - 'name', - 'namespace', - 'keeper', - 'external-id', - 0, - 1234 -); diff --git a/pkg/storage/secret/metadata/testdata/sqlite--secure_value_outbox_append-no-external-id.sql b/pkg/storage/secret/metadata/testdata/sqlite--secure_value_outbox_append-no-external-id.sql deleted file mode 100755 index 81eb522e3a8..00000000000 --- a/pkg/storage/secret/metadata/testdata/sqlite--secure_value_outbox_append-no-external-id.sql +++ /dev/null @@ -1,19 +0,0 @@ -INSERT INTO "secret_secure_value_outbox" ( - "request_id", - "message_type", - "name", - "namespace", - "encrypted_secret", - "keeper_name", - "receive_count", - "created" -) VALUES ( - '', - 'some-type', - 'name', - 'namespace', - 'encrypted', - 'keeper', - 0, - 1234 -); diff --git a/pkg/storage/secret/metadata/testdata/sqlite--secure_value_outbox_append-no-keeper-name.sql b/pkg/storage/secret/metadata/testdata/sqlite--secure_value_outbox_append-no-keeper-name.sql deleted file mode 100755 index 3c0e3abf5e8..00000000000 --- a/pkg/storage/secret/metadata/testdata/sqlite--secure_value_outbox_append-no-keeper-name.sql +++ /dev/null @@ -1,19 +0,0 @@ -INSERT INTO "secret_secure_value_outbox" ( - "request_id", - "message_type", - "name", - "namespace", - "encrypted_secret", - "external_id", - "receive_count", - "created" -) VALUES ( - '', - 'some-type', - 'name', - 'namespace', - 'encrypted', - 'external-id', - 0, - 1234 -); diff --git a/pkg/storage/secret/metadata/testdata/sqlite--secure_value_outbox_delete-basic.sql b/pkg/storage/secret/metadata/testdata/sqlite--secure_value_outbox_delete-basic.sql deleted file mode 100755 index f0c8984c8a0..00000000000 --- a/pkg/storage/secret/metadata/testdata/sqlite--secure_value_outbox_delete-basic.sql +++ /dev/null @@ -1,5 +0,0 @@ -DELETE FROM - "secret_secure_value_outbox" -WHERE - "id" = 1 -; diff --git a/pkg/storage/secret/metadata/testdata/sqlite--secure_value_outbox_fetch_message_ids-basic.sql b/pkg/storage/secret/metadata/testdata/sqlite--secure_value_outbox_fetch_message_ids-basic.sql deleted file mode 100755 index 4c590706948..00000000000 --- a/pkg/storage/secret/metadata/testdata/sqlite--secure_value_outbox_fetch_message_ids-basic.sql +++ /dev/null @@ -1,6 +0,0 @@ -SELECT - "id" -FROM "secret_secure_value_outbox" -ORDER BY id ASC -LIMIT 10 -; diff --git a/pkg/storage/secret/metadata/testdata/sqlite--secure_value_outbox_receiveN-basic.sql b/pkg/storage/secret/metadata/testdata/sqlite--secure_value_outbox_receiveN-basic.sql deleted file mode 100755 index 62b16f507ba..00000000000 --- a/pkg/storage/secret/metadata/testdata/sqlite--secure_value_outbox_receiveN-basic.sql +++ /dev/null @@ -1,18 +0,0 @@ -SELECT - "request_id", - "id", - "message_type", - "name", - "namespace", - "encrypted_secret", - "keeper_name", - "external_id", - "receive_count", - "created" -FROM - "secret_secure_value_outbox" -WHERE - "id" IN (1, 2, 3) -ORDER BY - "id" ASC -; diff --git a/pkg/storage/secret/metadata/testdata/sqlite--secure_value_outbox_update_receive_count-update-receive-count.sql b/pkg/storage/secret/metadata/testdata/sqlite--secure_value_outbox_update_receive_count-update-receive-count.sql deleted file mode 100755 index d9404fd8212..00000000000 --- a/pkg/storage/secret/metadata/testdata/sqlite--secure_value_outbox_update_receive_count-update-receive-count.sql +++ /dev/null @@ -1,7 +0,0 @@ -UPDATE - "secret_secure_value_outbox" -SET - "receive_count" = "receive_count" + 1 -WHERE - "id" IN (1, 2, 3) -; diff --git a/pkg/storage/secret/metadata/testdata/sqlite--secure_value_read-read-for-update.sql b/pkg/storage/secret/metadata/testdata/sqlite--secure_value_read-read-for-update.sql index d7fbc77a21b..2d16c211a85 100755 --- a/pkg/storage/secret/metadata/testdata/sqlite--secure_value_read-read-for-update.sql +++ b/pkg/storage/secret/metadata/testdata/sqlite--secure_value_read-read-for-update.sql @@ -8,15 +8,17 @@ SELECT "created_by", "updated", "updated_by", - "status_phase", - "status_message", "description", "keeper", "decrypters", "ref", - "external_id" + "external_id", + "active", + "version" FROM "secret_secure_value" -WHERE "namespace" = 'ns' AND - "name" = 'name' +WHERE + "namespace" = 'ns' AND + "name" = 'name' AND + "active" = true ; diff --git a/pkg/storage/secret/metadata/testdata/sqlite--secure_value_read-read.sql b/pkg/storage/secret/metadata/testdata/sqlite--secure_value_read-read.sql index d7fbc77a21b..2d16c211a85 100755 --- a/pkg/storage/secret/metadata/testdata/sqlite--secure_value_read-read.sql +++ b/pkg/storage/secret/metadata/testdata/sqlite--secure_value_read-read.sql @@ -8,15 +8,17 @@ SELECT "created_by", "updated", "updated_by", - "status_phase", - "status_message", "description", "keeper", "decrypters", "ref", - "external_id" + "external_id", + "active", + "version" FROM "secret_secure_value" -WHERE "namespace" = 'ns' AND - "name" = 'name' +WHERE + "namespace" = 'ns' AND + "name" = 'name' AND + "active" = true ; diff --git a/pkg/storage/secret/metadata/testdata/sqlite--secure_value_read_for_decrypt-read-for-decrypt.sql b/pkg/storage/secret/metadata/testdata/sqlite--secure_value_read_for_decrypt-read-for-decrypt.sql index 999e79c2fa1..2a764e2677a 100755 --- a/pkg/storage/secret/metadata/testdata/sqlite--secure_value_read_for_decrypt-read-for-decrypt.sql +++ b/pkg/storage/secret/metadata/testdata/sqlite--secure_value_read_for_decrypt-read-for-decrypt.sql @@ -2,9 +2,12 @@ SELECT "keeper", "decrypters", "ref", - "external_id" + "external_id", + "active" FROM "secret_secure_value" -WHERE "namespace" = 'ns' AND - "name" = 'name' +WHERE + "namespace" = 'ns' AND + "name" = 'name' AND + "active" = true ; diff --git a/pkg/storage/secret/metadata/testdata/sqlite--secure_value_set_version_to_active-set secure value version to active.sql b/pkg/storage/secret/metadata/testdata/sqlite--secure_value_set_version_to_active-set secure value version to active.sql new file mode 100755 index 00000000000..d659f944431 --- /dev/null +++ b/pkg/storage/secret/metadata/testdata/sqlite--secure_value_set_version_to_active-set secure value version to active.sql @@ -0,0 +1,8 @@ +UPDATE + "secret_secure_value" +SET + "active" = ("version" = 1) +WHERE + "namespace" = 'ns' AND + "name" = 'name' +; diff --git a/pkg/storage/secret/metadata/testdata/sqlite--secure_value_update-update-not-null.sql b/pkg/storage/secret/metadata/testdata/sqlite--secure_value_update-update-not-null.sql deleted file mode 100755 index 7371f13f6e5..00000000000 --- a/pkg/storage/secret/metadata/testdata/sqlite--secure_value_update-update-not-null.sql +++ /dev/null @@ -1,22 +0,0 @@ -UPDATE - "secret_secure_value" -SET - "guid" = 'abc', - "name" = 'name', - "namespace" = 'ns', - "annotations" = '{"x":"XXXX"}', - "labels" = '{"a":"AAA", "b", "BBBB"}', - "created" = 1234, - "created_by" = 'user:ryan', - "updated" = 5678, - "updated_by" = 'user:cameron', - "status_phase" = 'creating', - "status_message" = 'message_test', - "description" = 'description', - "keeper" = 'keeper_test', - "decrypters" = 'decrypters_test', - "ref" = 'ref_test', - "external_id" = 'extId' -WHERE "namespace" = 'ns' AND - "name" = 'name' -; diff --git a/pkg/storage/secret/metadata/testdata/sqlite--secure_value_update-update-null.sql b/pkg/storage/secret/metadata/testdata/sqlite--secure_value_update-update-null.sql deleted file mode 100755 index 0524e525096..00000000000 --- a/pkg/storage/secret/metadata/testdata/sqlite--secure_value_update-update-null.sql +++ /dev/null @@ -1,18 +0,0 @@ -UPDATE - "secret_secure_value" -SET - "guid" = 'abc', - "name" = 'name', - "namespace" = 'ns', - "annotations" = '{"x":"XXXX"}', - "labels" = '{"a":"AAA", "b", "BBBB"}', - "created" = 1234, - "created_by" = 'user:ryan', - "updated" = 5678, - "updated_by" = 'user:cameron', - "status_phase" = 'creating', - "description" = 'description', - "external_id" = 'extId' -WHERE "namespace" = 'ns' AND - "name" = 'name' -; diff --git a/pkg/storage/secret/metadata/testdata/sqlite--secure_value_updateExternalId-updateExternalId.sql b/pkg/storage/secret/metadata/testdata/sqlite--secure_value_updateExternalId-updateExternalId.sql index 3d9f474776e..29bedaa7afe 100755 --- a/pkg/storage/secret/metadata/testdata/sqlite--secure_value_updateExternalId-updateExternalId.sql +++ b/pkg/storage/secret/metadata/testdata/sqlite--secure_value_updateExternalId-updateExternalId.sql @@ -2,6 +2,8 @@ UPDATE "secret_secure_value" SET "external_id" = 'extId' -WHERE "namespace" = 'ns' AND - "name" = 'name' +WHERE + "namespace" = 'ns' AND + "name" = 'name' AND + "version" = 0 ; diff --git a/pkg/storage/secret/metadata/testdata/sqlite--secure_value_updateStatus-updateStatus.sql b/pkg/storage/secret/metadata/testdata/sqlite--secure_value_updateStatus-updateStatus.sql deleted file mode 100755 index c5cf29a5e7a..00000000000 --- a/pkg/storage/secret/metadata/testdata/sqlite--secure_value_updateStatus-updateStatus.sql +++ /dev/null @@ -1,8 +0,0 @@ -UPDATE - "secret_secure_value" -SET - "status_phase" = 'Succeeded', - "status_message" = 'message-1' -WHERE "namespace" = 'ns' AND - "name" = 'name' -; diff --git a/pkg/storage/secret/migrator/migrator.go b/pkg/storage/secret/migrator/migrator.go index f453d6dd3af..6ee7209bc8a 100644 --- a/pkg/storage/secret/migrator/migrator.go +++ b/pkg/storage/secret/migrator/migrator.go @@ -12,11 +12,10 @@ import ( ) const ( - TableNameKeeper = "secret_keeper" - TableNameSecureValue = "secret_secure_value" - TableNameSecureValueOutbox = "secret_secure_value_outbox" - TableNameDataKey = "secret_data_key" - TableNameEncryptedValue = "secret_encrypted_value" + TableNameKeeper = "secret_keeper" + TableNameSecureValue = "secret_secure_value" + TableNameDataKey = "secret_data_key" + TableNameEncryptedValue = "secret_encrypted_value" ) type SecretDB struct { @@ -61,18 +60,19 @@ func (*SecretDB) AddMigration(mg *migrator.Migrator) { {Name: "updated_by", Type: migrator.DB_Text, Nullable: false}, // Kubernetes Status - {Name: "status_phase", Type: migrator.DB_Text, Nullable: false}, - {Name: "status_message", Type: migrator.DB_Text, Nullable: true}, + {Name: "external_id", Type: migrator.DB_Text, Nullable: false}, + {Name: "active", Type: migrator.DB_Bool, Nullable: false}, + {Name: "version", Type: migrator.DB_BigInt, Nullable: false}, // Spec {Name: "description", Type: migrator.DB_NVarchar, Length: 253, Nullable: false}, // Chosen arbitrarily, but should be enough. {Name: "keeper", Type: migrator.DB_NVarchar, Length: 253, Nullable: true}, // Keeper name, if not set, use default keeper. {Name: "decrypters", Type: migrator.DB_Text, Nullable: true}, {Name: "ref", Type: migrator.DB_NVarchar, Length: 1024, Nullable: true}, // Reference to third-party storage secret path.Chosen arbitrarily, but should be enough. - {Name: "external_id", Type: migrator.DB_Text, Nullable: false}, }, Indices: []*migrator.Index{ - {Cols: []string{"namespace", "name"}, Type: migrator.UniqueIndex}, + {Cols: []string{"namespace", "name", "version", "active"}, Type: migrator.UniqueIndex}, + {Cols: []string{"namespace", "name", "version"}, Type: migrator.UniqueIndex}, }, }) @@ -130,27 +130,6 @@ func (*SecretDB) AddMigration(mg *migrator.Migrator) { Indices: []*migrator.Index{}, // TODO: add indexes based on the queries we make. }) - tables = append(tables, migrator.Table{ - Name: TableNameSecureValueOutbox, - Columns: []*migrator.Column{ - {Name: "request_id", Type: migrator.DB_NVarchar, Length: 1024, Nullable: false}, // Safer upper limit because we hex-encode traceparent+tracestate to form the request_id. - {Name: "id", Type: migrator.DB_BigInt, Length: 36, IsPrimaryKey: true, IsAutoIncrement: true}, - {Name: "message_type", Type: migrator.DB_NVarchar, Length: 16, Nullable: false}, - {Name: "name", Type: migrator.DB_NVarchar, Length: 253, Nullable: false}, // Limit enforced by K8s. - {Name: "namespace", Type: migrator.DB_NVarchar, Length: 253, Nullable: false}, // Limit enforced by K8s. - {Name: "encrypted_secret", Type: migrator.DB_Blob, Nullable: true}, - {Name: "keeper_name", Type: migrator.DB_NVarchar, Length: 253, Nullable: true}, // Keeper name, if not set, use default keeper. - {Name: "external_id", Type: migrator.DB_NVarchar, Length: 36, Nullable: true}, // Fixed size of a UUID. - {Name: "receive_count", Type: migrator.DB_SmallInt, Nullable: false}, - {Name: "created", Type: migrator.DB_BigInt, Nullable: false}, - }, - Indices: []*migrator.Index{ - // There's only one operation per secret in the queue at all times, - // meaning the namespace + name combination should be unique - {Cols: []string{"namespace", "name"}, Type: migrator.UniqueIndex}, - }, - }) - // Initialize all tables for t := range tables { mg.AddMigration("drop table "+tables[t].Name, migrator.NewDropTableMigration(tables[t].Name))