Merge remote-tracking branch 'origin/main' into ds-apiserver-with-configs

This commit is contained in:
Ryan McKinley
2025-07-09 14:35:20 -07:00
1005 changed files with 5390 additions and 6095 deletions
+1 -1
View File
@@ -74,7 +74,7 @@ func (hs *HTTPServer) SetHomeDashboard(c *contextmodel.ReqContext) response.Resp
func (hs *HTTPServer) GetUserPreferences(c *contextmodel.ReqContext) response.Response {
userID, err := identity.UserIdentifier(c.GetID())
if err != nil {
return response.Error(http.StatusInternalServerError, "Failed to update user preferences", err)
return response.Error(http.StatusUnauthorized, "Not a valid identity", err)
}
return prefapi.GetPreferencesFor(c.Req.Context(), hs.DashboardService, hs.preferenceService, hs.Features, c.GetOrgID(), userID, 0)
+1 -53
View File
@@ -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
-209
View File
@@ -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=
-26
View File
@@ -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
}
+4 -27
View File
@@ -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"`
@@ -598,7 +598,7 @@ func schema_pkg_apis_secret_v0alpha1_SecureValue(ref common.ReferenceCallback) c
},
},
},
Required: []string{"spec"},
Required: []string{"spec", "status"},
},
},
Dependencies: []string{
@@ -734,20 +734,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": {
@@ -757,7 +748,7 @@ func schema_pkg_apis_secret_v0alpha1_SecureValueStatus(ref common.ReferenceCallb
},
},
},
Required: []string{"phase"},
Required: []string{"version"},
},
},
}
@@ -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
+53 -5
View File
@@ -1,4 +1,4 @@
// Code generated by mockery v2.10.6. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package filestorage
@@ -17,6 +17,10 @@ type MockFileStorage struct {
func (_m *MockFileStorage) CreateFolder(ctx context.Context, path string) error {
ret := _m.Called(ctx, path)
if len(ret) == 0 {
panic("no return value specified for CreateFolder")
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, string) error); ok {
r0 = rf(ctx, path)
@@ -31,6 +35,10 @@ func (_m *MockFileStorage) CreateFolder(ctx context.Context, path string) error
func (_m *MockFileStorage) Delete(ctx context.Context, path string) error {
ret := _m.Called(ctx, path)
if len(ret) == 0 {
panic("no return value specified for Delete")
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, string) error); ok {
r0 = rf(ctx, path)
@@ -45,6 +53,10 @@ func (_m *MockFileStorage) Delete(ctx context.Context, path string) error {
func (_m *MockFileStorage) DeleteFolder(ctx context.Context, path string, options *DeleteFolderOptions) error {
ret := _m.Called(ctx, path, options)
if len(ret) == 0 {
panic("no return value specified for DeleteFolder")
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, string, *DeleteFolderOptions) error); ok {
r0 = rf(ctx, path, options)
@@ -59,7 +71,16 @@ func (_m *MockFileStorage) DeleteFolder(ctx context.Context, path string, option
func (_m *MockFileStorage) Get(ctx context.Context, path string, options *GetFileOptions) (*File, bool, error) {
ret := _m.Called(ctx, path, options)
if len(ret) == 0 {
panic("no return value specified for Get")
}
var r0 *File
var r1 bool
var r2 error
if rf, ok := ret.Get(0).(func(context.Context, string, *GetFileOptions) (*File, bool, error)); ok {
return rf(ctx, path, options)
}
if rf, ok := ret.Get(0).(func(context.Context, string, *GetFileOptions) *File); ok {
r0 = rf(ctx, path, options)
} else {
@@ -68,14 +89,12 @@ func (_m *MockFileStorage) Get(ctx context.Context, path string, options *GetFil
}
}
var r1 bool
if rf, ok := ret.Get(1).(func(context.Context, string, *GetFileOptions) bool); ok {
r1 = rf(ctx, path, options)
} else {
r1 = ret.Get(1).(bool)
}
var r2 error
if rf, ok := ret.Get(2).(func(context.Context, string, *GetFileOptions) error); ok {
r2 = rf(ctx, path, options)
} else {
@@ -89,7 +108,15 @@ func (_m *MockFileStorage) Get(ctx context.Context, path string, options *GetFil
func (_m *MockFileStorage) List(ctx context.Context, folderPath string, paging *Paging, options *ListOptions) (*ListResponse, error) {
ret := _m.Called(ctx, folderPath, paging, options)
if len(ret) == 0 {
panic("no return value specified for List")
}
var r0 *ListResponse
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string, *Paging, *ListOptions) (*ListResponse, error)); ok {
return rf(ctx, folderPath, paging, options)
}
if rf, ok := ret.Get(0).(func(context.Context, string, *Paging, *ListOptions) *ListResponse); ok {
r0 = rf(ctx, folderPath, paging, options)
} else {
@@ -98,7 +125,6 @@ func (_m *MockFileStorage) List(ctx context.Context, folderPath string, paging *
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, string, *Paging, *ListOptions) error); ok {
r1 = rf(ctx, folderPath, paging, options)
} else {
@@ -112,6 +138,10 @@ func (_m *MockFileStorage) List(ctx context.Context, folderPath string, paging *
func (_m *MockFileStorage) Upsert(ctx context.Context, command *UpsertFileCommand) error {
ret := _m.Called(ctx, command)
if len(ret) == 0 {
panic("no return value specified for Upsert")
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, *UpsertFileCommand) error); ok {
r0 = rf(ctx, command)
@@ -122,10 +152,14 @@ func (_m *MockFileStorage) Upsert(ctx context.Context, command *UpsertFileComman
return r0
}
// close provides a mock function with given fields:
// close provides a mock function with no fields
func (_m *MockFileStorage) close() error {
ret := _m.Called()
if len(ret) == 0 {
panic("no return value specified for close")
}
var r0 error
if rf, ok := ret.Get(0).(func() error); ok {
r0 = rf()
@@ -135,3 +169,17 @@ func (_m *MockFileStorage) close() error {
return r0
}
// NewMockFileStorage creates a new instance of MockFileStorage. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
// The first argument is typically a *testing.T value.
func NewMockFileStorage(t interface {
mock.TestingT
Cleanup(func())
}) *MockFileStorage {
mock := &MockFileStorage{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}
+1 -1
View File
@@ -36,7 +36,7 @@ func TestIntegrationSocialService_ProvideService(t *testing.T) {
expectedGenericOAuthSkipOrgRoleSync bool
}{
{
name: "should load all social connectors when ssoSettingsApi is enabled",
name: "should load all social connectors",
expectedSocialMapLength: 7,
expectedGenericOAuthSkipOrgRoleSync: false,
},
@@ -1,4 +1,4 @@
// Code generated by mockery v2.27.1. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package socialtest
@@ -31,6 +31,10 @@ func (_m *MockSocialConnector) AuthCodeURL(state string, opts ...oauth2.AuthCode
_ca = append(_ca, _va...)
ret := _m.Called(_ca...)
if len(ret) == 0 {
panic("no return value specified for AuthCodeURL")
}
var r0 string
if rf, ok := ret.Get(0).(func(string, ...oauth2.AuthCodeOption) string); ok {
r0 = rf(state, opts...)
@@ -45,6 +49,10 @@ func (_m *MockSocialConnector) AuthCodeURL(state string, opts ...oauth2.AuthCode
func (_m *MockSocialConnector) Client(ctx context.Context, t *oauth2.Token) *http.Client {
ret := _m.Called(ctx, t)
if len(ret) == 0 {
panic("no return value specified for Client")
}
var r0 *http.Client
if rf, ok := ret.Get(0).(func(context.Context, *oauth2.Token) *http.Client); ok {
r0 = rf(ctx, t)
@@ -68,6 +76,10 @@ func (_m *MockSocialConnector) Exchange(ctx context.Context, code string, authOp
_ca = append(_ca, _va...)
ret := _m.Called(_ca...)
if len(ret) == 0 {
panic("no return value specified for Exchange")
}
var r0 *oauth2.Token
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string, ...oauth2.AuthCodeOption) (*oauth2.Token, error)); ok {
@@ -90,10 +102,14 @@ func (_m *MockSocialConnector) Exchange(ctx context.Context, code string, authOp
return r0, r1
}
// GetOAuthInfo provides a mock function with given fields:
// GetOAuthInfo provides a mock function with no fields
func (_m *MockSocialConnector) GetOAuthInfo() *social.OAuthInfo {
ret := _m.Called()
if len(ret) == 0 {
panic("no return value specified for GetOAuthInfo")
}
var r0 *social.OAuthInfo
if rf, ok := ret.Get(0).(func() *social.OAuthInfo); ok {
r0 = rf()
@@ -110,6 +126,10 @@ func (_m *MockSocialConnector) GetOAuthInfo() *social.OAuthInfo {
func (_m *MockSocialConnector) IsEmailAllowed(email string) bool {
ret := _m.Called(email)
if len(ret) == 0 {
panic("no return value specified for IsEmailAllowed")
}
var r0 bool
if rf, ok := ret.Get(0).(func(string) bool); ok {
r0 = rf(email)
@@ -120,10 +140,14 @@ func (_m *MockSocialConnector) IsEmailAllowed(email string) bool {
return r0
}
// IsSignupAllowed provides a mock function with given fields:
// IsSignupAllowed provides a mock function with no fields
func (_m *MockSocialConnector) IsSignupAllowed() bool {
ret := _m.Called()
if len(ret) == 0 {
panic("no return value specified for IsSignupAllowed")
}
var r0 bool
if rf, ok := ret.Get(0).(func() bool); ok {
r0 = rf()
@@ -138,6 +162,10 @@ func (_m *MockSocialConnector) IsSignupAllowed() bool {
func (_m *MockSocialConnector) SupportBundleContent(_a0 *bytes.Buffer) error {
ret := _m.Called(_a0)
if len(ret) == 0 {
panic("no return value specified for SupportBundleContent")
}
var r0 error
if rf, ok := ret.Get(0).(func(*bytes.Buffer) error); ok {
r0 = rf(_a0)
@@ -152,6 +180,10 @@ func (_m *MockSocialConnector) SupportBundleContent(_a0 *bytes.Buffer) error {
func (_m *MockSocialConnector) TokenSource(ctx context.Context, t *oauth2.Token) oauth2.TokenSource {
ret := _m.Called(ctx, t)
if len(ret) == 0 {
panic("no return value specified for TokenSource")
}
var r0 oauth2.TokenSource
if rf, ok := ret.Get(0).(func(context.Context, *oauth2.Token) oauth2.TokenSource); ok {
r0 = rf(ctx, t)
@@ -168,6 +200,10 @@ func (_m *MockSocialConnector) TokenSource(ctx context.Context, t *oauth2.Token)
func (_m *MockSocialConnector) UserInfo(ctx context.Context, client *http.Client, token *oauth2.Token) (*social.BasicUserInfo, error) {
ret := _m.Called(ctx, client, token)
if len(ret) == 0 {
panic("no return value specified for UserInfo")
}
var r0 *social.BasicUserInfo
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, *http.Client, *oauth2.Token) (*social.BasicUserInfo, error)); ok {
@@ -190,13 +226,12 @@ func (_m *MockSocialConnector) UserInfo(ctx context.Context, client *http.Client
return r0, r1
}
type mockConstructorTestingTNewMockSocialConnector interface {
// NewMockSocialConnector creates a new instance of MockSocialConnector. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
// The first argument is typically a *testing.T value.
func NewMockSocialConnector(t interface {
mock.TestingT
Cleanup(func())
}
// NewMockSocialConnector creates a new instance of MockSocialConnector. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewMockSocialConnector(t mockConstructorTestingTNewMockSocialConnector) *MockSocialConnector {
}) *MockSocialConnector {
mock := &MockSocialConnector{}
mock.Mock.Test(t)
@@ -46,10 +46,6 @@ func DefaultService(cfg *config.PluginManagementCfg) *Service {
// Base returns the base path for the specified plugin.
func (s *Service) Base(n PluginInfo) (string, error) {
if n.class == plugins.ClassCore {
baseDir := getBaseDir(n.fs.Base())
return path.Join("public/app/plugins", string(n.pluginJSON.Type), baseDir), nil
}
if n.class == plugins.ClassCDN {
return n.fs.Base(), nil
}
@@ -64,7 +60,6 @@ func (s *Service) Base(n PluginInfo) (string, error) {
if s.cdn.PluginSupported(n.parent.pluginJSON.ID) {
return s.cdn.AssetURL(n.parent.pluginJSON.ID, n.parent.pluginJSON.Info.Version, relPath)
}
return path.Join("public/plugins", n.parent.pluginJSON.ID, relPath), nil
}
return path.Join("public/plugins", n.pluginJSON.ID), nil
@@ -73,32 +68,12 @@ func (s *Service) Base(n PluginInfo) (string, error) {
// Module returns the module.js path for the specified plugin.
func (s *Service) Module(n PluginInfo) (string, error) {
if n.class == plugins.ClassCore {
if filepath.Base(n.fs.Base()) == "dist" {
// The core plugin has been built externally, use the module from the dist folder
} else {
baseDir := getBaseDir(n.fs.Base())
return path.Join("core:plugin", baseDir), nil
if filepath.Base(n.fs.Base()) != "dist" {
return path.Join("core:plugin", filepath.Base(n.fs.Base())), nil
}
}
if n.class == plugins.ClassCDN {
return pluginscdn.JoinPath(n.fs.Base(), "module.js")
}
if s.cdn.PluginSupported(n.pluginJSON.ID) {
return s.cdn.AssetURL(n.pluginJSON.ID, n.pluginJSON.Info.Version, "module.js")
}
if n.parent != nil {
relPath, err := n.parent.fs.Rel(n.fs.Base())
if err != nil {
return "", err
}
if s.cdn.PluginSupported(n.parent.pluginJSON.ID) {
return s.cdn.AssetURL(n.parent.pluginJSON.ID, n.parent.pluginJSON.Info.Version, path.Join(relPath, "module.js"))
}
return path.Join("public/plugins", n.parent.pluginJSON.ID, relPath, "module.js"), nil
}
return path.Join("public/plugins", n.pluginJSON.ID, "module.js"), nil
return s.RelativeURL(n, "module.js")
}
// RelativeURL returns the relative URL for an arbitrary plugin asset.
@@ -145,15 +120,6 @@ func (s *Service) DefaultLogoPath(pluginType plugins.Type) string {
return path.Join("public/img", fmt.Sprintf("icn-%s.svg", string(pluginType)))
}
func getBaseDir(pluginDir string) string {
baseDir := filepath.Base(pluginDir)
// Decoupled core plugins will be suffixed with "dist" if they have been built
if baseDir == "dist" {
return filepath.Base(strings.TrimSuffix(pluginDir, baseDir))
}
return baseDir
}
func (s *Service) GetTranslations(n PluginInfo) (map[string]string, error) {
pathToTranslations, err := s.RelativeURL(n, "locales")
if err != nil {
@@ -78,7 +78,7 @@ func TestService(t *testing.T) {
base, err = svc.Base(NewPluginInfo(jsonData["table-old"], plugins.ClassCore, tableOldFS, nil))
require.NoError(t, err)
require.Equal(t, "public/app/plugins/table-old", base)
require.Equal(t, "public/plugins/table-old", base)
parentFS := pluginFS(oneCDNURL)
parentFS.RelFunc = func(_ string) (string, error) {
@@ -243,9 +243,9 @@ func TestService_ChildPlugins(t *testing.T) {
return childInfo
},
expected: expected{
module: "public/plugins/parent/child/module.js",
baseURL: "public/plugins/parent/child",
relURL: "public/plugins/parent/child/path/to/file.txt",
module: "public/plugins/child/module.js",
baseURL: "public/plugins/child",
relURL: "public/plugins/child/path/to/file.txt",
},
},
{
@@ -256,8 +256,8 @@ func TestService_ChildPlugins(t *testing.T) {
},
expected: expected{
module: "core:plugin/parent",
baseURL: "public/app/plugins/parent",
relURL: "public/app/plugins/parent/path/to/file.txt",
baseURL: "public/plugins/parent",
relURL: "public/plugins/parent/path/to/file.txt",
},
},
{
@@ -268,8 +268,8 @@ func TestService_ChildPlugins(t *testing.T) {
},
expected: expected{
module: "public/plugins/parent/module.js",
baseURL: "public/app/plugins/parent",
relURL: "public/app/plugins/parent/path/to/file.txt",
baseURL: "public/plugins/parent",
relURL: "public/plugins/parent/path/to/file.txt",
},
},
{
+3 -3
View File
@@ -85,8 +85,8 @@ func TestLoader_Load(t *testing.T) {
Description: "Data source for Amazon AWS monitoring service",
Keywords: []string{"aws", "amazon"},
Logos: plugins.Logos{
Small: "public/app/plugins/datasource/cloudwatch/img/amazon-web-services.png",
Large: "public/app/plugins/datasource/cloudwatch/img/amazon-web-services.png",
Small: "public/plugins/cloudwatch/img/amazon-web-services.png",
Large: "public/plugins/cloudwatch/img/amazon-web-services.png",
},
Links: []plugins.InfoLink{
{Name: "Raise issue", URL: "https://github.com/grafana/grafana/issues/new"},
@@ -123,7 +123,7 @@ func TestLoader_Load(t *testing.T) {
QueryOptions: map[string]bool{"minInterval": true},
},
Module: "core:plugin/cloudwatch",
BaseURL: "public/app/plugins/datasource/cloudwatch",
BaseURL: "public/plugins/cloudwatch",
FS: mustNewStaticFSForTests(t, filepath.Join(corePluginDir, "app/plugins/datasource/cloudwatch")),
Signature: plugins.SignatureStatusInternal,
Class: plugins.ClassCore,
@@ -1,12 +1,11 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package legacy
import (
context "context"
"github.com/grafana/grafana/pkg/storage/unified/resourcepb"
resourcepb "github.com/grafana/grafana/pkg/storage/unified/resourcepb"
mock "github.com/stretchr/testify/mock"
)
+1 -1
View File
@@ -236,7 +236,7 @@ func (b *FolderAPIBuilder) Mutate(ctx context.Context, a admission.Attributes, _
if !ok {
return fmt.Errorf("obj is not folders.Folder")
}
f.Spec.Title = strings.Trim(f.Spec.Title, "")
f.Spec.Title = strings.Trim(f.Spec.Title, " ")
return nil
}
return nil
+14 -4
View File
@@ -479,7 +479,7 @@ func TestFolderAPIBuilder_Mutate_Create(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := b.Validate(context.Background(), admission.NewAttributesRecord(
admAttr := admission.NewAttributesRecord(
tt.input,
nil,
folders.SchemeGroupVersion.WithKind("folder"),
@@ -491,13 +491,18 @@ func TestFolderAPIBuilder_Mutate_Create(t *testing.T) {
nil,
true,
&user.SignedInUser{},
), nil)
)
err := b.Validate(context.Background(), admAttr, nil)
if tt.wantErr {
require.Error(t, err)
return
}
require.NoError(t, err)
err = b.Mutate(context.Background(), admAttr, nil)
require.NoError(t, err)
require.Equal(t, tt.input, tt.expected)
})
}
}
@@ -585,7 +590,7 @@ func TestFolderAPIBuilder_Mutate_Update(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := b.Validate(context.Background(), admission.NewAttributesRecord(
admAttr := admission.NewAttributesRecord(
tt.input,
existingObj,
folders.SchemeGroupVersion.WithKind("folder"),
@@ -597,13 +602,18 @@ func TestFolderAPIBuilder_Mutate_Update(t *testing.T) {
nil,
true,
&user.SignedInUser{},
), nil)
)
err := b.Validate(context.Background(), admAttr, nil)
if tt.wantErr {
require.Error(t, err)
return
}
require.NoError(t, err)
err = b.Mutate(context.Background(), admAttr, nil)
require.NoError(t, err)
require.Equal(t, tt.input, tt.expected)
})
}
}
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package export
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package export
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package jobs
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package jobs
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package migrate
@@ -9,7 +9,7 @@ import (
mock "github.com/stretchr/testify/mock"
"github.com/grafana/grafana/pkg/storage/unified/resourcepb"
resourcepb "github.com/grafana/grafana/pkg/storage/unified/resourcepb"
)
// MockBulkStoreClient is an autogenerated mock type for the BulkStoreClient type
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package migrate
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package migrate
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package jobs
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package jobs
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package jobs
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package jobs
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package sync
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package sync
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package sync
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package sync
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package sync
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package jobs
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package repository
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package repository
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package repository
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package repository
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package repository
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package github
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package github
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package github
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package repository
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package gogit
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package gogit
@@ -595,7 +595,7 @@ func (r *gitRepository) resolveRefToHash(ctx context.Context, ref string) (hash.
// Try to parse ref as a hash first
refHash, err := hash.FromHex(ref)
if err == nil && refHash != nil {
if err == nil && refHash != hash.Zero {
// Valid hash, return it
return refHash, nil
}
@@ -604,9 +604,9 @@ func (r *gitRepository) resolveRefToHash(ctx context.Context, ref string) (hash.
branchRef, err := r.client.GetRef(ctx, ref)
if err != nil {
if errors.Is(err, nanogit.ErrObjectNotFound) {
return nil, fmt.Errorf("ref not found: %s: %w", ref, repository.ErrRefNotFound)
return hash.Zero, fmt.Errorf("ref not found: %s: %w", ref, repository.ErrRefNotFound)
}
return nil, fmt.Errorf("get ref %s: %w", ref, err)
return hash.Zero, fmt.Errorf("get ref %s: %w", ref, err)
}
return branchRef.Hash, nil
@@ -695,7 +695,7 @@ func TestGitRepository_Read(t *testing.T) {
Hash: hash.Hash{},
}, nil)
mockClient.GetCommitReturns(&nanogit.Commit{
Tree: hash.Hash([]byte("tree-hash")),
Tree: hash.MustFromHex("abcdef1234567890abcdef1234567890abcdef12"),
}, nil)
mockClient.GetTreeByPathReturns(&nanogit.Tree{
Hash: hash.Hash{},
@@ -1191,7 +1191,7 @@ func TestGitRepository_LatestRef(t *testing.T) {
setupMock: func(mockClient *mocks.FakeClient) {
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3}, // Non-empty hash
Hash: hash.Hash{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}, // Non-empty hash
}, nil)
},
gitConfig: RepositoryConfig{
@@ -1412,11 +1412,11 @@ func TestGitRepository_CompareFiles(t *testing.T) {
// Return refs for base and ref
mockClient.GetRefReturnsOnCall(0, nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.Hash{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
}, nil)
mockClient.GetRefReturnsOnCall(1, nanogit.Ref{
Name: "refs/heads/feature",
Hash: hash.Hash{4, 5, 6},
Hash: hash.Hash{4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23},
}, nil)
// Return comparison results
@@ -1449,11 +1449,11 @@ func TestGitRepository_CompareFiles(t *testing.T) {
setupMock: func(mockClient *mocks.FakeClient) {
mockClient.GetRefReturnsOnCall(0, nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.Hash{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
}, nil)
mockClient.GetRefReturnsOnCall(1, nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.Hash{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
}, nil)
mockClient.CompareCommitsReturns([]nanogit.CommitFile{}, nil)
@@ -1547,7 +1547,7 @@ func TestGitRepository_ensureBranchExists(t *testing.T) {
setupMock: func(mockClient *mocks.FakeClient) {
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/feature",
Hash: hash.Hash{1, 2, 3},
Hash: hash.Hash{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
}, nil)
},
gitConfig: RepositoryConfig{
@@ -1565,7 +1565,7 @@ func TestGitRepository_ensureBranchExists(t *testing.T) {
// Second call - get source branch
mockClient.GetRefReturnsOnCall(1, nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.Hash{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
}, nil)
// CreateRef succeeds
mockClient.CreateRefReturns(nil)
@@ -1862,7 +1862,7 @@ func TestGitRepository_resolveRefToHash(t *testing.T) {
setupMock: func(mockClient *mocks.FakeClient) {
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.Hash{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
}, nil)
},
gitConfig: RepositoryConfig{
@@ -1887,7 +1887,7 @@ func TestGitRepository_resolveRefToHash(t *testing.T) {
setupMock: func(mockClient *mocks.FakeClient) {
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/feature",
Hash: hash.Hash{4, 5, 6},
Hash: hash.Hash{4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23},
}, nil)
},
gitConfig: RepositoryConfig{
@@ -1939,7 +1939,7 @@ func TestGitRepository_resolveRefToHash(t *testing.T) {
if tt.wantError {
require.Error(t, err)
require.Nil(t, refHash)
require.Equal(t, hash.Zero, refHash)
} else {
require.NoError(t, err)
require.NotNil(t, refHash)
@@ -2212,7 +2212,7 @@ func TestGitRepository_EdgeCases(t *testing.T) {
mockClient := &mocks.FakeClient{}
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.Hash{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
}, nil)
mockWriter := &mocks.FakeStagedWriter{}
@@ -2251,7 +2251,7 @@ func TestGitRepository_EdgeCases(t *testing.T) {
mockClient := &mocks.FakeClient{}
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.Hash{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
}, nil)
mockClient.GetCommitReturns(&nanogit.Commit{Tree: hash.Hash{}}, nil)
mockClient.GetBlobByPathReturns(&nanogit.Blob{}, errors.New("some read error"))
@@ -2401,7 +2401,7 @@ func TestGitRepository_ResolveRefToHash_EdgeCases(t *testing.T) {
setupMock: func(mockClient *mocks.FakeClient) {
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/invalid-hex",
Hash: hash.Hash{1, 2, 3},
Hash: hash.Hash{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
}, nil)
},
ref: "invalid-hex-zzz",
@@ -2412,7 +2412,7 @@ func TestGitRepository_ResolveRefToHash_EdgeCases(t *testing.T) {
setupMock: func(mockClient *mocks.FakeClient) {
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/feature",
Hash: hash.Hash{4, 5, 6},
Hash: hash.Hash{4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23},
}, nil)
},
ref: "refs/heads/feature",
@@ -2423,7 +2423,7 @@ func TestGitRepository_ResolveRefToHash_EdgeCases(t *testing.T) {
setupMock: func(mockClient *mocks.FakeClient) {
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/tags/v1.0.0",
Hash: hash.Hash{7, 8, 9},
Hash: hash.Hash{7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26},
}, nil)
},
ref: "refs/tags/v1.0.0",
@@ -2540,11 +2540,11 @@ func TestGitRepository_CompareFiles_EdgeCases(t *testing.T) {
setupMock: func(mockClient *mocks.FakeClient) {
mockClient.GetRefReturnsOnCall(0, nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.Hash{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
}, nil)
mockClient.GetRefReturnsOnCall(1, nanogit.Ref{
Name: "refs/heads/feature",
Hash: hash.Hash{4, 5, 6},
Hash: hash.Hash{4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23},
}, nil)
mockClient.CompareCommitsReturns(nil, errors.New("compare error"))
},
@@ -2558,11 +2558,11 @@ func TestGitRepository_CompareFiles_EdgeCases(t *testing.T) {
setupMock: func(mockClient *mocks.FakeClient) {
mockClient.GetRefReturnsOnCall(0, nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.Hash{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
}, nil)
mockClient.GetRefReturnsOnCall(1, nanogit.Ref{
Name: "refs/heads/feature",
Hash: hash.Hash{4, 5, 6},
Hash: hash.Hash{4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23},
}, nil)
mockClient.CompareCommitsReturns([]nanogit.CommitFile{
{
@@ -2580,11 +2580,11 @@ func TestGitRepository_CompareFiles_EdgeCases(t *testing.T) {
setupMock: func(mockClient *mocks.FakeClient) {
mockClient.GetRefReturnsOnCall(0, nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.Hash{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
}, nil)
mockClient.GetRefReturnsOnCall(1, nanogit.Ref{
Name: "refs/heads/feature",
Hash: hash.Hash{4, 5, 6},
Hash: hash.Hash{4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23},
}, nil)
mockClient.CompareCommitsReturns([]nanogit.CommitFile{
{
@@ -2606,11 +2606,11 @@ func TestGitRepository_CompareFiles_EdgeCases(t *testing.T) {
setupMock: func(mockClient *mocks.FakeClient) {
mockClient.GetRefReturnsOnCall(0, nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.Hash{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
}, nil)
mockClient.GetRefReturnsOnCall(1, nanogit.Ref{
Name: "refs/heads/feature",
Hash: hash.Hash{4, 5, 6},
Hash: hash.Hash{4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23},
}, nil)
mockClient.CompareCommitsReturns([]nanogit.CommitFile{
{
@@ -2683,7 +2683,7 @@ func TestGitRepository_ReadTree_EdgeCases(t *testing.T) {
setupMock: func(mockClient *mocks.FakeClient) {
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.Hash{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
}, nil)
mockClient.GetFlatTreeReturns(nil, errors.New("flat tree error"))
},
@@ -2694,23 +2694,23 @@ func TestGitRepository_ReadTree_EdgeCases(t *testing.T) {
setupMock: func(mockClient *mocks.FakeClient) {
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.Hash{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
}, nil)
mockClient.GetFlatTreeReturns(&nanogit.FlatTree{
Entries: []nanogit.FlatTreeEntry{
{
Path: "other/file.yaml", // Outside configs/
Hash: hash.Hash{4, 5, 6},
Hash: hash.Hash{4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23},
Type: protocol.ObjectTypeBlob,
},
{
Path: "configs/included.yaml", // Inside configs/
Hash: hash.Hash{7, 8, 9},
Hash: hash.Hash{7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26},
Type: protocol.ObjectTypeBlob,
},
{
Path: "configs/dir", // Directory without trailing slash
Hash: hash.Hash{10, 11, 12},
Hash: hash.Hash{10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29},
Type: protocol.ObjectTypeTree,
},
},
@@ -2828,7 +2828,7 @@ func TestGitRepository_ensureBranchExists_ErrorConditions(t *testing.T) {
// Second call - get source branch
mockClient.GetRefReturnsOnCall(1, nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"),
}, nil)
// CreateRef fails
mockClient.CreateRefReturns(errors.New("create ref failed"))
@@ -2880,10 +2880,10 @@ func TestGitRepository_Read_EdgeCases(t *testing.T) {
setupMock: func(mockClient *mocks.FakeClient) {
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121315"),
}, nil)
mockClient.GetCommitReturns(&nanogit.Commit{
Tree: hash.Hash([]byte("tree-hash")),
Tree: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"),
}, nil)
mockClient.GetTreeByPathReturns(nil, errors.New("tree error"))
},
@@ -2895,7 +2895,7 @@ func TestGitRepository_Read_EdgeCases(t *testing.T) {
setupMock: func(mockClient *mocks.FakeClient) {
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"),
}, nil)
mockClient.GetCommitReturns(nil, errors.New("commit error"))
},
@@ -2907,10 +2907,10 @@ func TestGitRepository_Read_EdgeCases(t *testing.T) {
setupMock: func(mockClient *mocks.FakeClient) {
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"),
}, nil)
mockClient.GetCommitReturns(&nanogit.Commit{
Tree: hash.Hash{4, 5, 6},
Hash: hash.MustFromHex("0102030405060708092a0b0c0d0e0f1011121314"),
}, nil)
mockClient.GetBlobByPathReturns(nil, errors.New("blob error"))
},
@@ -2965,7 +2965,7 @@ func TestGitRepository_Create_ErrorConditions(t *testing.T) {
setupMock: func(mockClient *mocks.FakeClient) {
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.Hash{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
}, nil)
mockClient.NewStagedWriterReturns(nil, errors.New("staged writer error"))
},
@@ -2977,7 +2977,7 @@ func TestGitRepository_Create_ErrorConditions(t *testing.T) {
setupMock: func(mockClient *mocks.FakeClient) {
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"),
}, nil)
mockWriter := &mocks.FakeStagedWriter{}
mockWriter.CreateBlobReturns(hash.Hash{}, errors.New("create blob error"))
@@ -3030,7 +3030,7 @@ func TestGitRepository_Update_ErrorConditions(t *testing.T) {
setupMock: func(mockClient *mocks.FakeClient) {
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.Hash{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20},
}, nil)
mockClient.NewStagedWriterReturns(nil, errors.New("staged writer error"))
},
@@ -3042,7 +3042,7 @@ func TestGitRepository_Update_ErrorConditions(t *testing.T) {
setupMock: func(mockClient *mocks.FakeClient) {
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"),
}, nil)
mockWriter := &mocks.FakeStagedWriter{}
mockWriter.UpdateBlobReturns(hash.Hash{}, errors.New("update blob error"))
@@ -3096,7 +3096,7 @@ func TestGitRepository_Delete_ErrorConditions(t *testing.T) {
setupMock: func(mockClient *mocks.FakeClient) {
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"),
}, nil)
mockClient.NewStagedWriterReturns(nil, errors.New("staged writer error"))
},
@@ -3109,7 +3109,7 @@ func TestGitRepository_Delete_ErrorConditions(t *testing.T) {
setupMock: func(mockClient *mocks.FakeClient) {
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"),
}, nil)
mockWriter := &mocks.FakeStagedWriter{}
mockWriter.DeleteBlobReturns(hash.Hash{}, errors.New("delete blob error"))
@@ -3124,7 +3124,7 @@ func TestGitRepository_Delete_ErrorConditions(t *testing.T) {
setupMock: func(mockClient *mocks.FakeClient) {
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"),
}, nil)
mockWriter := &mocks.FakeStagedWriter{}
mockWriter.DeleteTreeReturns(hash.Hash{}, errors.New("delete tree error"))
@@ -3139,7 +3139,7 @@ func TestGitRepository_Delete_ErrorConditions(t *testing.T) {
setupMock: func(mockClient *mocks.FakeClient) {
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"),
}, nil)
mockWriter := &mocks.FakeStagedWriter{}
mockWriter.DeleteTreeReturns(hash.Hash{}, nanogit.ErrObjectNotFound)
@@ -3186,7 +3186,7 @@ func TestGitRepository_CompareFiles_EmptyBase(t *testing.T) {
// Only setup for ref resolution
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/feature",
Hash: hash.Hash{4, 5, 6},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"),
}, nil)
mockClient.CompareCommitsReturns([]nanogit.CommitFile{
{
@@ -3218,8 +3218,8 @@ func TestGitRepository_CompareFiles_EmptyBase(t *testing.T) {
// Verify CompareCommits was called with empty base hash and feature hash
require.Equal(t, 1, mockClient.CompareCommitsCallCount())
_, baseHash, refHash := mockClient.CompareCommitsArgsForCall(0)
require.Nil(t, baseHash) // Empty hash for empty base
require.Equal(t, hash.Hash{4, 5, 6}, refHash)
require.Equal(t, hash.Zero, baseHash) // Empty hash for empty base
require.Equal(t, hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"), refHash)
}
func TestGitRepository_EmptyRefHandling(t *testing.T) {
@@ -3237,7 +3237,7 @@ func TestGitRepository_EmptyRefHandling(t *testing.T) {
mockClient := &mocks.FakeClient{}
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"),
}, nil)
mockWriter := &mocks.FakeStagedWriter{}
@@ -3299,7 +3299,7 @@ func TestGitRepository_CompareFiles_ResolveErrors(t *testing.T) {
// First call succeeds for base
mockClient.GetRefReturnsOnCall(0, nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"),
}, nil)
// Second call fails for ref
mockClient.GetRefReturnsOnCall(1, nanogit.Ref{}, errors.New("ref error"))
@@ -3341,14 +3341,14 @@ func TestGitRepository_Read_EmptyRef(t *testing.T) {
mockClient := &mocks.FakeClient{}
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"),
}, nil)
mockClient.GetCommitReturns(&nanogit.Commit{
Tree: hash.Hash{4, 5, 6},
Tree: hash.Hash{4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23},
}, nil)
mockClient.GetBlobByPathReturns(&nanogit.Blob{
Content: []byte("file content"),
Hash: hash.Hash{7, 8, 9},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"),
}, nil)
gitRepo := &gitRepository{
@@ -3376,13 +3376,13 @@ func TestGitRepository_ReadTree_EmptyRef(t *testing.T) {
mockClient := &mocks.FakeClient{}
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"),
}, nil)
mockClient.GetFlatTreeReturns(&nanogit.FlatTree{
Entries: []nanogit.FlatTreeEntry{
{
Path: "configs/test.yaml",
Hash: hash.Hash{4, 5, 6},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"),
Type: protocol.ObjectTypeBlob,
},
},
@@ -3504,17 +3504,17 @@ func TestGitRepository_Write_DefaultRef(t *testing.T) {
// First call for Read check - file not found
mockClient.GetRefReturnsOnCall(0, nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"),
}, nil)
mockClient.GetCommitReturns(&nanogit.Commit{
Tree: hash.Hash{4, 5, 6},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"),
}, nil)
mockClient.GetBlobByPathReturns(&nanogit.Blob{}, nanogit.ErrObjectNotFound)
// Second call for Create
mockClient.GetRefReturnsOnCall(1, nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"),
}, nil)
mockWriter := &mocks.FakeStagedWriter{}
mockWriter.CreateBlobReturns(hash.Hash{}, nil)
@@ -3545,14 +3545,14 @@ func TestGitRepository_Read_RefInFileInfo(t *testing.T) {
mockClient := &mocks.FakeClient{}
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/feature",
Hash: hash.Hash{1, 2, 3},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"),
}, nil)
mockClient.GetCommitReturns(&nanogit.Commit{
Tree: hash.Hash{4, 5, 6},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"),
}, nil)
mockClient.GetBlobByPathReturns(&nanogit.Blob{
Content: []byte("file content"),
Hash: hash.Hash{7, 8, 9},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"),
}, nil)
gitRepo := &gitRepository{
@@ -3582,10 +3582,10 @@ func TestGitRepository_Read_GetTreeByPath_NotFound(t *testing.T) {
mockClient := &mocks.FakeClient{}
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"),
}, nil)
mockClient.GetCommitReturns(&nanogit.Commit{
Tree: hash.Hash([]byte("tree-hash")),
Tree: hash.Hash{30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49},
}, nil)
mockClient.GetTreeByPathReturns(nil, nanogit.ErrObjectNotFound)
@@ -3614,7 +3614,7 @@ func TestGitRepository_ReadTree_GetFlatTree_NotFound(t *testing.T) {
mockClient := &mocks.FakeClient{}
mockClient.GetRefReturns(nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"),
}, nil)
mockClient.GetFlatTreeReturns(nil, nanogit.ErrObjectNotFound)
@@ -3655,11 +3655,11 @@ func TestGitRepository_CompareFiles_FilesOutsideConfiguredPath_AllStatuses(t *te
mockClient := &mocks.FakeClient{}
mockClient.GetRefReturnsOnCall(0, nanogit.Ref{
Name: "refs/heads/main",
Hash: hash.Hash{1, 2, 3},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121314"),
}, nil)
mockClient.GetRefReturnsOnCall(1, nanogit.Ref{
Name: "refs/heads/feature",
Hash: hash.Hash{4, 5, 6},
Hash: hash.MustFromHex("0102030405060708090a0b0c0d0e0f1011121315"),
}, nil)
mockClient.CompareCommitsReturns([]nanogit.CommitFile{
{
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package repository
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package repository
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package resources
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package resources
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package resources
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package resources
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package resources
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package resources
@@ -26,64 +26,6 @@ func (_m *MockRepositoryResources) EXPECT() *MockRepositoryResources_Expecter {
return &MockRepositoryResources_Expecter{mock: &_m.Mock}
}
// WriteResourceFileFromObject provides a mock function with given fields: ctx, obj, options
func (_m *MockRepositoryResources) WriteResourceFileFromObject(ctx context.Context, obj *unstructured.Unstructured, options WriteOptions) (string, error) {
ret := _m.Called(ctx, obj, options)
if len(ret) == 0 {
panic("no return value specified for WriteResourceFileFromObject")
}
var r0 string
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, *unstructured.Unstructured, WriteOptions) (string, error)); ok {
return rf(ctx, obj, options)
}
if rf, ok := ret.Get(0).(func(context.Context, *unstructured.Unstructured, WriteOptions) string); ok {
r0 = rf(ctx, obj, options)
} else {
r0 = ret.Get(0).(string)
}
if rf, ok := ret.Get(1).(func(context.Context, *unstructured.Unstructured, WriteOptions) error); ok {
r1 = rf(ctx, obj, options)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// MockRepositoryResources_WriteResourceFileFromObject_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WriteResourceFileFromObject'
type MockRepositoryResources_WriteResourceFileFromObject_Call struct {
*mock.Call
}
// WriteResourceFileFromObject is a helper method to define mock.On call
// - ctx context.Context
// - obj *unstructured.Unstructured
// - options WriteOptions
func (_e *MockRepositoryResources_Expecter) WriteResourceFileFromObject(ctx interface{}, obj interface{}, options interface{}) *MockRepositoryResources_WriteResourceFileFromObject_Call {
return &MockRepositoryResources_WriteResourceFileFromObject_Call{Call: _e.mock.On("WriteResourceFileFromObject", ctx, obj, options)}
}
func (_c *MockRepositoryResources_WriteResourceFileFromObject_Call) Run(run func(ctx context.Context, obj *unstructured.Unstructured, options WriteOptions)) *MockRepositoryResources_WriteResourceFileFromObject_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(*unstructured.Unstructured), args[2].(WriteOptions))
})
return _c
}
func (_c *MockRepositoryResources_WriteResourceFileFromObject_Call) Return(_a0 string, _a1 error) *MockRepositoryResources_WriteResourceFileFromObject_Call {
_c.Call.Return(_a0, _a1)
return _c
}
func (_c *MockRepositoryResources_WriteResourceFileFromObject_Call) RunAndReturn(run func(context.Context, *unstructured.Unstructured, WriteOptions) (string, error)) *MockRepositoryResources_WriteResourceFileFromObject_Call {
_c.Call.Return(run)
return _c
}
// EnsureFolderExists provides a mock function with given fields: ctx, folder, parentID
func (_m *MockRepositoryResources) EnsureFolderExists(ctx context.Context, folder Folder, parentID string) error {
ret := _m.Called(ctx, folder, parentID)
@@ -520,6 +462,64 @@ func (_c *MockRepositoryResources_Stats_Call) RunAndReturn(run func(context.Cont
return _c
}
// WriteResourceFileFromObject provides a mock function with given fields: ctx, obj, options
func (_m *MockRepositoryResources) WriteResourceFileFromObject(ctx context.Context, obj *unstructured.Unstructured, options WriteOptions) (string, error) {
ret := _m.Called(ctx, obj, options)
if len(ret) == 0 {
panic("no return value specified for WriteResourceFileFromObject")
}
var r0 string
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, *unstructured.Unstructured, WriteOptions) (string, error)); ok {
return rf(ctx, obj, options)
}
if rf, ok := ret.Get(0).(func(context.Context, *unstructured.Unstructured, WriteOptions) string); ok {
r0 = rf(ctx, obj, options)
} else {
r0 = ret.Get(0).(string)
}
if rf, ok := ret.Get(1).(func(context.Context, *unstructured.Unstructured, WriteOptions) error); ok {
r1 = rf(ctx, obj, options)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// MockRepositoryResources_WriteResourceFileFromObject_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'WriteResourceFileFromObject'
type MockRepositoryResources_WriteResourceFileFromObject_Call struct {
*mock.Call
}
// WriteResourceFileFromObject is a helper method to define mock.On call
// - ctx context.Context
// - obj *unstructured.Unstructured
// - options WriteOptions
func (_e *MockRepositoryResources_Expecter) WriteResourceFileFromObject(ctx interface{}, obj interface{}, options interface{}) *MockRepositoryResources_WriteResourceFileFromObject_Call {
return &MockRepositoryResources_WriteResourceFileFromObject_Call{Call: _e.mock.On("WriteResourceFileFromObject", ctx, obj, options)}
}
func (_c *MockRepositoryResources_WriteResourceFileFromObject_Call) Run(run func(ctx context.Context, obj *unstructured.Unstructured, options WriteOptions)) *MockRepositoryResources_WriteResourceFileFromObject_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(*unstructured.Unstructured), args[2].(WriteOptions))
})
return _c
}
func (_c *MockRepositoryResources_WriteResourceFileFromObject_Call) Return(_a0 string, _a1 error) *MockRepositoryResources_WriteResourceFileFromObject_Call {
_c.Call.Return(_a0, _a1)
return _c
}
func (_c *MockRepositoryResources_WriteResourceFileFromObject_Call) RunAndReturn(run func(context.Context, *unstructured.Unstructured, WriteOptions) (string, error)) *MockRepositoryResources_WriteResourceFileFromObject_Call {
_c.Call.Return(run)
return _c
}
// WriteResourceFromFile provides a mock function with given fields: ctx, path, ref
func (_m *MockRepositoryResources) WriteResourceFromFile(ctx context.Context, path string, ref string) (string, schema.GroupVersionKind, error) {
ret := _m.Called(ctx, path, ref)
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package resources
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package signature
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package signature
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package resources
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package secrets
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package pullrequest
@@ -9,7 +9,7 @@ import (
mock "github.com/stretchr/testify/mock"
"github.com/grafana/grafana/pkg/storage/unified/resourcepb"
resourcepb "github.com/grafana/grafana/pkg/storage/unified/resourcepb"
)
// MockBlobStoreClient is an autogenerated mock type for the BlobStoreClient type
@@ -69,7 +69,7 @@ type MockBlobStoreClient_PutBlob_Call struct {
// PutBlob is a helper method to define mock.On call
// - ctx context.Context
// - in *resource.PutBlobRequest
// - in *resourcepb.PutBlobRequest
// - opts ...grpc.CallOption
func (_e *MockBlobStoreClient_Expecter) PutBlob(ctx interface{}, in interface{}, opts ...interface{}) *MockBlobStoreClient_PutBlob_Call {
return &MockBlobStoreClient_PutBlob_Call{Call: _e.mock.On("PutBlob",
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package pullrequest
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package pullrequest
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package pullrequest
@@ -1,4 +1,4 @@
// Code generated by mockery v2.52.4. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package pullrequest
@@ -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
}
@@ -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)
}
+93 -154
View File
@@ -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"}
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()
var out *secretv0alpha1.SecureValue
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)
}
// Specifically 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 {
createdSecureValue, err := s.secureValueMetadataStorage.Create(ctx, sv, actorUID)
if newSecureValue.Spec.Value == "" {
decrypted, err := s.secureValueMetadataStorage.ReadForDecrypt(ctx, xkube.Namespace(newSecureValue.Namespace), newSecureValue.Name)
if err != nil {
return fmt.Errorf("failed to create securevalue: %w", 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)
return nil, false, fmt.Errorf("reading secure value secret: %+w", err)
}
return nil
}); err != nil {
return out, err
// 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)
}
keeper, err := s.keeperService.KeeperForConfig(keeperCfg)
if err != nil {
return nil, false, fmt.Errorf("getting keeper for config: namespace=%+v keeperName=%+v %w", newSecureValue.Namespace, newSecureValue.Spec.Keeper, 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)
}
newSecureValue.Spec.Value = secret
}
return out, nil
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)
}
// 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
return nil
}); err != nil {
return out, err
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 out, nil
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 sv, nil
}
@@ -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)
})
}
+24 -46
View File
@@ -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 WithKeeperService(keeperService contracts.KeeperService) func(*SetupConfig) {
return func(setupCfg *SetupConfig) {
setupCfg.KeeperService = keeperService
}
}
func WithWorkerConfig(cfg worker.Config) func(*setupConfig) {
return func(setupCfg *setupConfig) {
setupCfg.workerCfg = cfg
func WithMutateCfg(f func(*SetupConfig)) func(*SetupConfig) {
return func(cfg *SetupConfig) {
f(cfg)
}
}
func WithKeeperService(keeperService contracts.KeeperService) func(*setupConfig) {
return func(setupCfg *setupConfig) {
setupCfg.keeperService = keeperService
}
}
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 {
@@ -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()
}
-274
View File
@@ -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
}
@@ -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)
})
}
@@ -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,
)
}
+2
View File
@@ -19,6 +19,7 @@ import (
"github.com/grafana/grafana/pkg/api"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/tracing"
"github.com/grafana/grafana/pkg/modules"
"github.com/grafana/grafana/pkg/services/authz"
"github.com/grafana/grafana/pkg/services/featuremgmt"
@@ -39,6 +40,7 @@ func NewModule(opts Options,
indexMetrics *resource.BleveIndexMetrics,
reg prometheus.Registerer,
promGatherer prometheus.Gatherer,
tracer tracing.Tracer, // Ensures tracing is initialized
license licensing.Licensing,
) (*ModuleServer, error) {
s, err := newModuleServer(opts, apiOpts, features, cfg, storageMetrics, indexMetrics, reg, promGatherer, license)
+4 -1
View File
@@ -15,6 +15,7 @@ import (
claims "github.com/grafana/authlib/types"
"github.com/grafana/grafana/pkg/api"
"github.com/grafana/grafana/pkg/apimachinery/identity"
"github.com/grafana/grafana/pkg/infra/tracing"
"github.com/grafana/grafana/pkg/modules"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/sqlstore/sqlutil"
@@ -321,7 +322,9 @@ func initModuleServerForTest(
opts Options,
apiOpts api.ServerOptions,
) testModuleServer {
ms, err := NewModule(opts, apiOpts, featuremgmt.WithFeatures(featuremgmt.FlagUnifiedStorageSearch), cfg, nil, nil, prometheus.NewRegistry(), prometheus.DefaultGatherer, nil)
tracer := tracing.InitializeTracerForTest()
ms, err := NewModule(opts, apiOpts, featuremgmt.WithFeatures(featuremgmt.FlagUnifiedStorageSearch), cfg, nil, nil, prometheus.NewRegistry(), prometheus.DefaultGatherer, tracer, nil)
require.NoError(t, err)
conn, err := grpc.NewClient(cfg.GRPCServer.Address,
-4
View File
@@ -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,
+15 -73
View File
File diff suppressed because one or more lines are too long
+5
View File
@@ -8,6 +8,7 @@ import (
"github.com/google/wire"
"github.com/grafana/grafana/pkg/infra/metrics"
"github.com/grafana/grafana/pkg/infra/tracing"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/plugins/manager"
"github.com/grafana/grafana/pkg/registry"
@@ -165,6 +166,10 @@ var wireExtsBaseCLISet = wire.NewSet(
var wireExtsModuleServerSet = wire.NewSet(
NewModule,
wireExtsBaseCLISet,
// Tracing
tracing.ProvideTracingConfig,
tracing.ProvideService,
wire.Bind(new(tracing.Tracer), new(*tracing.TracingService)),
// Unified storage
resource.ProvideStorageMetrics,
resource.ProvideIndexMetrics,
@@ -1,4 +1,4 @@
// Code generated by mockery v2.43.0. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package actest
@@ -1,10 +1,9 @@
// Code generated by mockery v2.12.0. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package annotations
import (
context "context"
testing "testing"
mock "github.com/stretchr/testify/mock"
)
@@ -18,6 +17,10 @@ type FakeAnnotationsRepo struct {
func (_m *FakeAnnotationsRepo) Delete(ctx context.Context, params *DeleteParams) error {
ret := _m.Called(ctx, params)
if len(ret) == 0 {
panic("no return value specified for Delete")
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, *DeleteParams) error); ok {
r0 = rf(ctx, params)
@@ -32,7 +35,15 @@ func (_m *FakeAnnotationsRepo) Delete(ctx context.Context, params *DeleteParams)
func (_m *FakeAnnotationsRepo) Find(ctx context.Context, query *ItemQuery) ([]*ItemDTO, error) {
ret := _m.Called(ctx, query)
if len(ret) == 0 {
panic("no return value specified for Find")
}
var r0 []*ItemDTO
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, *ItemQuery) ([]*ItemDTO, error)); ok {
return rf(ctx, query)
}
if rf, ok := ret.Get(0).(func(context.Context, *ItemQuery) []*ItemDTO); ok {
r0 = rf(ctx, query)
} else {
@@ -41,7 +52,6 @@ func (_m *FakeAnnotationsRepo) Find(ctx context.Context, query *ItemQuery) ([]*I
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, *ItemQuery) error); ok {
r1 = rf(ctx, query)
} else {
@@ -55,14 +65,21 @@ func (_m *FakeAnnotationsRepo) Find(ctx context.Context, query *ItemQuery) ([]*I
func (_m *FakeAnnotationsRepo) FindTags(ctx context.Context, query *TagsQuery) (FindTagsResult, error) {
ret := _m.Called(ctx, query)
if len(ret) == 0 {
panic("no return value specified for FindTags")
}
var r0 FindTagsResult
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, *TagsQuery) (FindTagsResult, error)); ok {
return rf(ctx, query)
}
if rf, ok := ret.Get(0).(func(context.Context, *TagsQuery) FindTagsResult); ok {
r0 = rf(ctx, query)
} else {
r0 = ret.Get(0).(FindTagsResult)
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, *TagsQuery) error); ok {
r1 = rf(ctx, query)
} else {
@@ -76,6 +93,10 @@ func (_m *FakeAnnotationsRepo) FindTags(ctx context.Context, query *TagsQuery) (
func (_m *FakeAnnotationsRepo) Save(ctx context.Context, item *Item) error {
ret := _m.Called(ctx, item)
if len(ret) == 0 {
panic("no return value specified for Save")
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, *Item) error); ok {
r0 = rf(ctx, item)
@@ -90,6 +111,10 @@ func (_m *FakeAnnotationsRepo) Save(ctx context.Context, item *Item) error {
func (_m *FakeAnnotationsRepo) SaveMany(ctx context.Context, items []Item) error {
ret := _m.Called(ctx, items)
if len(ret) == 0 {
panic("no return value specified for SaveMany")
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, []Item) error); ok {
r0 = rf(ctx, items)
@@ -104,6 +129,10 @@ func (_m *FakeAnnotationsRepo) SaveMany(ctx context.Context, items []Item) error
func (_m *FakeAnnotationsRepo) Update(ctx context.Context, item *Item) error {
ret := _m.Called(ctx, item)
if len(ret) == 0 {
panic("no return value specified for Update")
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, *Item) error); ok {
r0 = rf(ctx, item)
@@ -114,8 +143,12 @@ func (_m *FakeAnnotationsRepo) Update(ctx context.Context, item *Item) error {
return r0
}
// NewFakeAnnotationsRepo creates a new instance of FakeAnnotationsRepo. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations.
func NewFakeAnnotationsRepo(t testing.TB) *FakeAnnotationsRepo {
// NewFakeAnnotationsRepo creates a new instance of FakeAnnotationsRepo. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
// The first argument is typically a *testing.T value.
func NewFakeAnnotationsRepo(t interface {
mock.TestingT
Cleanup(func())
}) *FakeAnnotationsRepo {
mock := &FakeAnnotationsRepo{}
mock.Mock.Test(t)
@@ -1,4 +1,4 @@
// Code generated by mockery v2.42.1. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package authtest
@@ -1,4 +1,4 @@
// Code generated by mockery v2.42.1. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package authtest
+1 -1
View File
@@ -1,4 +1,4 @@
// Code generated by mockery v2.42.1. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package idtest
+13 -11
View File
@@ -150,17 +150,19 @@ const (
type ItemErrorCode string
const (
ErrDatasourceNameConflict ItemErrorCode = "DATASOURCE_NAME_CONFLICT"
ErrDatasourceInvalidURL ItemErrorCode = "DATASOURCE_INVALID_URL"
ErrDatasourceAlreadyManaged ItemErrorCode = "DATASOURCE_ALREADY_MANAGED"
ErrFolderNameConflict ItemErrorCode = "FOLDER_NAME_CONFLICT"
ErrDashboardAlreadyManaged ItemErrorCode = "DASHBOARD_ALREADY_MANAGED"
ErrLibraryElementNameConflict ItemErrorCode = "LIBRARY_ELEMENT_NAME_CONFLICT"
ErrUnsupportedDataType ItemErrorCode = "UNSUPPORTED_DATA_TYPE"
ErrResourceConflict ItemErrorCode = "RESOURCE_CONFLICT"
ErrUnexpectedStatus ItemErrorCode = "UNEXPECTED_STATUS_CODE"
ErrInternalServiceError ItemErrorCode = "INTERNAL_SERVICE_ERROR"
ErrGeneric ItemErrorCode = "GENERIC_ERROR"
ErrAlertRulesQuotaReached ItemErrorCode = "ALERT_RULES_QUOTA_REACHED"
ErrAlertRulesGroupQuotaReached ItemErrorCode = "ALERT_RULES_GROUP_QUOTA_REACHED"
ErrDatasourceNameConflict ItemErrorCode = "DATASOURCE_NAME_CONFLICT"
ErrDatasourceInvalidURL ItemErrorCode = "DATASOURCE_INVALID_URL"
ErrDatasourceAlreadyManaged ItemErrorCode = "DATASOURCE_ALREADY_MANAGED"
ErrFolderNameConflict ItemErrorCode = "FOLDER_NAME_CONFLICT"
ErrDashboardAlreadyManaged ItemErrorCode = "DASHBOARD_ALREADY_MANAGED"
ErrLibraryElementNameConflict ItemErrorCode = "LIBRARY_ELEMENT_NAME_CONFLICT"
ErrUnsupportedDataType ItemErrorCode = "UNSUPPORTED_DATA_TYPE"
ErrResourceConflict ItemErrorCode = "RESOURCE_CONFLICT"
ErrUnexpectedStatus ItemErrorCode = "UNEXPECTED_STATUS_CODE"
ErrInternalServiceError ItemErrorCode = "INTERNAL_SERVICE_ERROR"
ErrGeneric ItemErrorCode = "GENERIC_ERROR"
)
// swagger:parameters getCloudMigrationRun
+13 -11
View File
@@ -110,17 +110,19 @@ const (
type ResourceErrorCode string
const (
ErrDatasourceNameConflict ResourceErrorCode = "DATASOURCE_NAME_CONFLICT"
ErrDatasourceInvalidURL ResourceErrorCode = "DATASOURCE_INVALID_URL"
ErrDatasourceAlreadyManaged ResourceErrorCode = "DATASOURCE_ALREADY_MANAGED"
ErrFolderNameConflict ResourceErrorCode = "FOLDER_NAME_CONFLICT"
ErrDashboardAlreadyManaged ResourceErrorCode = "DASHBOARD_ALREADY_MANAGED"
ErrLibraryElementNameConflict ResourceErrorCode = "LIBRARY_ELEMENT_NAME_CONFLICT"
ErrUnsupportedDataType ResourceErrorCode = "UNSUPPORTED_DATA_TYPE"
ErrResourceConflict ResourceErrorCode = "RESOURCE_CONFLICT"
ErrUnexpectedStatus ResourceErrorCode = "UNEXPECTED_STATUS_CODE"
ErrInternalServiceError ResourceErrorCode = "INTERNAL_SERVICE_ERROR"
ErrGeneric ResourceErrorCode = "GENERIC_ERROR"
ErrAlertRulesQuotaReached ResourceErrorCode = "ALERT_RULES_QUOTA_REACHED"
ErrAlertRulesGroupQuotaReached ResourceErrorCode = "ALERT_RULES_GROUP_QUOTA_REACHED"
ErrDatasourceNameConflict ResourceErrorCode = "DATASOURCE_NAME_CONFLICT"
ErrDatasourceInvalidURL ResourceErrorCode = "DATASOURCE_INVALID_URL"
ErrDatasourceAlreadyManaged ResourceErrorCode = "DATASOURCE_ALREADY_MANAGED"
ErrFolderNameConflict ResourceErrorCode = "FOLDER_NAME_CONFLICT"
ErrDashboardAlreadyManaged ResourceErrorCode = "DASHBOARD_ALREADY_MANAGED"
ErrLibraryElementNameConflict ResourceErrorCode = "LIBRARY_ELEMENT_NAME_CONFLICT"
ErrUnsupportedDataType ResourceErrorCode = "UNSUPPORTED_DATA_TYPE"
ErrResourceConflict ResourceErrorCode = "RESOURCE_CONFLICT"
ErrUnexpectedStatus ResourceErrorCode = "UNEXPECTED_STATUS_CODE"
ErrInternalServiceError ResourceErrorCode = "INTERNAL_SERVICE_ERROR"
ErrGeneric ResourceErrorCode = "GENERIC_ERROR"
)
type SnapshotResourceStats struct {
@@ -1,4 +1,4 @@
// Code generated by mockery v2.53.3. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package dashboards
@@ -1,4 +1,4 @@
// Code generated by mockery v2.53.3. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package dashboards
@@ -94,36 +94,6 @@ func (_m *FakeDashboardService) CountDashboardsInOrg(ctx context.Context, orgID
return r0, r1
}
// GetDashboardsByLibraryPanelUID provides a mock function with given fields: ctx, libraryPanelUID, orgID
func (_m *FakeDashboardService) GetDashboardsByLibraryPanelUID(ctx context.Context, libraryPanelUID string, orgID int64) ([]*DashboardRef, error) {
ret := _m.Called(ctx, libraryPanelUID, orgID)
if len(ret) == 0 {
panic("no return value specified for GetDashboardsByLibraryPanelUID")
}
var r0 []*DashboardRef
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string, int64) ([]*DashboardRef, error)); ok {
return rf(ctx, libraryPanelUID, orgID)
}
if rf, ok := ret.Get(0).(func(context.Context, string, int64) []*DashboardRef); ok {
r0 = rf(ctx, libraryPanelUID, orgID)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]*DashboardRef)
}
}
if rf, ok := ret.Get(1).(func(context.Context, string, int64) error); ok {
r1 = rf(ctx, libraryPanelUID, orgID)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// CountInFolders provides a mock function with given fields: ctx, orgID, folderUIDs, user
func (_m *FakeDashboardService) CountInFolders(ctx context.Context, orgID int64, folderUIDs []string, user identity.Requester) (int64, error) {
ret := _m.Called(ctx, orgID, folderUIDs, user)
@@ -368,6 +338,36 @@ func (_m *FakeDashboardService) GetDashboards(ctx context.Context, query *GetDas
return r0, r1
}
// GetDashboardsByLibraryPanelUID provides a mock function with given fields: ctx, libraryPanelUID, orgID
func (_m *FakeDashboardService) GetDashboardsByLibraryPanelUID(ctx context.Context, libraryPanelUID string, orgID int64) ([]*DashboardRef, error) {
ret := _m.Called(ctx, libraryPanelUID, orgID)
if len(ret) == 0 {
panic("no return value specified for GetDashboardsByLibraryPanelUID")
}
var r0 []*DashboardRef
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string, int64) ([]*DashboardRef, error)); ok {
return rf(ctx, libraryPanelUID, orgID)
}
if rf, ok := ret.Get(0).(func(context.Context, string, int64) []*DashboardRef); ok {
r0 = rf(ctx, libraryPanelUID, orgID)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]*DashboardRef)
}
}
if rf, ok := ret.Get(1).(func(context.Context, string, int64) error); ok {
r1 = rf(ctx, libraryPanelUID, orgID)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// ImportDashboard provides a mock function with given fields: ctx, dto
func (_m *FakeDashboardService) ImportDashboard(ctx context.Context, dto *SaveDashboardDTO) (*Dashboard, error) {
ret := _m.Called(ctx, dto)
+31 -31
View File
@@ -1,4 +1,4 @@
// Code generated by mockery v2.53.3. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package dashboards
@@ -370,6 +370,36 @@ func (_m *FakeDashboardStore) GetDashboards(ctx context.Context, query *GetDashb
return r0, r1
}
// GetDashboardsByLibraryPanelUID provides a mock function with given fields: ctx, libraryPanelUID, orgID
func (_m *FakeDashboardStore) GetDashboardsByLibraryPanelUID(ctx context.Context, libraryPanelUID string, orgID int64) ([]*DashboardRef, error) {
ret := _m.Called(ctx, libraryPanelUID, orgID)
if len(ret) == 0 {
panic("no return value specified for GetDashboardsByLibraryPanelUID")
}
var r0 []*DashboardRef
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string, int64) ([]*DashboardRef, error)); ok {
return rf(ctx, libraryPanelUID, orgID)
}
if rf, ok := ret.Get(0).(func(context.Context, string, int64) []*DashboardRef); ok {
r0 = rf(ctx, libraryPanelUID, orgID)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]*DashboardRef)
}
}
if rf, ok := ret.Get(1).(func(context.Context, string, int64) error); ok {
r1 = rf(ctx, libraryPanelUID, orgID)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// GetDashboardsByPluginID provides a mock function with given fields: ctx, query
func (_m *FakeDashboardStore) GetDashboardsByPluginID(ctx context.Context, query *GetDashboardsByPluginIDQuery) ([]*Dashboard, error) {
ret := _m.Called(ctx, query)
@@ -628,36 +658,6 @@ func (_m *FakeDashboardStore) UnprovisionDashboard(ctx context.Context, id int64
return r0
}
// GetDashboardsByLibraryPanelUID provides a mock function with given fields: ctx, libraryPanelUID, orgID
func (_m *FakeDashboardStore) GetDashboardsByLibraryPanelUID(ctx context.Context, libraryPanelUID string, orgID int64) ([]*DashboardRef, error) {
ret := _m.Called(ctx, libraryPanelUID, orgID)
if len(ret) == 0 {
panic("no return value specified for GetDashboardsByLibraryPanelUID")
}
var r0 []*DashboardRef
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string, int64) ([]*DashboardRef, error)); ok {
return rf(ctx, libraryPanelUID, orgID)
}
if rf, ok := ret.Get(0).(func(context.Context, string, int64) []*DashboardRef); ok {
r0 = rf(ctx, libraryPanelUID, orgID)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]*DashboardRef)
}
}
if rf, ok := ret.Get(1).(func(context.Context, string, int64) error); ok {
r1 = rf(ctx, libraryPanelUID, orgID)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// ValidateDashboardBeforeSave provides a mock function with given fields: ctx, dashboard, overwrite
func (_m *FakeDashboardStore) ValidateDashboardBeforeSave(ctx context.Context, dashboard *Dashboard, overwrite bool) (bool, error) {
ret := _m.Called(ctx, dashboard, overwrite)
@@ -1,4 +1,4 @@
// Code generated by mockery v2.34.0. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package dashboardsnapshots
@@ -17,6 +17,10 @@ type MockService struct {
func (_m *MockService) CreateDashboardSnapshot(_a0 context.Context, _a1 *CreateDashboardSnapshotCommand) (*DashboardSnapshot, error) {
ret := _m.Called(_a0, _a1)
if len(ret) == 0 {
panic("no return value specified for CreateDashboardSnapshot")
}
var r0 *DashboardSnapshot
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, *CreateDashboardSnapshotCommand) (*DashboardSnapshot, error)); ok {
@@ -43,6 +47,10 @@ func (_m *MockService) CreateDashboardSnapshot(_a0 context.Context, _a1 *CreateD
func (_m *MockService) DeleteDashboardSnapshot(_a0 context.Context, _a1 *DeleteDashboardSnapshotCommand) error {
ret := _m.Called(_a0, _a1)
if len(ret) == 0 {
panic("no return value specified for DeleteDashboardSnapshot")
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, *DeleteDashboardSnapshotCommand) error); ok {
r0 = rf(_a0, _a1)
@@ -57,6 +65,10 @@ func (_m *MockService) DeleteDashboardSnapshot(_a0 context.Context, _a1 *DeleteD
func (_m *MockService) DeleteExpiredSnapshots(_a0 context.Context, _a1 *DeleteExpiredSnapshotsCommand) error {
ret := _m.Called(_a0, _a1)
if len(ret) == 0 {
panic("no return value specified for DeleteExpiredSnapshots")
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, *DeleteExpiredSnapshotsCommand) error); ok {
r0 = rf(_a0, _a1)
@@ -71,6 +83,10 @@ func (_m *MockService) DeleteExpiredSnapshots(_a0 context.Context, _a1 *DeleteEx
func (_m *MockService) GetDashboardSnapshot(_a0 context.Context, _a1 *GetDashboardSnapshotQuery) (*DashboardSnapshot, error) {
ret := _m.Called(_a0, _a1)
if len(ret) == 0 {
panic("no return value specified for GetDashboardSnapshot")
}
var r0 *DashboardSnapshot
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, *GetDashboardSnapshotQuery) (*DashboardSnapshot, error)); ok {
@@ -97,6 +113,10 @@ func (_m *MockService) GetDashboardSnapshot(_a0 context.Context, _a1 *GetDashboa
func (_m *MockService) SearchDashboardSnapshots(_a0 context.Context, _a1 *GetDashboardSnapshotsQuery) (DashboardSnapshotsList, error) {
ret := _m.Called(_a0, _a1)
if len(ret) == 0 {
panic("no return value specified for SearchDashboardSnapshots")
}
var r0 DashboardSnapshotsList
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, *GetDashboardSnapshotsQuery) (DashboardSnapshotsList, error)); ok {
@@ -123,6 +143,10 @@ func (_m *MockService) SearchDashboardSnapshots(_a0 context.Context, _a1 *GetDas
func (_m *MockService) ValidateDashboardExists(_a0 context.Context, _a1 int64, _a2 string) error {
ret := _m.Called(_a0, _a1, _a2)
if len(ret) == 0 {
panic("no return value specified for ValidateDashboardExists")
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, int64, string) error); ok {
r0 = rf(_a0, _a1, _a2)
+17 -1
View File
@@ -1,4 +1,4 @@
// Code generated by mockery v2.35.2. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package tests
@@ -18,6 +18,10 @@ type ExternalServiceRegistryMock struct {
func (_m *ExternalServiceRegistryMock) GetExternalServiceNames(ctx context.Context) ([]string, error) {
ret := _m.Called(ctx)
if len(ret) == 0 {
panic("no return value specified for GetExternalServiceNames")
}
var r0 []string
var r1 error
if rf, ok := ret.Get(0).(func(context.Context) ([]string, error)); ok {
@@ -44,6 +48,10 @@ func (_m *ExternalServiceRegistryMock) GetExternalServiceNames(ctx context.Conte
func (_m *ExternalServiceRegistryMock) HasExternalService(ctx context.Context, name string) (bool, error) {
ret := _m.Called(ctx, name)
if len(ret) == 0 {
panic("no return value specified for HasExternalService")
}
var r0 bool
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string) (bool, error)); ok {
@@ -68,6 +76,10 @@ func (_m *ExternalServiceRegistryMock) HasExternalService(ctx context.Context, n
func (_m *ExternalServiceRegistryMock) RemoveExternalService(ctx context.Context, name string) error {
ret := _m.Called(ctx, name)
if len(ret) == 0 {
panic("no return value specified for RemoveExternalService")
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, string) error); ok {
r0 = rf(ctx, name)
@@ -82,6 +94,10 @@ func (_m *ExternalServiceRegistryMock) RemoveExternalService(ctx context.Context
func (_m *ExternalServiceRegistryMock) SaveExternalService(ctx context.Context, cmd *extsvcauth.ExternalServiceRegistration) (*extsvcauth.ExternalService, error) {
ret := _m.Called(ctx, cmd)
if len(ret) == 0 {
panic("no return value specified for SaveExternalService")
}
var r0 *extsvcauth.ExternalService
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, *extsvcauth.ExternalServiceRegistration) (*extsvcauth.ExternalService, error)); ok {
+1 -1
View File
@@ -1714,7 +1714,7 @@ var (
Description: "Use fixed-width numbers globally in the UI",
Stage: FeatureStageGeneralAvailability,
Owner: grafanaFrontendPlatformSquad,
Expression: "true",
Expression: "false",
},
{
Name: "newInfluxDSConfigPageDesign",
+3 -3
View File
@@ -2943,17 +2943,17 @@
{
"metadata": {
"name": "tabularNumbers",
"resourceVersion": "1750754828442",
"resourceVersion": "1752078306230",
"creationTimestamp": "2025-06-24T11:52:03Z",
"annotations": {
"grafana.app/updatedTimestamp": "2025-06-24 08:47:08.442537461 +0000 UTC"
"grafana.app/updatedTimestamp": "2025-07-09 16:25:06.230922635 +0000 UTC"
}
},
"spec": {
"description": "Use fixed-width numbers globally in the UI",
"stage": "GA",
"codeowner": "@grafana/grafana-frontend-platform",
"expression": "true"
"expression": "false"
}
},
{
@@ -1,4 +1,4 @@
// Code generated by mockery v2.32.0. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package foldertest
@@ -14,10 +14,44 @@ type FakeFolderStore struct {
mock.Mock
}
// Get provides a mock function with given fields: ctx, q
func (_m *FakeFolderStore) Get(ctx context.Context, q folder.GetFolderQuery) (*folder.Folder, error) {
ret := _m.Called(ctx, q)
if len(ret) == 0 {
panic("no return value specified for Get")
}
var r0 *folder.Folder
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, folder.GetFolderQuery) (*folder.Folder, error)); ok {
return rf(ctx, q)
}
if rf, ok := ret.Get(0).(func(context.Context, folder.GetFolderQuery) *folder.Folder); ok {
r0 = rf(ctx, q)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*folder.Folder)
}
}
if rf, ok := ret.Get(1).(func(context.Context, folder.GetFolderQuery) error); ok {
r1 = rf(ctx, q)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// GetFolderByID provides a mock function with given fields: ctx, orgID, id
func (_m *FakeFolderStore) GetFolderByID(ctx context.Context, orgID int64, id int64) (*folder.Folder, error) {
ret := _m.Called(ctx, orgID, id)
if len(ret) == 0 {
panic("no return value specified for GetFolderByID")
}
var r0 *folder.Folder
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, int64, int64) (*folder.Folder, error)); ok {
@@ -40,36 +74,14 @@ func (_m *FakeFolderStore) GetFolderByID(ctx context.Context, orgID int64, id in
return r0, r1
}
// Get provides a mock function with given fields: ctx, query
func (_m *FakeFolderStore) Get(ctx context.Context, query folder.GetFolderQuery) (*folder.Folder, error) {
ret := _m.Called(ctx, query)
var r0 *folder.Folder
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, folder.GetFolderQuery) (*folder.Folder, error)); ok {
return rf(ctx, query)
}
if rf, ok := ret.Get(0).(func(context.Context, folder.GetFolderQuery) *folder.Folder); ok {
r0 = rf(ctx, query)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*folder.Folder)
}
}
if rf, ok := ret.Get(1).(func(context.Context, folder.GetFolderQuery) error); ok {
r1 = rf(ctx, query)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// GetFolderByUID provides a mock function with given fields: ctx, orgID, uid
func (_m *FakeFolderStore) GetFolderByUID(ctx context.Context, orgID int64, uid string) (*folder.Folder, error) {
ret := _m.Called(ctx, orgID, uid)
if len(ret) == 0 {
panic("no return value specified for GetFolderByUID")
}
var r0 *folder.Folder
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, int64, string) (*folder.Folder, error)); ok {
@@ -96,6 +108,10 @@ func (_m *FakeFolderStore) GetFolderByUID(ctx context.Context, orgID int64, uid
func (_m *FakeFolderStore) GetFolders(ctx context.Context, orgID int64, uids []string) (map[string]*folder.Folder, error) {
ret := _m.Called(ctx, orgID, uids)
if len(ret) == 0 {
panic("no return value specified for GetFolders")
}
var r0 map[string]*folder.Folder
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, int64, []string) (map[string]*folder.Folder, error)); ok {
@@ -118,29 +134,6 @@ func (_m *FakeFolderStore) GetFolders(ctx context.Context, orgID int64, uids []s
return r0, r1
}
func (_m *FakeFolderStore) CountInOrg(ctx context.Context, orgID int64) (int64, error) {
ret := _m.Called(ctx, orgID)
var r0 int64
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, int64) (int64, error)); ok {
return rf(ctx, orgID)
}
if rf, ok := ret.Get(0).(func(context.Context, int64) int64); ok {
r0 = rf(ctx, orgID)
} else {
r0 = ret.Get(0).(int64)
}
if rf, ok := ret.Get(1).(func(context.Context, int64) error); ok {
r1 = rf(ctx, orgID)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// NewFakeFolderStore creates a new instance of FakeFolderStore. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
// The first argument is typically a *testing.T value.
func NewFakeFolderStore(t interface {
@@ -8,6 +8,7 @@ import (
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"go.opentelemetry.io/otel"
"github.com/grafana/dskit/services"
"github.com/grafana/grafana/pkg/infra/log"
@@ -15,6 +16,8 @@ import (
"github.com/grafana/grafana/pkg/setting"
)
var tracer = otel.Tracer("github.com/grafana/grafana/pkg/services/frontend")
type frontendService struct {
*services.BasicService
cfg *setting.Cfg
+3
View File
@@ -79,6 +79,9 @@ func NewIndexProvider(cfg *setting.Cfg, license licensing.Licensing) (*IndexProv
}
func (p *IndexProvider) HandleRequest(writer http.ResponseWriter, request *http.Request) {
_, span := tracer.Start(request.Context(), "frontend.index.HandleRequest")
defer span.End()
if request.Method != "GET" {
writer.WriteHeader(http.StatusMethodNotAllowed)
return
@@ -1,15 +1,17 @@
// Code generated by mockery v2.14.0. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package eval_mocks
import (
context "context"
time "time"
backend "github.com/grafana/grafana-plugin-sdk-go/backend"
mock "github.com/stretchr/testify/mock"
eval "github.com/grafana/grafana/pkg/services/ngalert/eval"
mock "github.com/stretchr/testify/mock"
time "time"
)
// ConditionEvaluatorMock is an autogenerated mock type for the ConditionEvaluator type
@@ -29,7 +31,15 @@ func (_m *ConditionEvaluatorMock) EXPECT() *ConditionEvaluatorMock_Expecter {
func (_m *ConditionEvaluatorMock) Evaluate(ctx context.Context, now time.Time) (eval.Results, error) {
ret := _m.Called(ctx, now)
if len(ret) == 0 {
panic("no return value specified for Evaluate")
}
var r0 eval.Results
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, time.Time) (eval.Results, error)); ok {
return rf(ctx, now)
}
if rf, ok := ret.Get(0).(func(context.Context, time.Time) eval.Results); ok {
r0 = rf(ctx, now)
} else {
@@ -38,7 +48,6 @@ func (_m *ConditionEvaluatorMock) Evaluate(ctx context.Context, now time.Time) (
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, time.Time) error); ok {
r1 = rf(ctx, now)
} else {
@@ -56,7 +65,7 @@ type ConditionEvaluatorMock_Evaluate_Call struct {
// Evaluate is a helper method to define mock.On call
// - ctx context.Context
// - now time.Time
func (_e *ConditionEvaluatorMock_Expecter) Evaluate(ctx any, now any) *ConditionEvaluatorMock_Evaluate_Call {
func (_e *ConditionEvaluatorMock_Expecter) Evaluate(ctx interface{}, now interface{}) *ConditionEvaluatorMock_Evaluate_Call {
return &ConditionEvaluatorMock_Evaluate_Call{Call: _e.mock.On("Evaluate", ctx, now)}
}
@@ -72,11 +81,24 @@ func (_c *ConditionEvaluatorMock_Evaluate_Call) Return(_a0 eval.Results, _a1 err
return _c
}
func (_c *ConditionEvaluatorMock_Evaluate_Call) RunAndReturn(run func(context.Context, time.Time) (eval.Results, error)) *ConditionEvaluatorMock_Evaluate_Call {
_c.Call.Return(run)
return _c
}
// EvaluateRaw provides a mock function with given fields: ctx, now
func (_m *ConditionEvaluatorMock) EvaluateRaw(ctx context.Context, now time.Time) (*backend.QueryDataResponse, error) {
ret := _m.Called(ctx, now)
if len(ret) == 0 {
panic("no return value specified for EvaluateRaw")
}
var r0 *backend.QueryDataResponse
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, time.Time) (*backend.QueryDataResponse, error)); ok {
return rf(ctx, now)
}
if rf, ok := ret.Get(0).(func(context.Context, time.Time) *backend.QueryDataResponse); ok {
r0 = rf(ctx, now)
} else {
@@ -85,7 +107,6 @@ func (_m *ConditionEvaluatorMock) EvaluateRaw(ctx context.Context, now time.Time
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, time.Time) error); ok {
r1 = rf(ctx, now)
} else {
@@ -103,7 +124,7 @@ type ConditionEvaluatorMock_EvaluateRaw_Call struct {
// EvaluateRaw is a helper method to define mock.On call
// - ctx context.Context
// - now time.Time
func (_e *ConditionEvaluatorMock_Expecter) EvaluateRaw(ctx any, now any) *ConditionEvaluatorMock_EvaluateRaw_Call {
func (_e *ConditionEvaluatorMock_Expecter) EvaluateRaw(ctx interface{}, now interface{}) *ConditionEvaluatorMock_EvaluateRaw_Call {
return &ConditionEvaluatorMock_EvaluateRaw_Call{Call: _e.mock.On("EvaluateRaw", ctx, now)}
}
@@ -119,13 +140,17 @@ func (_c *ConditionEvaluatorMock_EvaluateRaw_Call) Return(resp *backend.QueryDat
return _c
}
type mockConstructorTestingTNewConditionEvaluatorMock interface {
mock.TestingT
Cleanup(func())
func (_c *ConditionEvaluatorMock_EvaluateRaw_Call) RunAndReturn(run func(context.Context, time.Time) (*backend.QueryDataResponse, error)) *ConditionEvaluatorMock_EvaluateRaw_Call {
_c.Call.Return(run)
return _c
}
// NewConditionEvaluatorMock creates a new instance of ConditionEvaluatorMock. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewConditionEvaluatorMock(t mockConstructorTestingTNewConditionEvaluatorMock) *ConditionEvaluatorMock {
// The first argument is typically a *testing.T value.
func NewConditionEvaluatorMock(t interface {
mock.TestingT
Cleanup(func())
}) *ConditionEvaluatorMock {
mock := &ConditionEvaluatorMock{}
mock.Mock.Test(t)
@@ -1,4 +1,4 @@
// Code generated by mockery v2.44.1. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package alertmanager_mock
@@ -585,7 +585,7 @@ func (_c *AlertmanagerMock_PutAlerts_Call) RunAndReturn(run func(context.Context
return _c
}
// Ready provides a mock function with given fields:
// Ready provides a mock function with no fields
func (_m *AlertmanagerMock) Ready() bool {
ret := _m.Called()
@@ -781,7 +781,7 @@ func (_c *AlertmanagerMock_SilenceState_Call) RunAndReturn(run func(context.Cont
return _c
}
// StopAndWait provides a mock function with given fields:
// StopAndWait provides a mock function with no fields
func (_m *AlertmanagerMock) StopAndWait() {
_m.Called()
}
@@ -809,7 +809,7 @@ func (_c *AlertmanagerMock_StopAndWait_Call) Return() *AlertmanagerMock_StopAndW
}
func (_c *AlertmanagerMock_StopAndWait_Call) RunAndReturn(run func()) *AlertmanagerMock_StopAndWait_Call {
_c.Call.Return(run)
_c.Run(run)
return _c
}
@@ -1,4 +1,4 @@
// Code generated by mockery v2.44.1. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package legacy_storage
@@ -1,4 +1,4 @@
// Code generated by mockery v2.34.2. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package provisioning
@@ -26,6 +26,10 @@ func (_m *MockProvisioningStore) EXPECT() *MockProvisioningStore_Expecter {
func (_m *MockProvisioningStore) DeleteProvenance(ctx context.Context, o models.Provisionable, org int64) error {
ret := _m.Called(ctx, o, org)
if len(ret) == 0 {
panic("no return value specified for DeleteProvenance")
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, models.Provisionable, int64) error); ok {
r0 = rf(ctx, o, org)
@@ -70,6 +74,10 @@ func (_c *MockProvisioningStore_DeleteProvenance_Call) RunAndReturn(run func(con
func (_m *MockProvisioningStore) GetProvenance(ctx context.Context, o models.Provisionable, org int64) (models.Provenance, error) {
ret := _m.Called(ctx, o, org)
if len(ret) == 0 {
panic("no return value specified for GetProvenance")
}
var r0 models.Provenance
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, models.Provisionable, int64) (models.Provenance, error)); ok {
@@ -124,6 +132,10 @@ func (_c *MockProvisioningStore_GetProvenance_Call) RunAndReturn(run func(contex
func (_m *MockProvisioningStore) GetProvenances(ctx context.Context, org int64, resourceType string) (map[string]models.Provenance, error) {
ret := _m.Called(ctx, org, resourceType)
if len(ret) == 0 {
panic("no return value specified for GetProvenances")
}
var r0 map[string]models.Provenance
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, int64, string) (map[string]models.Provenance, error)); ok {
@@ -180,6 +192,10 @@ func (_c *MockProvisioningStore_GetProvenances_Call) RunAndReturn(run func(conte
func (_m *MockProvisioningStore) SetProvenance(ctx context.Context, o models.Provisionable, org int64, p models.Provenance) error {
ret := _m.Called(ctx, o, org, p)
if len(ret) == 0 {
panic("no return value specified for SetProvenance")
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, models.Provisionable, int64, models.Provenance) error); ok {
r0 = rf(ctx, o, org, p)
@@ -1,4 +1,4 @@
// Code generated by mockery v2.34.2. DO NOT EDIT.
// Code generated by mockery v2.53.4. DO NOT EDIT.
package provisioning
@@ -26,6 +26,10 @@ func (_m *MockQuotaChecker) EXPECT() *MockQuotaChecker_Expecter {
func (_m *MockQuotaChecker) CheckQuotaReached(ctx context.Context, target quota.TargetSrv, scopeParams *quota.ScopeParameters) (bool, error) {
ret := _m.Called(ctx, target, scopeParams)
if len(ret) == 0 {
panic("no return value specified for CheckQuotaReached")
}
var r0 bool
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, quota.TargetSrv, *quota.ScopeParameters) (bool, error)); ok {

Some files were not shown because too many files have changed in this diff Show More