mirror of https://github.com/grafana/grafana.git
Merge remote-tracking branch 'origin/main' into copilot/rename-azuread-to-entraid
This commit is contained in:
commit
6ed6ffccec
|
|
@ -28,7 +28,7 @@ require (
|
|||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
golang.org/x/net v0.44.0 // indirect
|
||||
golang.org/x/text v0.29.0 // indirect
|
||||
google.golang.org/protobuf v1.36.8 // indirect
|
||||
google.golang.org/protobuf v1.36.9 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/klog/v2 v2.130.1 // indirect
|
||||
|
|
|
|||
|
|
@ -91,8 +91,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
|
|||
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/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
|
||||
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
|
||||
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/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=
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ require (
|
|||
google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 // indirect
|
||||
google.golang.org/grpc v1.75.1 // indirect
|
||||
google.golang.org/protobuf v1.36.8 // indirect
|
||||
google.golang.org/protobuf v1.36.9 // indirect
|
||||
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
|
|
|
|||
|
|
@ -284,8 +284,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090/go.
|
|||
google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
google.golang.org/grpc v1.75.1 h1:/ODCNEuf9VghjgO3rqLcfg8fiOP0nSluljWFlDxELLI=
|
||||
google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
|
||||
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
|
||||
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
|
||||
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/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=
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ require (
|
|||
google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 // indirect
|
||||
google.golang.org/grpc v1.75.1 // indirect
|
||||
google.golang.org/protobuf v1.36.8 // indirect
|
||||
google.golang.org/protobuf v1.36.9 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/api v0.34.1 // indirect
|
||||
|
|
|
|||
|
|
@ -203,8 +203,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 h1:
|
|||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090/go.mod h1:GmFNa4BdJZ2a8G+wCe9Bg3wwThLrJun751XstdJt5Og=
|
||||
google.golang.org/grpc v1.75.1 h1:/ODCNEuf9VghjgO3rqLcfg8fiOP0nSluljWFlDxELLI=
|
||||
google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
|
||||
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
|
||||
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
|
||||
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/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=
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ require (
|
|||
google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 // indirect
|
||||
google.golang.org/grpc v1.75.1 // indirect
|
||||
google.golang.org/protobuf v1.36.8 // indirect
|
||||
google.golang.org/protobuf v1.36.9 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/api v0.34.1 // indirect
|
||||
|
|
|
|||
|
|
@ -203,8 +203,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 h1:
|
|||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090/go.mod h1:GmFNa4BdJZ2a8G+wCe9Bg3wwThLrJun751XstdJt5Og=
|
||||
google.golang.org/grpc v1.75.1 h1:/ODCNEuf9VghjgO3rqLcfg8fiOP0nSluljWFlDxELLI=
|
||||
google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
|
||||
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
|
||||
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
|
||||
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/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=
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ go 1.24.6
|
|||
|
||||
require (
|
||||
cuelang.org/go v0.11.1
|
||||
github.com/grafana/authlib/types v0.0.0-20250917093142-83a502239781
|
||||
github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37
|
||||
github.com/grafana/grafana-app-sdk v0.45.0
|
||||
github.com/grafana/grafana-app-sdk/logging v0.45.0
|
||||
github.com/grafana/grafana-plugin-sdk-go v0.279.0
|
||||
|
|
@ -51,7 +51,7 @@ require (
|
|||
github.com/google/go-cmp v0.7.0 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/gorilla/mux v1.8.1 // indirect
|
||||
github.com/grafana/authlib v0.0.0-20250924100039-ea07223cdb6c // indirect
|
||||
github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f // indirect
|
||||
github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4 // indirect
|
||||
github.com/grafana/otel-profiling-go v0.5.1 // indirect
|
||||
github.com/grafana/pyroscope-go/godeltaprof v0.1.8 // indirect
|
||||
|
|
@ -134,7 +134,7 @@ require (
|
|||
google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 // indirect
|
||||
google.golang.org/grpc v1.75.1 // indirect
|
||||
google.golang.org/protobuf v1.36.8 // indirect
|
||||
google.golang.org/protobuf v1.36.9 // indirect
|
||||
gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
|
|
|
|||
|
|
@ -95,10 +95,10 @@ github.com/gopherjs/gopherjs v1.17.2 h1:fQnZVsXk8uxXIStYb0N4bGk7jeyTalG/wsZjQ25d
|
|||
github.com/gopherjs/gopherjs v1.17.2/go.mod h1:pRRIvn/QzFLrKfvEz3qUuEhtE/zLCWfreZ6J5gM2i+k=
|
||||
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
||||
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
||||
github.com/grafana/authlib v0.0.0-20250924100039-ea07223cdb6c h1:8GIMe1KclDdfogaeRsiU69Ev2zTF9kmjqjQqqZMzerc=
|
||||
github.com/grafana/authlib v0.0.0-20250924100039-ea07223cdb6c/go.mod h1:C6CmTG6vfiqebjJswKsc6zes+1F/OtTCi6aAtL5Um6A=
|
||||
github.com/grafana/authlib/types v0.0.0-20250917093142-83a502239781 h1:jymmOFIWnW26DeUjFgYEoltI170KeT5r1rI8a/dUf0E=
|
||||
github.com/grafana/authlib/types v0.0.0-20250917093142-83a502239781/go.mod h1:qeWYbnWzaYGl88JlL9+DsP1GT2Cudm58rLtx13fKZdw=
|
||||
github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f h1:Cbm6OKkOcJ+7CSZsGsEJzktC/SIa5bxVeYKQLuYK86o=
|
||||
github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f/go.mod h1:axY0cdOg3q0TZHwpHnIz5x16xZ8ZBxJHShsSHHXcHQg=
|
||||
github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37 h1:qEwZ+7MbPjzRvTi31iT9w7NBhKIpKwZrFbYmOZLqkwA=
|
||||
github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37/go.mod h1:qeWYbnWzaYGl88JlL9+DsP1GT2Cudm58rLtx13fKZdw=
|
||||
github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4 h1:jSojuc7njleS3UOz223WDlXOinmuLAIPI0z2vtq8EgI=
|
||||
github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4/go.mod h1:VahT+GtfQIM+o8ht2StR6J9g+Ef+C2Vokh5uuSmOD/4=
|
||||
github.com/grafana/grafana-app-sdk v0.45.0 h1:niFqYovxuw9vnUB9qoxEgmupqriG7Gns9ZGwB2uuOyE=
|
||||
|
|
@ -386,8 +386,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 h1:
|
|||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090/go.mod h1:GmFNa4BdJZ2a8G+wCe9Bg3wwThLrJun751XstdJt5Og=
|
||||
google.golang.org/grpc v1.75.1 h1:/ODCNEuf9VghjgO3rqLcfg8fiOP0nSluljWFlDxELLI=
|
||||
google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
|
||||
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
|
||||
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
|
||||
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/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=
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ require (
|
|||
golang.org/x/term v0.35.0 // indirect
|
||||
golang.org/x/text v0.29.0 // indirect
|
||||
golang.org/x/time v0.13.0 // indirect
|
||||
google.golang.org/protobuf v1.36.8 // indirect
|
||||
google.golang.org/protobuf v1.36.9 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/client-go v0.34.1 // indirect
|
||||
|
|
|
|||
|
|
@ -152,8 +152,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
|
|||
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/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
|
||||
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
|
||||
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/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=
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ replace github.com/grafana/grafana/pkg/aggregator => ../../pkg/aggregator
|
|||
replace github.com/prometheus/alertmanager => github.com/grafana/prometheus-alertmanager v0.25.1-0.20250911094103-5456b6e45604
|
||||
|
||||
require (
|
||||
github.com/grafana/grafana v6.1.6+incompatible
|
||||
github.com/grafana/grafana v0.0.0-00010101000000-000000000000
|
||||
github.com/grafana/grafana-app-sdk v0.45.0
|
||||
github.com/grafana/grafana-app-sdk/logging v0.45.0
|
||||
github.com/grafana/grafana/apps/folder v0.0.0
|
||||
|
|
@ -202,8 +202,8 @@ require (
|
|||
github.com/googleapis/gax-go/v2 v2.14.2 // indirect
|
||||
github.com/gorilla/mux v1.8.1 // indirect
|
||||
github.com/grafana/alerting v0.0.0-20250925200825-7a889aa4934d // indirect
|
||||
github.com/grafana/authlib v0.0.0-20250924100039-ea07223cdb6c // indirect
|
||||
github.com/grafana/authlib/types v0.0.0-20250917093142-83a502239781 // indirect
|
||||
github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f // indirect
|
||||
github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37 // indirect
|
||||
github.com/grafana/dataplane/sdata v0.0.9 // indirect
|
||||
github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4 // indirect
|
||||
github.com/grafana/grafana-aws-sdk v1.2.0 // indirect
|
||||
|
|
@ -422,7 +422,7 @@ require (
|
|||
google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 // indirect
|
||||
google.golang.org/grpc v1.75.1 // indirect
|
||||
google.golang.org/protobuf v1.36.8 // indirect
|
||||
google.golang.org/protobuf v1.36.9 // indirect
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
|
||||
gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect
|
||||
|
|
|
|||
|
|
@ -723,10 +723,10 @@ github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5T
|
|||
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA=
|
||||
github.com/grafana/alerting v0.0.0-20250925200825-7a889aa4934d h1:zzEty7HgfXbQ/RiBCJFMqaZiJlqiXuz/Zbc6/H6ksuM=
|
||||
github.com/grafana/alerting v0.0.0-20250925200825-7a889aa4934d/go.mod h1:T5sitas9VhVj8/S9LeRLy6H75kTBdh/sCCqHo7gaQI8=
|
||||
github.com/grafana/authlib v0.0.0-20250924100039-ea07223cdb6c h1:8GIMe1KclDdfogaeRsiU69Ev2zTF9kmjqjQqqZMzerc=
|
||||
github.com/grafana/authlib v0.0.0-20250924100039-ea07223cdb6c/go.mod h1:C6CmTG6vfiqebjJswKsc6zes+1F/OtTCi6aAtL5Um6A=
|
||||
github.com/grafana/authlib/types v0.0.0-20250917093142-83a502239781 h1:jymmOFIWnW26DeUjFgYEoltI170KeT5r1rI8a/dUf0E=
|
||||
github.com/grafana/authlib/types v0.0.0-20250917093142-83a502239781/go.mod h1:qeWYbnWzaYGl88JlL9+DsP1GT2Cudm58rLtx13fKZdw=
|
||||
github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f h1:Cbm6OKkOcJ+7CSZsGsEJzktC/SIa5bxVeYKQLuYK86o=
|
||||
github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f/go.mod h1:axY0cdOg3q0TZHwpHnIz5x16xZ8ZBxJHShsSHHXcHQg=
|
||||
github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37 h1:qEwZ+7MbPjzRvTi31iT9w7NBhKIpKwZrFbYmOZLqkwA=
|
||||
github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37/go.mod h1:qeWYbnWzaYGl88JlL9+DsP1GT2Cudm58rLtx13fKZdw=
|
||||
github.com/grafana/dataplane/examples v0.0.1 h1:K9M5glueWyLoL4//H+EtTQq16lXuHLmOhb6DjSCahzA=
|
||||
github.com/grafana/dataplane/examples v0.0.1/go.mod h1:h5YwY8s407/17XF5/dS8XrUtsTVV2RnuW8+m1Mp46mg=
|
||||
github.com/grafana/dataplane/sdata v0.0.9 h1:AGL1LZnCUG4MnQtnWpBPbQ8ZpptaZs14w6kE/MWfg7s=
|
||||
|
|
@ -1994,8 +1994,8 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
|
|||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
|
||||
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
|
||||
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ require (
|
|||
google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 // indirect
|
||||
google.golang.org/grpc v1.75.1 // indirect
|
||||
google.golang.org/protobuf v1.36.8 // indirect
|
||||
google.golang.org/protobuf v1.36.9 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/api v0.34.1 // indirect
|
||||
|
|
|
|||
|
|
@ -203,8 +203,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 h1:
|
|||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090/go.mod h1:GmFNa4BdJZ2a8G+wCe9Bg3wwThLrJun751XstdJt5Og=
|
||||
google.golang.org/grpc v1.75.1 h1:/ODCNEuf9VghjgO3rqLcfg8fiOP0nSluljWFlDxELLI=
|
||||
google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
|
||||
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
|
||||
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
|
||||
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/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=
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ require (
|
|||
google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 // indirect
|
||||
google.golang.org/grpc v1.75.1 // indirect
|
||||
google.golang.org/protobuf v1.36.8 // indirect
|
||||
google.golang.org/protobuf v1.36.9 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/api v0.34.1 // indirect
|
||||
|
|
|
|||
|
|
@ -203,8 +203,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 h1:
|
|||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090/go.mod h1:GmFNa4BdJZ2a8G+wCe9Bg3wwThLrJun751XstdJt5Og=
|
||||
google.golang.org/grpc v1.75.1 h1:/ODCNEuf9VghjgO3rqLcfg8fiOP0nSluljWFlDxELLI=
|
||||
google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
|
||||
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
|
||||
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
|
||||
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/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=
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ module github.com/grafana/grafana/apps/plugins
|
|||
go 1.24.4
|
||||
|
||||
require (
|
||||
github.com/grafana/authlib/types v0.0.0-20250917093142-83a502239781
|
||||
github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37
|
||||
github.com/grafana/grafana-app-sdk v0.45.0
|
||||
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250428110029-a8ea72012bde
|
||||
k8s.io/apimachinery v0.34.1
|
||||
|
|
@ -35,7 +35,7 @@ require (
|
|||
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/grafana/authlib v0.0.0-20250924100039-ea07223cdb6c // indirect
|
||||
github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f // indirect
|
||||
github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4 // indirect
|
||||
github.com/grafana/grafana-app-sdk/logging v0.45.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect
|
||||
|
|
@ -86,7 +86,7 @@ require (
|
|||
google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 // indirect
|
||||
google.golang.org/grpc v1.75.1 // indirect
|
||||
google.golang.org/protobuf v1.36.8 // indirect
|
||||
google.golang.org/protobuf v1.36.9 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/api v0.34.1 // indirect
|
||||
|
|
|
|||
|
|
@ -50,10 +50,10 @@ github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J
|
|||
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/grafana/authlib v0.0.0-20250924100039-ea07223cdb6c h1:8GIMe1KclDdfogaeRsiU69Ev2zTF9kmjqjQqqZMzerc=
|
||||
github.com/grafana/authlib v0.0.0-20250924100039-ea07223cdb6c/go.mod h1:C6CmTG6vfiqebjJswKsc6zes+1F/OtTCi6aAtL5Um6A=
|
||||
github.com/grafana/authlib/types v0.0.0-20250917093142-83a502239781 h1:jymmOFIWnW26DeUjFgYEoltI170KeT5r1rI8a/dUf0E=
|
||||
github.com/grafana/authlib/types v0.0.0-20250917093142-83a502239781/go.mod h1:qeWYbnWzaYGl88JlL9+DsP1GT2Cudm58rLtx13fKZdw=
|
||||
github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f h1:Cbm6OKkOcJ+7CSZsGsEJzktC/SIa5bxVeYKQLuYK86o=
|
||||
github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f/go.mod h1:axY0cdOg3q0TZHwpHnIz5x16xZ8ZBxJHShsSHHXcHQg=
|
||||
github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37 h1:qEwZ+7MbPjzRvTi31iT9w7NBhKIpKwZrFbYmOZLqkwA=
|
||||
github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37/go.mod h1:qeWYbnWzaYGl88JlL9+DsP1GT2Cudm58rLtx13fKZdw=
|
||||
github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4 h1:jSojuc7njleS3UOz223WDlXOinmuLAIPI0z2vtq8EgI=
|
||||
github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4/go.mod h1:VahT+GtfQIM+o8ht2StR6J9g+Ef+C2Vokh5uuSmOD/4=
|
||||
github.com/grafana/grafana-app-sdk v0.45.0 h1:niFqYovxuw9vnUB9qoxEgmupqriG7Gns9ZGwB2uuOyE=
|
||||
|
|
@ -219,8 +219,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 h1:
|
|||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090/go.mod h1:GmFNa4BdJZ2a8G+wCe9Bg3wwThLrJun751XstdJt5Og=
|
||||
google.golang.org/grpc v1.75.1 h1:/ODCNEuf9VghjgO3rqLcfg8fiOP0nSluljWFlDxELLI=
|
||||
google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
|
||||
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
|
||||
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
|
||||
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/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=
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ require (
|
|||
golang.org/x/term v0.35.0 // indirect
|
||||
golang.org/x/text v0.29.0 // indirect
|
||||
golang.org/x/time v0.13.0 // indirect
|
||||
google.golang.org/protobuf v1.36.8 // indirect
|
||||
google.golang.org/protobuf v1.36.9 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/client-go v0.34.1 // indirect
|
||||
|
|
|
|||
|
|
@ -152,8 +152,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
|
|||
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/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
|
||||
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
|
||||
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/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=
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ go 1.24.6
|
|||
require (
|
||||
github.com/google/go-github/v70 v70.0.0
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/grafana/authlib v0.0.0-20250924100039-ea07223cdb6c
|
||||
github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f
|
||||
github.com/grafana/grafana-app-sdk/logging v0.45.0
|
||||
github.com/grafana/grafana/apps/secret v0.0.0-20250902093454-b56b7add012f
|
||||
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250804150913-990f1c69ecc2
|
||||
|
|
@ -40,7 +40,7 @@ require (
|
|||
github.com/google/go-github/v64 v64.0.0 // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/gorilla/mux v1.8.1 // indirect
|
||||
github.com/grafana/authlib/types v0.0.0-20250917093142-83a502239781 // indirect
|
||||
github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37 // indirect
|
||||
github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4 // indirect
|
||||
github.com/grafana/grafana-app-sdk v0.45.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
|
|
@ -75,7 +75,7 @@ require (
|
|||
golang.org/x/time v0.13.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 // indirect
|
||||
google.golang.org/grpc v1.75.1 // indirect
|
||||
google.golang.org/protobuf v1.36.8 // indirect
|
||||
google.golang.org/protobuf v1.36.9 // indirect
|
||||
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
|
|
|
|||
|
|
@ -52,10 +52,10 @@ 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/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
||||
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
||||
github.com/grafana/authlib v0.0.0-20250924100039-ea07223cdb6c h1:8GIMe1KclDdfogaeRsiU69Ev2zTF9kmjqjQqqZMzerc=
|
||||
github.com/grafana/authlib v0.0.0-20250924100039-ea07223cdb6c/go.mod h1:C6CmTG6vfiqebjJswKsc6zes+1F/OtTCi6aAtL5Um6A=
|
||||
github.com/grafana/authlib/types v0.0.0-20250917093142-83a502239781 h1:jymmOFIWnW26DeUjFgYEoltI170KeT5r1rI8a/dUf0E=
|
||||
github.com/grafana/authlib/types v0.0.0-20250917093142-83a502239781/go.mod h1:qeWYbnWzaYGl88JlL9+DsP1GT2Cudm58rLtx13fKZdw=
|
||||
github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f h1:Cbm6OKkOcJ+7CSZsGsEJzktC/SIa5bxVeYKQLuYK86o=
|
||||
github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f/go.mod h1:axY0cdOg3q0TZHwpHnIz5x16xZ8ZBxJHShsSHHXcHQg=
|
||||
github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37 h1:qEwZ+7MbPjzRvTi31iT9w7NBhKIpKwZrFbYmOZLqkwA=
|
||||
github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37/go.mod h1:qeWYbnWzaYGl88JlL9+DsP1GT2Cudm58rLtx13fKZdw=
|
||||
github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4 h1:jSojuc7njleS3UOz223WDlXOinmuLAIPI0z2vtq8EgI=
|
||||
github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4/go.mod h1:VahT+GtfQIM+o8ht2StR6J9g+Ef+C2Vokh5uuSmOD/4=
|
||||
github.com/grafana/grafana-app-sdk v0.45.0 h1:niFqYovxuw9vnUB9qoxEgmupqriG7Gns9ZGwB2uuOyE=
|
||||
|
|
@ -224,8 +224,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 h1:
|
|||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090/go.mod h1:GmFNa4BdJZ2a8G+wCe9Bg3wwThLrJun751XstdJt5Og=
|
||||
google.golang.org/grpc v1.75.1 h1:/ODCNEuf9VghjgO3rqLcfg8fiOP0nSluljWFlDxELLI=
|
||||
google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
|
||||
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
|
||||
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
|
||||
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/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=
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import (
|
|||
// API errors that we need to convey after parsing real GH errors (or faking them).
|
||||
var (
|
||||
ErrResourceNotFound = errors.New("the resource does not exist")
|
||||
ErrUnauthorized = errors.New("unauthorized")
|
||||
//lint:ignore ST1005 this is not punctuation
|
||||
ErrServiceUnavailable = apierrors.NewServiceUnavailable("github is unavailable")
|
||||
ErrTooManyItems = errors.New("maximum number of items exceeded")
|
||||
|
|
|
|||
|
|
@ -199,6 +199,9 @@ func (r *githubClient) DeleteWebhook(ctx context.Context, owner, repository stri
|
|||
if ghErr.Response.StatusCode == http.StatusNotFound {
|
||||
return ErrResourceNotFound
|
||||
}
|
||||
if ghErr.Response.StatusCode == http.StatusUnauthorized || ghErr.Response.StatusCode == http.StatusForbidden {
|
||||
return ErrUnauthorized
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -975,6 +975,27 @@ func TestGithubClient_DeleteWebhook(t *testing.T) {
|
|||
webhookID: 789,
|
||||
wantErr: ErrServiceUnavailable,
|
||||
},
|
||||
{
|
||||
name: "unauthorized to delete the webhook",
|
||||
mockHandler: mockhub.NewMockedHTTPClient(
|
||||
mockhub.WithRequestMatchHandler(
|
||||
mockhub.DeleteReposHooksByOwnerByRepoByHookId,
|
||||
http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
require.NoError(t, json.NewEncoder(w).Encode(github.ErrorResponse{
|
||||
Response: &http.Response{
|
||||
StatusCode: http.StatusUnauthorized,
|
||||
},
|
||||
Message: "401 bad credentials",
|
||||
}))
|
||||
}),
|
||||
),
|
||||
),
|
||||
owner: "test-owner",
|
||||
repository: "test-repo",
|
||||
webhookID: 789,
|
||||
wantErr: ErrUnauthorized,
|
||||
},
|
||||
{
|
||||
name: "other error",
|
||||
mockHandler: mockhub.NewMockedHTTPClient(
|
||||
|
|
|
|||
|
|
@ -274,11 +274,15 @@ func (r *githubWebhookRepository) deleteWebhook(ctx context.Context) error {
|
|||
id := r.config.Status.Webhook.ID
|
||||
|
||||
err := r.gh.DeleteWebhook(ctx, r.owner, r.repo, id)
|
||||
if err != nil && !errors.Is(err, ErrResourceNotFound) {
|
||||
if err != nil && !errors.Is(err, ErrResourceNotFound) && !errors.Is(err, ErrUnauthorized) {
|
||||
return fmt.Errorf("delete webhook: %w", err)
|
||||
}
|
||||
if errors.Is(err, ErrResourceNotFound) {
|
||||
logger.Info("webhook does not exist", "url", r.config.Status.Webhook.URL, "id", id)
|
||||
logger.Warn("webhook no longer exists", "url", r.config.Status.Webhook.URL, "id", id)
|
||||
return nil
|
||||
}
|
||||
if errors.Is(err, ErrUnauthorized) {
|
||||
logger.Warn("webhook deletion failed. no longer authorized to delete this webhook", "url", r.config.Status.Webhook.URL, "id", id)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1565,6 +1565,32 @@ func TestGitHubRepository_OnDelete(t *testing.T) {
|
|||
// We don't return an error if the webhook is already gone
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "unauthorized to delete the webhook",
|
||||
setupMock: func(m *MockClient) {
|
||||
m.On("DeleteWebhook", mock.Anything, "grafana", "grafana", int64(123)).
|
||||
Return(ErrUnauthorized)
|
||||
},
|
||||
config: &provisioning.Repository{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-repo",
|
||||
},
|
||||
Spec: provisioning.RepositorySpec{
|
||||
GitHub: &provisioning.GitHubRepositoryConfig{
|
||||
Branch: "main",
|
||||
},
|
||||
},
|
||||
Status: provisioning.RepositoryStatus{
|
||||
Webhook: &provisioning.WebhookStatus{
|
||||
ID: 123,
|
||||
URL: "https://example.com/webhook",
|
||||
},
|
||||
},
|
||||
},
|
||||
webhookURL: "https://example.com/webhook",
|
||||
// We don't return an error if access to the webhook is revoked
|
||||
expectedError: nil,
|
||||
},
|
||||
{
|
||||
name: "no webhook URL provided",
|
||||
setupMock: func(_ *MockClient) {},
|
||||
|
|
|
|||
|
|
@ -75,11 +75,6 @@ func ValidateRepository(repo Repository) field.ErrorList {
|
|||
"The target type is required when sync is enabled"))
|
||||
}
|
||||
|
||||
if cfg.Spec.Sync.Enabled && cfg.Spec.Sync.IntervalSeconds < 10 {
|
||||
list = append(list, field.Invalid(field.NewPath("spec", "sync", "intervalSeconds"),
|
||||
cfg.Spec.Sync.IntervalSeconds, fmt.Sprintf("Interval must be at least %d seconds", 10)))
|
||||
}
|
||||
|
||||
// Reserved names (for now)
|
||||
reserved := []string{"classic", "sql", "SQL", "plugins", "legacy", "new", "job", "github", "s3", "gcs", "file", "new", "create", "update", "delete"}
|
||||
if slices.Contains(reserved, cfg.Name) {
|
||||
|
|
|
|||
|
|
@ -74,28 +74,6 @@ func TestValidateRepository(t *testing.T) {
|
|||
require.Contains(t, errors.ToAggregate().Error(), "spec.sync.target: Required value")
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "sync interval too low",
|
||||
repository: func() *MockRepository {
|
||||
m := NewMockRepository(t)
|
||||
m.On("Config").Return(&provisioning.Repository{
|
||||
Spec: provisioning.RepositorySpec{
|
||||
Title: "Test Repo",
|
||||
Sync: provisioning.SyncOptions{
|
||||
Enabled: true,
|
||||
Target: "test",
|
||||
IntervalSeconds: 5,
|
||||
},
|
||||
},
|
||||
})
|
||||
m.On("Validate").Return(field.ErrorList{})
|
||||
return m
|
||||
}(),
|
||||
expectedErrs: 1,
|
||||
validateError: func(t *testing.T, errors field.ErrorList) {
|
||||
require.Contains(t, errors.ToAggregate().Error(), "spec.sync.intervalSeconds: Invalid value")
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "reserved name",
|
||||
repository: func() *MockRepository {
|
||||
|
|
@ -191,11 +169,10 @@ func TestValidateRepository(t *testing.T) {
|
|||
m.On("Validate").Return(field.ErrorList{})
|
||||
return m
|
||||
}(),
|
||||
expectedErrs: 4, // Updated from 3 to 4 to match actual errors:
|
||||
expectedErrs: 3,
|
||||
// 1. missing title
|
||||
// 2. sync target missing
|
||||
// 3. sync interval too low
|
||||
// 4. reserved name
|
||||
// 3. reserved name
|
||||
},
|
||||
{
|
||||
name: "branch workflow for non-github repository",
|
||||
|
|
@ -447,18 +424,6 @@ func TestFromFieldError(t *testing.T) {
|
|||
expectedType: metav1.CauseTypeFieldValueRequired,
|
||||
expectedDetail: "a repository title must be given",
|
||||
},
|
||||
{
|
||||
name: "invalid field error",
|
||||
fieldError: &field.Error{
|
||||
Type: field.ErrorTypeInvalid,
|
||||
Field: "spec.sync.intervalSeconds",
|
||||
Detail: "Interval must be at least 10 seconds",
|
||||
},
|
||||
expectedCode: http.StatusBadRequest,
|
||||
expectedField: "spec.sync.intervalSeconds",
|
||||
expectedType: metav1.CauseTypeFieldValueInvalid,
|
||||
expectedDetail: "Interval must be at least 10 seconds",
|
||||
},
|
||||
{
|
||||
name: "not supported field error",
|
||||
fieldError: &field.Error{
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ require (
|
|||
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250710134100-1f3dc0533caf
|
||||
github.com/stretchr/testify v1.11.1
|
||||
google.golang.org/grpc v1.75.1
|
||||
google.golang.org/protobuf v1.36.8
|
||||
google.golang.org/protobuf v1.36.9
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
k8s.io/apimachinery v0.34.1
|
||||
k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b
|
||||
|
|
|
|||
|
|
@ -170,8 +170,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 h1:
|
|||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090/go.mod h1:GmFNa4BdJZ2a8G+wCe9Bg3wwThLrJun751XstdJt5Og=
|
||||
google.golang.org/grpc v1.75.1 h1:/ODCNEuf9VghjgO3rqLcfg8fiOP0nSluljWFlDxELLI=
|
||||
google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
|
||||
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
|
||||
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
|
||||
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/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=
|
||||
|
|
|
|||
|
|
@ -33,8 +33,8 @@ require (
|
|||
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/grafana/authlib v0.0.0-20250924100039-ea07223cdb6c // indirect
|
||||
github.com/grafana/authlib/types v0.0.0-20250917093142-83a502239781 // indirect
|
||||
github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f // indirect
|
||||
github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37 // indirect
|
||||
github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
|
|
@ -84,7 +84,7 @@ require (
|
|||
google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 // indirect
|
||||
google.golang.org/grpc v1.75.1 // indirect
|
||||
google.golang.org/protobuf v1.36.8 // indirect
|
||||
google.golang.org/protobuf v1.36.9 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/api v0.34.1 // indirect
|
||||
|
|
|
|||
|
|
@ -48,10 +48,10 @@ github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J
|
|||
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/grafana/authlib v0.0.0-20250924100039-ea07223cdb6c h1:8GIMe1KclDdfogaeRsiU69Ev2zTF9kmjqjQqqZMzerc=
|
||||
github.com/grafana/authlib v0.0.0-20250924100039-ea07223cdb6c/go.mod h1:C6CmTG6vfiqebjJswKsc6zes+1F/OtTCi6aAtL5Um6A=
|
||||
github.com/grafana/authlib/types v0.0.0-20250917093142-83a502239781 h1:jymmOFIWnW26DeUjFgYEoltI170KeT5r1rI8a/dUf0E=
|
||||
github.com/grafana/authlib/types v0.0.0-20250917093142-83a502239781/go.mod h1:qeWYbnWzaYGl88JlL9+DsP1GT2Cudm58rLtx13fKZdw=
|
||||
github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f h1:Cbm6OKkOcJ+7CSZsGsEJzktC/SIa5bxVeYKQLuYK86o=
|
||||
github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f/go.mod h1:axY0cdOg3q0TZHwpHnIz5x16xZ8ZBxJHShsSHHXcHQg=
|
||||
github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37 h1:qEwZ+7MbPjzRvTi31iT9w7NBhKIpKwZrFbYmOZLqkwA=
|
||||
github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37/go.mod h1:qeWYbnWzaYGl88JlL9+DsP1GT2Cudm58rLtx13fKZdw=
|
||||
github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4 h1:jSojuc7njleS3UOz223WDlXOinmuLAIPI0z2vtq8EgI=
|
||||
github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4/go.mod h1:VahT+GtfQIM+o8ht2StR6J9g+Ef+C2Vokh5uuSmOD/4=
|
||||
github.com/grafana/grafana-app-sdk v0.45.0 h1:niFqYovxuw9vnUB9qoxEgmupqriG7Gns9ZGwB2uuOyE=
|
||||
|
|
@ -217,8 +217,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 h1:
|
|||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090/go.mod h1:GmFNa4BdJZ2a8G+wCe9Bg3wwThLrJun751XstdJt5Og=
|
||||
google.golang.org/grpc v1.75.1 h1:/ODCNEuf9VghjgO3rqLcfg8fiOP0nSluljWFlDxELLI=
|
||||
google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
|
||||
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
|
||||
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
|
||||
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/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=
|
||||
|
|
|
|||
|
|
@ -2229,3 +2229,8 @@ allowed_targets = instance|folder
|
|||
# Whether image rendering is allowed for dashboard previews.
|
||||
# Requires image rendering service to be configured.
|
||||
allow_image_rendering = true
|
||||
|
||||
# The minimum sync interval that can be set for a repository. This is how often the controller
|
||||
# will check if there has been any changes to the repository not propagated by a webhook.
|
||||
# The minimum value is 10 seconds.
|
||||
min_sync_interval = 10s
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ labels:
|
|||
- cloud
|
||||
- enterprise
|
||||
- oss
|
||||
menuTitle: Modify dashboard settings
|
||||
title: Modify dashboard settings
|
||||
description: Manage and edit your dashboard settings
|
||||
weight: 8
|
||||
|
|
@ -56,7 +55,7 @@ To access the dashboard setting page:
|
|||
|
||||
Adjust dashboard time settings when you want to change the dashboard timezone, the local browser time, and specify auto-refresh time intervals.
|
||||
|
||||
1. On the **Settings** page, scroll down to the **Time Options** section of the **General** tab.
|
||||
1. On the the **General** tab of the **Settings** page, scroll down to the **Time options** section.
|
||||
1. Specify time settings as follows.
|
||||
- **Time zone:** Specify the local time zone of the service or system that you are monitoring. This can be helpful when monitoring a system or service that operates across several time zones.
|
||||
- **Default:** Grafana uses the default selected time zone for the user profile, team, or organization. If no time zone is specified for the user profile, a team the user is a member of, or the organization, then Grafana uses the local browser time.
|
||||
|
|
@ -71,6 +70,21 @@ Adjust dashboard time settings when you want to change the dashboard timezone, t
|
|||
1. Click **Save**.
|
||||
1. Click **Exit edit**.
|
||||
|
||||
## Modify graph tooltip behavior
|
||||
|
||||
Use this option to control tooltip and hover highlight behavior across graph panels (for example, time series).
|
||||
|
||||
1. On the the **General** tab of the **Settings** page, scroll down to the **Panel options** section.
|
||||
1. Choose from the following options to control the tooltip and hover highlight behavior across graph panels:
|
||||
- **Default** - Tooltip and hover highlight behavior isn't shared across panels.
|
||||
- **Shared crosshair** - When you hover the cursor over one graph panel in the dashboard, the crosshair is also displayed on all other graph panels in the dashboard.
|
||||
- **Shared tooltip** - When you hover the cursor over one graph panel in the dashboard, the crosshair and tooltips are also displayed on all other graph panels in the dashboard.
|
||||
|
||||
1. Click **Save dashboard**.
|
||||
1. (Optional) Enter a description of the changes you've made.
|
||||
1. Click **Save**.
|
||||
1. Click **Exit edit**.
|
||||
|
||||
## Add tags
|
||||
|
||||
You can add metadata to your dashboards using tags. Tags also give you the ability to filter the list of dashboards.
|
||||
|
|
@ -79,7 +93,7 @@ Tags can be up to 50 characters long, including spaces.
|
|||
|
||||
To add tags to a dashboard, follow these steps:
|
||||
|
||||
1. On the **Settings** page, scroll down to the **Tags** section of the **General** tab.
|
||||
1. On the the **General** tab of the **Settings** page, scroll down to the **Tags** section.
|
||||
1. In the field, enter a new or existing tag.
|
||||
|
||||
If you're entering an existing tag, make sure that you spell it the same way or a new tag is created.
|
||||
|
|
|
|||
|
|
@ -452,24 +452,28 @@ This transformation is very useful if your data source does not natively filter
|
|||
|
||||
The available conditions for all fields are:
|
||||
|
||||
- **Regex** - Match a regex expression.
|
||||
- **Is Null** - Match if the value is null.
|
||||
- **Is Not Null** - Match if the value is not null.
|
||||
- **Equal** - Match if the value is equal to the specified value.
|
||||
- **Different** - Match if the value is different than the specified value.
|
||||
- **Not Equal** - Match if the value is not equal to the specified value.
|
||||
- **Regex** - Match a regex expression.
|
||||
|
||||
The available conditions for string fields are:
|
||||
|
||||
- **Contains substring** - Match if the value contains the specified substring (case insensitive).
|
||||
- **Does not contain substring** - Match if the value doesn't contain the specified substring (case insensitive).
|
||||
|
||||
The available conditions for number and time fields are:
|
||||
The available conditions for number fields are:
|
||||
|
||||
- **Greater** - Match if the value is greater than the specified value.
|
||||
- **Lower** - Match if the value is lower than the specified value.
|
||||
- **Greater or equal** - Match if the value is greater or equal.
|
||||
- **Lower or equal** - Match if the value is lower or equal.
|
||||
- **Range** - Match a range between a specified minimum and maximum, min and max included. A time field will pre-populate with variables to filter by selected time.
|
||||
- **In between** - Match a range between a specified minimum and maximum, min and max included.
|
||||
|
||||
The available conditions for time fields are:
|
||||
|
||||
- **In between** - Match a range between a specified minimum and maximum. The min and max values will pre-populate with variables to filter by selected time.
|
||||
|
||||
Consider the following dataset:
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ description: Learn how to integrate Grafana with Hashicorp Vault so that you can
|
|||
labels:
|
||||
products:
|
||||
- enterprise
|
||||
- oss
|
||||
title: Integrate Grafana with Hashicorp Vault
|
||||
weight: 500
|
||||
---
|
||||
|
|
|
|||
|
|
@ -223,7 +223,7 @@ Team provisioning requires `group_sync_enabled = true` in the SCIM configuration
|
|||
{{< /admonition >}}
|
||||
|
||||
{{< admonition type="warning" >}}
|
||||
Teams provisioned through SCIM cannot be deleted manually from Grafana - they can only be deleted by removing their corresponding groups from the identity provider.
|
||||
Teams provisioned through SCIM cannot be deleted manually from Grafana - they can only be deleted by removing their corresponding groups from the identity provider. Optionally, you can disable SCIM group sync to allow manual deletion of teams.
|
||||
{{< /admonition >}}
|
||||
|
||||
For detailed configuration steps specific to the identity provider, see:
|
||||
|
|
|
|||
|
|
@ -598,7 +598,7 @@
|
|||
"auth-validator",
|
||||
"config-loader",
|
||||
"config-writer",
|
||||
"metrics-collector",
|
||||
"metrics-collector-last-span",
|
||||
"log-writer",
|
||||
"log-reader",
|
||||
"event-publisher",
|
||||
|
|
|
|||
|
|
@ -2,11 +2,6 @@ import { test, expect } from '@grafana/plugin-e2e';
|
|||
|
||||
import longTraceResponse from '../fixtures/long-trace-response.json';
|
||||
|
||||
// this test requires a larger viewport
|
||||
test.use({
|
||||
viewport: { width: 1280, height: 1080 },
|
||||
});
|
||||
|
||||
test.describe(
|
||||
'Trace view',
|
||||
{
|
||||
|
|
@ -33,7 +28,7 @@ test.describe(
|
|||
await datasourceList.getByText('gdev-jaeger').click();
|
||||
|
||||
// Check that gdev-jaeger is visible in the query editor
|
||||
await expect(page.getByText('gdev-jaeger')).toBeVisible();
|
||||
await expect(page.getByTestId('query-editor-row').getByText('(gdev-jaeger)')).toBeVisible();
|
||||
|
||||
// Type the query
|
||||
const queryField = page
|
||||
|
|
@ -44,14 +39,22 @@ test.describe(
|
|||
// Use Shift+Enter to execute the query
|
||||
await queryField.press('Shift+Enter');
|
||||
|
||||
// Get the initial count of span bars
|
||||
const initialSpanBars = page.getByTestId(selectors.components.TraceViewer.spanBar);
|
||||
const initialSpanBarCount = await initialSpanBars.count();
|
||||
// Wait for the trace viewer to be ready
|
||||
await expect(page.getByRole('switch', { name: /api\-gateway GET/ })).toBeVisible();
|
||||
|
||||
await initialSpanBars.last().scrollIntoViewIfNeeded();
|
||||
await expect
|
||||
.poll(async () => await page.getByTestId(selectors.components.TraceViewer.spanBar).count())
|
||||
.toBeGreaterThan(initialSpanBarCount);
|
||||
// Note the scrolling element is actually the first child of the scroll view, but we can use the scroll wheel on this anyway
|
||||
const scrollEl = page.getByTestId(selectors.pages.Explore.General.scrollView);
|
||||
|
||||
// Assert that the last span is not visible in th page - it should be lazily rendered as the user scrolls
|
||||
const lastSpan = page.getByRole('switch', { name: /metrics\-collector\-last\-span GET/ });
|
||||
await expect(lastSpan).not.toBeVisible();
|
||||
|
||||
// Scroll until the "metrics-collector-last-span GET" switch is visible
|
||||
await expect(async () => {
|
||||
await scrollEl.hover();
|
||||
await page.mouse.wheel(0, 1000);
|
||||
await expect(lastSpan).toBeVisible({ timeout: 1 });
|
||||
}).toPass();
|
||||
});
|
||||
}
|
||||
);
|
||||
|
|
|
|||
6
go.mod
6
go.mod
|
|
@ -87,8 +87,8 @@ require (
|
|||
github.com/gorilla/mux v1.8.1 // @grafana/grafana-backend-group
|
||||
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // @grafana/grafana-app-platform-squad
|
||||
github.com/grafana/alerting v0.0.0-20250925200825-7a889aa4934d // @grafana/alerting-backend
|
||||
github.com/grafana/authlib v0.0.0-20250924100039-ea07223cdb6c // @grafana/identity-access-team
|
||||
github.com/grafana/authlib/types v0.0.0-20250917093142-83a502239781 // @grafana/identity-access-team
|
||||
github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f // @grafana/identity-access-team
|
||||
github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37 // @grafana/identity-access-team
|
||||
github.com/grafana/dataplane/examples v0.0.1 // @grafana/observability-metrics
|
||||
github.com/grafana/dataplane/sdata v0.0.9 // @grafana/observability-metrics
|
||||
github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4 // @grafana/grafana-backend-group
|
||||
|
|
@ -211,7 +211,7 @@ require (
|
|||
gonum.org/v1/gonum v0.16.0 // @grafana/oss-big-tent
|
||||
google.golang.org/api v0.235.0 // @grafana/grafana-backend-group
|
||||
google.golang.org/grpc v1.75.1 // @grafana/plugins-platform-backend
|
||||
google.golang.org/protobuf v1.36.8 // @grafana/plugins-platform-backend
|
||||
google.golang.org/protobuf v1.36.9 // @grafana/plugins-platform-backend
|
||||
gopkg.in/ini.v1 v1.67.0 // @grafana/alerting-backend
|
||||
gopkg.in/mail.v2 v2.3.1 // @grafana/grafana-backend-group
|
||||
gopkg.in/yaml.v2 v2.4.0 // @grafana/alerting-backend
|
||||
|
|
|
|||
12
go.sum
12
go.sum
|
|
@ -1587,10 +1587,10 @@ github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5T
|
|||
github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA=
|
||||
github.com/grafana/alerting v0.0.0-20250925200825-7a889aa4934d h1:zzEty7HgfXbQ/RiBCJFMqaZiJlqiXuz/Zbc6/H6ksuM=
|
||||
github.com/grafana/alerting v0.0.0-20250925200825-7a889aa4934d/go.mod h1:T5sitas9VhVj8/S9LeRLy6H75kTBdh/sCCqHo7gaQI8=
|
||||
github.com/grafana/authlib v0.0.0-20250924100039-ea07223cdb6c h1:8GIMe1KclDdfogaeRsiU69Ev2zTF9kmjqjQqqZMzerc=
|
||||
github.com/grafana/authlib v0.0.0-20250924100039-ea07223cdb6c/go.mod h1:C6CmTG6vfiqebjJswKsc6zes+1F/OtTCi6aAtL5Um6A=
|
||||
github.com/grafana/authlib/types v0.0.0-20250917093142-83a502239781 h1:jymmOFIWnW26DeUjFgYEoltI170KeT5r1rI8a/dUf0E=
|
||||
github.com/grafana/authlib/types v0.0.0-20250917093142-83a502239781/go.mod h1:qeWYbnWzaYGl88JlL9+DsP1GT2Cudm58rLtx13fKZdw=
|
||||
github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f h1:Cbm6OKkOcJ+7CSZsGsEJzktC/SIa5bxVeYKQLuYK86o=
|
||||
github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f/go.mod h1:axY0cdOg3q0TZHwpHnIz5x16xZ8ZBxJHShsSHHXcHQg=
|
||||
github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37 h1:qEwZ+7MbPjzRvTi31iT9w7NBhKIpKwZrFbYmOZLqkwA=
|
||||
github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37/go.mod h1:qeWYbnWzaYGl88JlL9+DsP1GT2Cudm58rLtx13fKZdw=
|
||||
github.com/grafana/dataplane/examples v0.0.1 h1:K9M5glueWyLoL4//H+EtTQq16lXuHLmOhb6DjSCahzA=
|
||||
github.com/grafana/dataplane/examples v0.0.1/go.mod h1:h5YwY8s407/17XF5/dS8XrUtsTVV2RnuW8+m1Mp46mg=
|
||||
github.com/grafana/dataplane/sdata v0.0.9 h1:AGL1LZnCUG4MnQtnWpBPbQ8ZpptaZs14w6kE/MWfg7s=
|
||||
|
|
@ -3534,8 +3534,8 @@ google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw
|
|||
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
|
||||
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
|
||||
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
|
||||
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
|
||||
|
|
|
|||
|
|
@ -1046,10 +1046,12 @@ github.com/grafana/alerting v0.0.0-20250925193206-bd061d3d9185 h1:R494uXJOz7glN7
|
|||
github.com/grafana/alerting v0.0.0-20250925193206-bd061d3d9185/go.mod h1:T5sitas9VhVj8/S9LeRLy6H75kTBdh/sCCqHo7gaQI8=
|
||||
github.com/grafana/authlib v0.0.0-20250123104008-e99947858901/go.mod h1:/gYfphsNu9v1qYWXxpv1NSvMEMSwvdf8qb8YlgwIRl8=
|
||||
github.com/grafana/authlib v0.0.0-20250909101823-1b466dbd19a1/go.mod h1:C6CmTG6vfiqebjJswKsc6zes+1F/OtTCi6aAtL5Um6A=
|
||||
github.com/grafana/authlib v0.0.0-20250924100039-ea07223cdb6c/go.mod h1:C6CmTG6vfiqebjJswKsc6zes+1F/OtTCi6aAtL5Um6A=
|
||||
github.com/grafana/authlib/types v0.0.0-20250120144156-d6737a7dc8f5/go.mod h1:qYjSd1tmJiuVoSICp7Py9/zD54O9uQQA3wuM6Gg4DFM=
|
||||
github.com/grafana/authlib/types v0.0.0-20250120145936-5f0e28e7a87c/go.mod h1:qYjSd1tmJiuVoSICp7Py9/zD54O9uQQA3wuM6Gg4DFM=
|
||||
github.com/grafana/authlib/types v0.0.0-20250314102521-a77865c746c0/go.mod h1:qeWYbnWzaYGl88JlL9+DsP1GT2Cudm58rLtx13fKZdw=
|
||||
github.com/grafana/authlib/types v0.0.0-20250721184729-1593a38e4933/go.mod h1:qeWYbnWzaYGl88JlL9+DsP1GT2Cudm58rLtx13fKZdw=
|
||||
github.com/grafana/authlib/types v0.0.0-20250917093142-83a502239781/go.mod h1:qeWYbnWzaYGl88JlL9+DsP1GT2Cudm58rLtx13fKZdw=
|
||||
github.com/grafana/cloudflare-go v0.0.0-20230110200409-c627cf6792f2 h1:qhugDMdQ4Vp68H0tp/0iN17DM2ehRo1rLEdOFe/gB8I=
|
||||
github.com/grafana/cloudflare-go v0.0.0-20230110200409-c627cf6792f2/go.mod h1:w/aiO1POVIeXUQyl0VQSZjl5OAGDTL5aX+4v0RA1tcw=
|
||||
github.com/grafana/cog v0.0.37/go.mod h1:UDstzYqMdgIROmbfkHL8fB9XWQO2lnf5z+4W/eJo4Dc=
|
||||
|
|
@ -2163,6 +2165,7 @@ google.golang.org/protobuf v1.36.3/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojt
|
|||
google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
google.golang.org/protobuf v1.36.7/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
|
||||
gopkg.in/errgo.v2 v2.1.0 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8=
|
||||
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||
|
|
|
|||
|
|
@ -885,6 +885,11 @@ export interface FeatureToggles {
|
|||
*/
|
||||
alertingJiraIntegration?: boolean;
|
||||
/**
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
alertingUseNewSimplifiedRoutingHashAlgorithm?: boolean;
|
||||
/**
|
||||
* Use the scopes navigation endpoint instead of the dashboardbindings endpoint
|
||||
*/
|
||||
useScopesNavigationEndpoint?: boolean;
|
||||
|
|
|
|||
|
|
@ -153,7 +153,7 @@ require (
|
|||
google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 // indirect
|
||||
google.golang.org/grpc v1.75.1 // indirect
|
||||
google.golang.org/protobuf v1.36.8 // indirect
|
||||
google.golang.org/protobuf v1.36.9 // indirect
|
||||
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
|
||||
gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
|
|
|
|||
|
|
@ -445,8 +445,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090/go.
|
|||
google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
google.golang.org/grpc v1.75.1 h1:/ODCNEuf9VghjgO3rqLcfg8fiOP0nSluljWFlDxELLI=
|
||||
google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
|
||||
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
|
||||
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
|
||||
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/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=
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ module github.com/grafana/grafana/pkg/apimachinery
|
|||
go 1.24.6
|
||||
|
||||
require (
|
||||
github.com/grafana/authlib v0.0.0-20250924100039-ea07223cdb6c // @grafana/identity-access-team
|
||||
github.com/grafana/authlib/types v0.0.0-20250917093142-83a502239781 // @grafana/identity-access-team
|
||||
github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f // @grafana/identity-access-team
|
||||
github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37 // @grafana/identity-access-team
|
||||
github.com/stretchr/testify v1.11.1
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
k8s.io/apimachinery v0.34.1
|
||||
|
|
@ -51,7 +51,7 @@ require (
|
|||
golang.org/x/text v0.29.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 // indirect
|
||||
google.golang.org/grpc v1.75.1 // indirect
|
||||
google.golang.org/protobuf v1.36.8 // indirect
|
||||
google.golang.org/protobuf v1.36.9 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
k8s.io/klog/v2 v2.130.1 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
|
||||
|
|
|
|||
|
|
@ -30,10 +30,10 @@ github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX
|
|||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
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/grafana/authlib v0.0.0-20250924100039-ea07223cdb6c h1:8GIMe1KclDdfogaeRsiU69Ev2zTF9kmjqjQqqZMzerc=
|
||||
github.com/grafana/authlib v0.0.0-20250924100039-ea07223cdb6c/go.mod h1:C6CmTG6vfiqebjJswKsc6zes+1F/OtTCi6aAtL5Um6A=
|
||||
github.com/grafana/authlib/types v0.0.0-20250917093142-83a502239781 h1:jymmOFIWnW26DeUjFgYEoltI170KeT5r1rI8a/dUf0E=
|
||||
github.com/grafana/authlib/types v0.0.0-20250917093142-83a502239781/go.mod h1:qeWYbnWzaYGl88JlL9+DsP1GT2Cudm58rLtx13fKZdw=
|
||||
github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f h1:Cbm6OKkOcJ+7CSZsGsEJzktC/SIa5bxVeYKQLuYK86o=
|
||||
github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f/go.mod h1:axY0cdOg3q0TZHwpHnIz5x16xZ8ZBxJHShsSHHXcHQg=
|
||||
github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37 h1:qEwZ+7MbPjzRvTi31iT9w7NBhKIpKwZrFbYmOZLqkwA=
|
||||
github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37/go.mod h1:qeWYbnWzaYGl88JlL9+DsP1GT2Cudm58rLtx13fKZdw=
|
||||
github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4 h1:jSojuc7njleS3UOz223WDlXOinmuLAIPI0z2vtq8EgI=
|
||||
github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4/go.mod h1:VahT+GtfQIM+o8ht2StR6J9g+Ef+C2Vokh5uuSmOD/4=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
|
|
@ -132,8 +132,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 h1:
|
|||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090/go.mod h1:GmFNa4BdJZ2a8G+wCe9Bg3wwThLrJun751XstdJt5Og=
|
||||
google.golang.org/grpc v1.75.1 h1:/ODCNEuf9VghjgO3rqLcfg8fiOP0nSluljWFlDxELLI=
|
||||
google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
|
||||
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
|
||||
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
|
||||
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/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=
|
||||
|
|
|
|||
|
|
@ -23,9 +23,9 @@ const qualifiedNameFmt string = "^(" + qnameCharFmt + qnameExtCharFmt + "*)?" +
|
|||
const qualifiedNameErrMsg string = "must consist of alphanumeric characters, '-', '_' or '.', and must start and end with an alphanumeric character"
|
||||
|
||||
const alphaCharFmt string = "[A-Za-z]"
|
||||
const resourceCharFmt string = "[A-Za-z0-9]" // alpha numeric
|
||||
const resourceCharFmt string = "[A-Za-z0-9-]" // alpha numeric plus dashes
|
||||
const resourceFmt string = "^" + alphaCharFmt + resourceCharFmt + "*$"
|
||||
const resourceErrMsg string = "must consist of alphanumeric characters"
|
||||
const resourceErrMsg string = "must consist of alphanumeric characters and dashes, and must start with an alphabetic character"
|
||||
|
||||
var (
|
||||
grafanaNameRegexp = regexp.MustCompile(grafanaNameFmt).MatchString
|
||||
|
|
|
|||
|
|
@ -198,16 +198,17 @@ func TestValidation(t *testing.T) {
|
|||
"folders",
|
||||
"folders123",
|
||||
"aaa",
|
||||
"hello-world",
|
||||
"hello-world-",
|
||||
},
|
||||
}, {
|
||||
name: "bad input",
|
||||
expect: []string{
|
||||
"resource must consist of alphanumeric characters (e.g. 'dashboards', or 'folders', regex used for validation is '^[A-Za-z][A-Za-z0-9]*$')",
|
||||
"resource must consist of alphanumeric characters and dashes, and must start with an alphabetic character (e.g. 'dashboards', or 'folders', regex used for validation is '^[A-Za-z][A-Za-z0-9-]*$')",
|
||||
},
|
||||
input: []string{
|
||||
"_bad_input",
|
||||
"hello world",
|
||||
"hello-world",
|
||||
"hello!",
|
||||
"hello~",
|
||||
"hello ",
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ go 1.24.6
|
|||
|
||||
require (
|
||||
github.com/google/go-cmp v0.7.0
|
||||
github.com/grafana/authlib/types v0.0.0-20250917093142-83a502239781
|
||||
github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37
|
||||
github.com/grafana/grafana-app-sdk/logging v0.45.0
|
||||
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250514132646-acbc7b54ed9e
|
||||
github.com/prometheus/client_golang v1.23.2
|
||||
|
|
@ -44,7 +44,7 @@ require (
|
|||
github.com/google/gnostic-models v0.7.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/grafana/authlib v0.0.0-20250924100039-ea07223cdb6c // indirect
|
||||
github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f // indirect
|
||||
github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.2 // indirect
|
||||
|
|
@ -95,7 +95,7 @@ require (
|
|||
google.golang.org/genproto/googleapis/api v0.0.0-20250908214217-97024824d090 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 // indirect
|
||||
google.golang.org/grpc v1.75.1 // indirect
|
||||
google.golang.org/protobuf v1.36.8 // indirect
|
||||
google.golang.org/protobuf v1.36.9 // indirect
|
||||
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
|
|
|
|||
|
|
@ -63,10 +63,10 @@ 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/authlib v0.0.0-20250924100039-ea07223cdb6c h1:8GIMe1KclDdfogaeRsiU69Ev2zTF9kmjqjQqqZMzerc=
|
||||
github.com/grafana/authlib v0.0.0-20250924100039-ea07223cdb6c/go.mod h1:C6CmTG6vfiqebjJswKsc6zes+1F/OtTCi6aAtL5Um6A=
|
||||
github.com/grafana/authlib/types v0.0.0-20250917093142-83a502239781 h1:jymmOFIWnW26DeUjFgYEoltI170KeT5r1rI8a/dUf0E=
|
||||
github.com/grafana/authlib/types v0.0.0-20250917093142-83a502239781/go.mod h1:qeWYbnWzaYGl88JlL9+DsP1GT2Cudm58rLtx13fKZdw=
|
||||
github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f h1:Cbm6OKkOcJ+7CSZsGsEJzktC/SIa5bxVeYKQLuYK86o=
|
||||
github.com/grafana/authlib v0.0.0-20250930082137-a40e2c2b094f/go.mod h1:axY0cdOg3q0TZHwpHnIz5x16xZ8ZBxJHShsSHHXcHQg=
|
||||
github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37 h1:qEwZ+7MbPjzRvTi31iT9w7NBhKIpKwZrFbYmOZLqkwA=
|
||||
github.com/grafana/authlib/types v0.0.0-20250926065801-df98203cff37/go.mod h1:qeWYbnWzaYGl88JlL9+DsP1GT2Cudm58rLtx13fKZdw=
|
||||
github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4 h1:jSojuc7njleS3UOz223WDlXOinmuLAIPI0z2vtq8EgI=
|
||||
github.com/grafana/dskit v0.0.0-20250908063411-6b6da59b5cc4/go.mod h1:VahT+GtfQIM+o8ht2StR6J9g+Ef+C2Vokh5uuSmOD/4=
|
||||
github.com/grafana/grafana-app-sdk/logging v0.45.0 h1:0SH6nYZpiLBZRwUq4J6+1vo8xuHKJjnO95/2pGOoA8w=
|
||||
|
|
@ -265,8 +265,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090/go.
|
|||
google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
google.golang.org/grpc v1.75.1 h1:/ODCNEuf9VghjgO3rqLcfg8fiOP0nSluljWFlDxELLI=
|
||||
google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
|
||||
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
|
||||
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
|
||||
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/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=
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ require (
|
|||
golang.org/x/sync v0.17.0 // @grafana/alerting-backend
|
||||
golang.org/x/text v0.29.0 // indirect; @grafana/grafana-backend-group
|
||||
google.golang.org/grpc v1.75.1 // indirect; @grafana/plugins-platform-backend
|
||||
google.golang.org/protobuf v1.36.8 // indirect; @grafana/plugins-platform-backend
|
||||
google.golang.org/protobuf v1.36.9 // indirect; @grafana/plugins-platform-backend
|
||||
)
|
||||
|
||||
require (
|
||||
|
|
|
|||
|
|
@ -111,8 +111,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 h1:
|
|||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090/go.mod h1:GmFNa4BdJZ2a8G+wCe9Bg3wwThLrJun751XstdJt5Og=
|
||||
google.golang.org/grpc v1.75.1 h1:/ODCNEuf9VghjgO3rqLcfg8fiOP0nSluljWFlDxELLI=
|
||||
google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
|
||||
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
|
||||
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
|
||||
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ require (
|
|||
github.com/stretchr/testify v1.11.1
|
||||
go.opentelemetry.io/otel v1.38.0
|
||||
go.opentelemetry.io/otel/trace v1.38.0
|
||||
google.golang.org/protobuf v1.36.8
|
||||
google.golang.org/protobuf v1.36.9
|
||||
k8s.io/apimachinery v0.34.1
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -420,8 +420,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090 h1:
|
|||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250908214217-97024824d090/go.mod h1:GmFNa4BdJZ2a8G+wCe9Bg3wwThLrJun751XstdJt5Og=
|
||||
google.golang.org/grpc v1.75.1 h1:/ODCNEuf9VghjgO3rqLcfg8fiOP0nSluljWFlDxELLI=
|
||||
google.golang.org/grpc v1.75.1/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
|
||||
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
|
||||
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
|
||||
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/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=
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"context"
|
||||
"embed"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
|
@ -15,6 +16,7 @@ import (
|
|||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
|
||||
glog "github.com/grafana/grafana-plugin-sdk-go/backend/log"
|
||||
"github.com/grafana/grafana/pkg/promlib/intervalv2"
|
||||
)
|
||||
|
||||
|
|
@ -190,7 +192,7 @@ type internalQueryModel struct {
|
|||
Interval string `json:"interval,omitempty"`
|
||||
}
|
||||
|
||||
func Parse(span trace.Span, query backend.DataQuery, dsScrapeInterval string, intervalCalculator intervalv2.Calculator, fromAlert bool, enableScope bool) (*Query, error) {
|
||||
func Parse(ctx context.Context, log glog.Logger, span trace.Span, query backend.DataQuery, dsScrapeInterval string, intervalCalculator intervalv2.Calculator, fromAlert bool, enableScope bool) (*Query, error) {
|
||||
model := &internalQueryModel{}
|
||||
if err := json.Unmarshal(query.JSON, model); err != nil {
|
||||
return nil, err
|
||||
|
|
@ -241,6 +243,7 @@ func Parse(span trace.Span, query backend.DataQuery, dsScrapeInterval string, in
|
|||
}
|
||||
|
||||
if len(scopeFilters) > 0 || len(model.AdhocFilters) > 0 || len(model.GroupByKeys) > 0 {
|
||||
log.Info("Applying scope filters", "scopeFiltersCount", len(scopeFilters), "adhocFiltersCount", len(model.AdhocFilters), "groupByKeysCount", len(model.GroupByKeys))
|
||||
expr, err = ApplyFiltersAndGroupBy(expr, scopeFilters, model.AdhocFilters, model.GroupByKeys)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
"go.opentelemetry.io/otel"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
|
||||
"github.com/grafana/grafana/pkg/promlib/intervalv2"
|
||||
"github.com/grafana/grafana/pkg/promlib/models"
|
||||
)
|
||||
|
|
@ -44,7 +45,7 @@ func TestParse(t *testing.T) {
|
|||
RefID: "A",
|
||||
}
|
||||
|
||||
res, err := models.Parse(span, q, "15s", intervalCalculator, true, false)
|
||||
res, err := models.Parse(context.Background(), log.New(), span, q, "15s", intervalCalculator, true, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, false, res.ExemplarQuery)
|
||||
})
|
||||
|
|
@ -61,7 +62,7 @@ func TestParse(t *testing.T) {
|
|||
"refId": "A"
|
||||
}`, timeRange, time.Duration(1)*time.Minute)
|
||||
|
||||
res, err := models.Parse(span, q, "15s", intervalCalculator, false, false)
|
||||
res, err := models.Parse(context.Background(), log.New(), span, q, "15s", intervalCalculator, false, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, time.Second*30, res.Step)
|
||||
})
|
||||
|
|
@ -79,7 +80,7 @@ func TestParse(t *testing.T) {
|
|||
"refId": "A"
|
||||
}`, timeRange, time.Duration(1)*time.Minute)
|
||||
|
||||
res, err := models.Parse(span, q, "15s", intervalCalculator, false, false)
|
||||
res, err := models.Parse(context.Background(), log.New(), span, q, "15s", intervalCalculator, false, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, time.Second*15, res.Step)
|
||||
})
|
||||
|
|
@ -97,7 +98,7 @@ func TestParse(t *testing.T) {
|
|||
"refId": "A"
|
||||
}`, timeRange, time.Duration(1)*time.Minute)
|
||||
|
||||
res, err := models.Parse(span, q, "15s", intervalCalculator, false, false)
|
||||
res, err := models.Parse(context.Background(), log.New(), span, q, "15s", intervalCalculator, false, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, time.Minute*20, res.Step)
|
||||
})
|
||||
|
|
@ -115,7 +116,7 @@ func TestParse(t *testing.T) {
|
|||
"refId": "A"
|
||||
}`, timeRange, time.Duration(1)*time.Minute)
|
||||
|
||||
res, err := models.Parse(span, q, "15s", intervalCalculator, false, false)
|
||||
res, err := models.Parse(context.Background(), log.New(), span, q, "15s", intervalCalculator, false, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, time.Minute*2, res.Step)
|
||||
})
|
||||
|
|
@ -133,7 +134,7 @@ func TestParse(t *testing.T) {
|
|||
"refId": "A"
|
||||
}`, timeRange, time.Duration(1)*time.Minute)
|
||||
|
||||
res, err := models.Parse(span, q, "240s", intervalCalculator, false, false)
|
||||
res, err := models.Parse(context.Background(), log.New(), span, q, "240s", intervalCalculator, false, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, time.Minute*4, res.Step)
|
||||
})
|
||||
|
|
@ -152,7 +153,7 @@ func TestParse(t *testing.T) {
|
|||
"refId": "A"
|
||||
}`, timeRange, time.Duration(1)*time.Minute)
|
||||
|
||||
res, err := models.Parse(span, q, "15s", intervalCalculator, false, false)
|
||||
res, err := models.Parse(context.Background(), log.New(), span, q, "15s", intervalCalculator, false, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "rate(ALERTS{job=\"test\" [2m]})", res.Expr)
|
||||
require.Equal(t, 120*time.Second, res.Step)
|
||||
|
|
@ -173,7 +174,7 @@ func TestParse(t *testing.T) {
|
|||
"refId": "A"
|
||||
}`, timeRange, time.Duration(1)*time.Minute)
|
||||
|
||||
res, err := models.Parse(span, q, "15s", intervalCalculator, false, false)
|
||||
res, err := models.Parse(context.Background(), log.New(), span, q, "15s", intervalCalculator, false, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "rate(ALERTS{job=\"test\" [2m]})", res.Expr)
|
||||
})
|
||||
|
|
@ -192,7 +193,7 @@ func TestParse(t *testing.T) {
|
|||
"refId": "A"
|
||||
}`, timeRange, time.Duration(1)*time.Minute)
|
||||
|
||||
res, err := models.Parse(span, q, "15s", intervalCalculator, false, false)
|
||||
res, err := models.Parse(context.Background(), log.New(), span, q, "15s", intervalCalculator, false, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "rate(ALERTS{job=\"test\" [120000]})", res.Expr)
|
||||
})
|
||||
|
|
@ -211,7 +212,7 @@ func TestParse(t *testing.T) {
|
|||
"refId": "A"
|
||||
}`, timeRange, time.Duration(1)*time.Minute)
|
||||
|
||||
res, err := models.Parse(span, q, "15s", intervalCalculator, false, false)
|
||||
res, err := models.Parse(context.Background(), log.New(), span, q, "15s", intervalCalculator, false, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "rate(ALERTS{job=\"test\" [120000]}) + rate(ALERTS{job=\"test\" [2m]})", res.Expr)
|
||||
})
|
||||
|
|
@ -230,7 +231,7 @@ func TestParse(t *testing.T) {
|
|||
"refId": "A"
|
||||
}`, timeRange, time.Duration(1)*time.Minute)
|
||||
|
||||
res, err := models.Parse(span, q, "15s", intervalCalculator, false, false)
|
||||
res, err := models.Parse(context.Background(), log.New(), span, q, "15s", intervalCalculator, false, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "rate(ALERTS{job=\"test\" [120000]}) + rate(ALERTS{job=\"test\" [2m]})", res.Expr)
|
||||
})
|
||||
|
|
@ -248,7 +249,7 @@ func TestParse(t *testing.T) {
|
|||
"refId": "A"
|
||||
}`, timeRange, time.Duration(1)*time.Minute)
|
||||
|
||||
res, err := models.Parse(span, q, "15s", intervalCalculator, false, false)
|
||||
res, err := models.Parse(context.Background(), log.New(), span, q, "15s", intervalCalculator, false, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "rate(ALERTS{job=\"test\" [172800s]})", res.Expr)
|
||||
})
|
||||
|
|
@ -266,7 +267,7 @@ func TestParse(t *testing.T) {
|
|||
"refId": "A"
|
||||
}`, timeRange, time.Duration(1)*time.Minute)
|
||||
|
||||
res, err := models.Parse(span, q, "15s", intervalCalculator, false, false)
|
||||
res, err := models.Parse(context.Background(), log.New(), span, q, "15s", intervalCalculator, false, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "rate(ALERTS{job=\"test\" [172800]})", res.Expr)
|
||||
})
|
||||
|
|
@ -284,7 +285,7 @@ func TestParse(t *testing.T) {
|
|||
"refId": "A"
|
||||
}`, timeRange, time.Duration(1)*time.Minute)
|
||||
|
||||
res, err := models.Parse(span, q, "15s", intervalCalculator, false, false)
|
||||
res, err := models.Parse(context.Background(), log.New(), span, q, "15s", intervalCalculator, false, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "rate(ALERTS{job=\"test\" [172800s]})", res.Expr)
|
||||
})
|
||||
|
|
@ -302,7 +303,7 @@ func TestParse(t *testing.T) {
|
|||
"refId": "A"
|
||||
}`, timeRange, time.Duration(1)*time.Minute)
|
||||
|
||||
res, err := models.Parse(span, q, "15s", intervalCalculator, false, false)
|
||||
res, err := models.Parse(context.Background(), log.New(), span, q, "15s", intervalCalculator, false, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "rate(ALERTS{job=\"test\" [0]})", res.Expr)
|
||||
})
|
||||
|
|
@ -320,7 +321,7 @@ func TestParse(t *testing.T) {
|
|||
"refId": "A"
|
||||
}`, timeRange, time.Duration(1)*time.Minute)
|
||||
|
||||
res, err := models.Parse(span, q, "15s", intervalCalculator, false, false)
|
||||
res, err := models.Parse(context.Background(), log.New(), span, q, "15s", intervalCalculator, false, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "rate(ALERTS{job=\"test\" [1]})", res.Expr)
|
||||
})
|
||||
|
|
@ -338,7 +339,7 @@ func TestParse(t *testing.T) {
|
|||
"refId": "A"
|
||||
}`, timeRange, time.Duration(1)*time.Minute)
|
||||
|
||||
res, err := models.Parse(span, q, "15s", intervalCalculator, false, false)
|
||||
res, err := models.Parse(context.Background(), log.New(), span, q, "15s", intervalCalculator, false, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "rate(ALERTS{job=\"test\" [172800000]})", res.Expr)
|
||||
})
|
||||
|
|
@ -356,7 +357,7 @@ func TestParse(t *testing.T) {
|
|||
"refId": "A"
|
||||
}`, timeRange, time.Duration(1)*time.Minute)
|
||||
|
||||
res, err := models.Parse(span, q, "15s", intervalCalculator, false, false)
|
||||
res, err := models.Parse(context.Background(), log.New(), span, q, "15s", intervalCalculator, false, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "rate(ALERTS{job=\"test\" [20]})", res.Expr)
|
||||
})
|
||||
|
|
@ -375,7 +376,7 @@ func TestParse(t *testing.T) {
|
|||
"refId": "A"
|
||||
}`, timeRange, time.Duration(1)*time.Minute)
|
||||
|
||||
res, err := models.Parse(span, q, "15s", intervalCalculator, false, false)
|
||||
res, err := models.Parse(context.Background(), log.New(), span, q, "15s", intervalCalculator, false, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "rate(ALERTS{job=\"test\" [20m0s]})", res.Expr)
|
||||
})
|
||||
|
|
@ -394,7 +395,7 @@ func TestParse(t *testing.T) {
|
|||
"refId": "A"
|
||||
}`, timeRange, 1*time.Minute)
|
||||
|
||||
res, err := models.Parse(span, q, "15s", intervalCalculator, false, false)
|
||||
res, err := models.Parse(context.Background(), log.New(), span, q, "15s", intervalCalculator, false, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "rate(ALERTS{job=\"test\" [1m0s]})", res.Expr)
|
||||
require.Equal(t, 1*time.Minute, res.Step)
|
||||
|
|
@ -413,7 +414,7 @@ func TestParse(t *testing.T) {
|
|||
"refId": "A"
|
||||
}`, timeRange, 2*time.Minute)
|
||||
|
||||
res, err := models.Parse(span, q, "15s", intervalCalculator, false, false)
|
||||
res, err := models.Parse(context.Background(), log.New(), span, q, "15s", intervalCalculator, false, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "rate(ALERTS{job=\"test\" [135000]})", res.Expr)
|
||||
})
|
||||
|
|
@ -431,7 +432,7 @@ func TestParse(t *testing.T) {
|
|||
"refId": "A"
|
||||
}`, timeRange, 2*time.Minute)
|
||||
|
||||
res, err := models.Parse(span, q, "15s", intervalCalculator, false, false)
|
||||
res, err := models.Parse(context.Background(), log.New(), span, q, "15s", intervalCalculator, false, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "rate(ALERTS{job=\"test\" [135000]}) + rate(ALERTS{job=\"test\" [2m15s]})", res.Expr)
|
||||
})
|
||||
|
|
@ -450,7 +451,7 @@ func TestParse(t *testing.T) {
|
|||
"refId": "A"
|
||||
}`, timeRange, 2*time.Minute)
|
||||
|
||||
res, err := models.Parse(span, q, "15s", intervalCalculator, false, false)
|
||||
res, err := models.Parse(context.Background(), log.New(), span, q, "15s", intervalCalculator, false, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "A", res.RefId)
|
||||
})
|
||||
|
|
@ -468,7 +469,7 @@ func TestParse(t *testing.T) {
|
|||
"refId": "A"
|
||||
}`, timeRange, 2*time.Minute)
|
||||
|
||||
res, err := models.Parse(span, q, "15s", intervalCalculator, false, false)
|
||||
res, err := models.Parse(context.Background(), log.New(), span, q, "15s", intervalCalculator, false, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "rate(ALERTS{job=\"test\" [135000]}) + rate(ALERTS{job=\"test\" [2m15s]})", res.Expr)
|
||||
})
|
||||
|
|
@ -487,7 +488,7 @@ func TestParse(t *testing.T) {
|
|||
"range": true
|
||||
}`, timeRange, time.Duration(1)*time.Minute)
|
||||
|
||||
res, err := models.Parse(span, q, "15s", intervalCalculator, false, false)
|
||||
res, err := models.Parse(context.Background(), log.New(), span, q, "15s", intervalCalculator, false, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, true, res.RangeQuery)
|
||||
})
|
||||
|
|
@ -507,7 +508,7 @@ func TestParse(t *testing.T) {
|
|||
"instant": true
|
||||
}`, timeRange, time.Duration(1)*time.Minute)
|
||||
|
||||
res, err := models.Parse(span, q, "15s", intervalCalculator, false, false)
|
||||
res, err := models.Parse(context.Background(), log.New(), span, q, "15s", intervalCalculator, false, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, true, res.RangeQuery)
|
||||
require.Equal(t, true, res.InstantQuery)
|
||||
|
|
@ -526,7 +527,7 @@ func TestParse(t *testing.T) {
|
|||
"refId": "A"
|
||||
}`, timeRange, time.Duration(1)*time.Minute)
|
||||
|
||||
res, err := models.Parse(span, q, "15s", intervalCalculator, false, false)
|
||||
res, err := models.Parse(context.Background(), log.New(), span, q, "15s", intervalCalculator, false, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, true, res.RangeQuery)
|
||||
})
|
||||
|
|
@ -659,7 +660,7 @@ func TestRateInterval(t *testing.T) {
|
|||
t.Run(tt.name, func(t *testing.T) {
|
||||
q := mockQuery(tt.args.expr, tt.args.interval, tt.args.intervalMs, tt.args.timeRange)
|
||||
q.MaxDataPoints = 12384
|
||||
res, err := models.Parse(span, q, tt.args.dsScrapeInterval, intervalCalculator, false, false)
|
||||
res, err := models.Parse(context.Background(), log.New(), span, q, tt.args.dsScrapeInterval, intervalCalculator, false, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tt.want.Expr, res.Expr)
|
||||
require.Equal(t, tt.want.Step, res.Step)
|
||||
|
|
@ -694,7 +695,7 @@ func TestRateInterval(t *testing.T) {
|
|||
"utcOffsetSec":3600
|
||||
}`),
|
||||
}
|
||||
res, err := models.Parse(span, query, "30s", intervalCalculator, false, false)
|
||||
res, err := models.Parse(context.Background(), log.New(), span, query, "30s", intervalCalculator, false, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "sum(rate(process_cpu_seconds_total[2m0s]))", res.Expr)
|
||||
require.Equal(t, 30*time.Second, res.Step)
|
||||
|
|
@ -729,7 +730,7 @@ func TestRateInterval(t *testing.T) {
|
|||
"maxDataPoints": 1055
|
||||
}`),
|
||||
}
|
||||
res, err := models.Parse(span, query, "15s", intervalCalculator, false, false)
|
||||
res, err := models.Parse(context.Background(), log.New(), span, query, "15s", intervalCalculator, false, false)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "sum(rate(cache_requests_total[1m0s]))", res.Expr)
|
||||
require.Equal(t, 15*time.Second, res.Step)
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ func (s *QueryData) handleQuery(ctx context.Context, bq backend.DataQuery, fromA
|
|||
hasPromQLScopeFeatureFlag bool) *backend.DataResponse {
|
||||
traceCtx, span := s.tracer.Start(ctx, "datasource.prometheus")
|
||||
defer span.End()
|
||||
query, err := models.Parse(span, bq, s.TimeInterval, s.intervalCalculator, fromAlert, hasPromQLScopeFeatureFlag)
|
||||
query, err := models.Parse(ctx, s.log, span, bq, s.TimeInterval, s.intervalCalculator, fromAlert, hasPromQLScopeFeatureFlag)
|
||||
if err != nil {
|
||||
return &backend.DataResponse{
|
||||
Error: err,
|
||||
|
|
@ -145,7 +145,7 @@ func (s *QueryData) handleQuery(ctx context.Context, bq backend.DataQuery, fromA
|
|||
|
||||
func (s *QueryData) fetch(traceCtx context.Context, client *client.Client, q *models.Query) *backend.DataResponse {
|
||||
logger := s.log.FromContext(traceCtx)
|
||||
logger.Debug("Sending query", "start", q.Start, "end", q.End, "step", q.Step, "query", q.Expr /*, "queryTimeout", s.QueryTimeout*/)
|
||||
logger.Debug("Sending query", "start", q.Start, "end", q.End, "step", q.Step, "query", q.Expr)
|
||||
|
||||
dr := &backend.DataResponse{
|
||||
Frames: data.Frames{},
|
||||
|
|
|
|||
|
|
@ -87,8 +87,7 @@ func (r *subAccessREST) getAccessInfo(ctx context.Context, name string) (*folder
|
|||
Resource: foldersV1.RESOURCE,
|
||||
Namespace: ns.Value,
|
||||
Name: name,
|
||||
Folder: obj.GetFolder(),
|
||||
})
|
||||
}, obj.GetFolder())
|
||||
return tmp.Allowed
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -120,8 +120,8 @@ func (f *finalizer) processExistingItems(
|
|||
Group: item.Group,
|
||||
Resource: item.Resource,
|
||||
})
|
||||
logger.Error("error getting client for resource", "resource", item.Resource, "error", err)
|
||||
if err != nil {
|
||||
logger.Error("error getting client for resource", "resource", item.Resource, "error", err)
|
||||
return count, err
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -92,6 +92,7 @@ type APIBuilder struct {
|
|||
|
||||
allowedTargets []provisioning.SyncTargetType
|
||||
allowImageRendering bool
|
||||
minSyncInterval time.Duration
|
||||
|
||||
features featuremgmt.FeatureToggles
|
||||
usageStats usagestats.Service
|
||||
|
|
@ -144,6 +145,7 @@ func NewAPIBuilder(
|
|||
allowedTargets []provisioning.SyncTargetType,
|
||||
restConfigGetter func(context.Context) (*clientrest.Config, error),
|
||||
allowImageRendering bool,
|
||||
minSyncInterval time.Duration,
|
||||
registry prometheus.Registerer,
|
||||
newStandaloneClientFactoryFunc func(loopbackConfigProvider apiserver.RestConfigProvider) resources.ClientFactory, // optional, only used for standalone apiserver
|
||||
) *APIBuilder {
|
||||
|
|
@ -156,6 +158,11 @@ func NewAPIBuilder(
|
|||
parsers := resources.NewParserFactory(clients)
|
||||
resourceLister := resources.NewResourceListerForMigrations(unified, legacyMigrator, storageStatus)
|
||||
|
||||
// do not allow minsync interval to be less than 10
|
||||
if minSyncInterval <= 10*time.Second {
|
||||
minSyncInterval = 10 * time.Second
|
||||
}
|
||||
|
||||
b := &APIBuilder{
|
||||
onlyApiServer: onlyApiServer,
|
||||
tracer: tracer,
|
||||
|
|
@ -175,6 +182,7 @@ func NewAPIBuilder(
|
|||
allowedTargets: allowedTargets,
|
||||
restConfigGetter: restConfigGetter,
|
||||
allowImageRendering: allowImageRendering,
|
||||
minSyncInterval: minSyncInterval,
|
||||
registry: registry,
|
||||
}
|
||||
|
||||
|
|
@ -261,6 +269,7 @@ func RegisterAPIService(
|
|||
allowedTargets,
|
||||
nil, // will use loopback instead
|
||||
cfg.ProvisioningAllowImageRendering,
|
||||
cfg.ProvisioningMinSyncInterval,
|
||||
reg,
|
||||
nil,
|
||||
)
|
||||
|
|
@ -287,7 +296,7 @@ func (b *APIBuilder) GetAuthorizer() authorizer.Authorizer {
|
|||
Name: a.GetName(),
|
||||
Namespace: a.GetNamespace(),
|
||||
Subresource: a.GetSubresource(),
|
||||
})
|
||||
}, "")
|
||||
if err != nil {
|
||||
return authorizer.DecisionDeny, "failed to perform authorization", err
|
||||
}
|
||||
|
|
@ -587,6 +596,11 @@ func (b *APIBuilder) Validate(ctx context.Context, a admission.Attributes, o adm
|
|||
"sync target is not supported"))
|
||||
}
|
||||
|
||||
if cfg.Spec.Sync.Enabled && cfg.Spec.Sync.IntervalSeconds < int64(b.minSyncInterval.Seconds()) {
|
||||
list = append(list, field.Invalid(field.NewPath("spec", "sync", "intervalSeconds"),
|
||||
cfg.Spec.Sync.IntervalSeconds, fmt.Sprintf("Interval must be at least %d seconds", int64(b.minSyncInterval.Seconds()))))
|
||||
}
|
||||
|
||||
if !b.allowImageRendering && cfg.Spec.GitHub != nil && cfg.Spec.GitHub.GenerateDashboardPreviews {
|
||||
list = append(list,
|
||||
field.Invalid(field.NewPath("spec", "generateDashboardPreviews"),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,114 @@
|
|||
package provisioning
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apiserver/pkg/admission"
|
||||
"k8s.io/apiserver/pkg/authentication/user"
|
||||
|
||||
"github.com/grafana/grafana/apps/provisioning/pkg/apis/provisioning/v0alpha1"
|
||||
"github.com/grafana/grafana/apps/provisioning/pkg/repository"
|
||||
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestAPIBuilderValidate(t *testing.T) {
|
||||
factory := repository.NewMockFactory(t)
|
||||
mockRepo := repository.NewMockConfigRepository(t)
|
||||
mockRepo.EXPECT().Validate().Return(nil)
|
||||
factory.EXPECT().Build(mock.Anything, mock.Anything).Return(mockRepo, nil)
|
||||
b := &APIBuilder{
|
||||
repoFactory: factory,
|
||||
allowedTargets: []v0alpha1.SyncTargetType{v0alpha1.SyncTargetTypeFolder},
|
||||
allowImageRendering: false,
|
||||
minSyncInterval: 30 * time.Second,
|
||||
}
|
||||
|
||||
t.Run("min sync interval is less than 10 seconds", func(t *testing.T) {
|
||||
cfg := &v0alpha1.Repository{
|
||||
Spec: v0alpha1.RepositorySpec{
|
||||
Title: "repo",
|
||||
Type: v0alpha1.GitHubRepositoryType,
|
||||
Sync: v0alpha1.SyncOptions{Enabled: true, Target: v0alpha1.SyncTargetTypeFolder, IntervalSeconds: 5},
|
||||
},
|
||||
}
|
||||
mockRepo.EXPECT().Config().Return(cfg)
|
||||
|
||||
obj := newRepoObj("repo1", "default", cfg.Spec, v0alpha1.RepositoryStatus{})
|
||||
err := b.Validate(context.Background(), newAttributes(obj, nil, admission.Create), nil)
|
||||
require.Error(t, err)
|
||||
require.True(t, apierrors.IsInvalid(err))
|
||||
})
|
||||
|
||||
t.Run("image rendering is not enabled", func(t *testing.T) {
|
||||
cfg2 := &v0alpha1.Repository{
|
||||
Spec: v0alpha1.RepositorySpec{
|
||||
Title: "repo",
|
||||
Type: v0alpha1.GitHubRepositoryType,
|
||||
Sync: v0alpha1.SyncOptions{Enabled: false, Target: v0alpha1.SyncTargetTypeFolder},
|
||||
GitHub: &v0alpha1.GitHubRepositoryConfig{URL: "https://github.com/acme/repo", Branch: "main", GenerateDashboardPreviews: true},
|
||||
},
|
||||
}
|
||||
mockRepo.EXPECT().Config().Return(cfg2)
|
||||
|
||||
obj := newRepoObj("repo2", "default", cfg2.Spec, v0alpha1.RepositoryStatus{})
|
||||
err := b.Validate(context.Background(), newAttributes(obj, nil, admission.Create), nil)
|
||||
require.Error(t, err)
|
||||
require.True(t, apierrors.IsInvalid(err))
|
||||
})
|
||||
|
||||
t.Run("sync target is not supported", func(t *testing.T) {
|
||||
cfg3 := &v0alpha1.Repository{
|
||||
Spec: v0alpha1.RepositorySpec{
|
||||
Title: "repo",
|
||||
Type: v0alpha1.GitHubRepositoryType,
|
||||
Sync: v0alpha1.SyncOptions{Enabled: true, Target: v0alpha1.SyncTargetTypeInstance},
|
||||
},
|
||||
}
|
||||
mockRepo.EXPECT().Config().Return(cfg3)
|
||||
|
||||
obj := newRepoObj("repo3", "default", cfg3.Spec, v0alpha1.RepositoryStatus{})
|
||||
err := b.Validate(context.Background(), newAttributes(obj, nil, admission.Create), nil)
|
||||
require.Error(t, err)
|
||||
require.True(t, apierrors.IsInvalid(err))
|
||||
})
|
||||
}
|
||||
|
||||
func newRepoObj(name string, ns string, spec v0alpha1.RepositorySpec, status v0alpha1.RepositoryStatus) *v0alpha1.Repository {
|
||||
return &v0alpha1.Repository{
|
||||
TypeMeta: metav1.TypeMeta{APIVersion: v0alpha1.APIVERSION, Kind: "Repository"},
|
||||
ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: ns},
|
||||
Spec: spec,
|
||||
Status: status,
|
||||
}
|
||||
}
|
||||
|
||||
func newAttributes(obj, old runtime.Object, op admission.Operation) admission.Attributes {
|
||||
return admission.NewAttributesRecord(
|
||||
obj,
|
||||
old,
|
||||
v0alpha1.RepositoryResourceInfo.GroupVersionKind(),
|
||||
"default",
|
||||
func() string {
|
||||
if obj != nil {
|
||||
return obj.(*v0alpha1.Repository).Name
|
||||
}
|
||||
if old != nil {
|
||||
return old.(*v0alpha1.Repository).Name
|
||||
}
|
||||
return ""
|
||||
}(),
|
||||
v0alpha1.RepositoryResourceInfo.GroupVersionResource(),
|
||||
"",
|
||||
op,
|
||||
nil,
|
||||
false,
|
||||
&user.DefaultInfo{},
|
||||
)
|
||||
}
|
||||
|
|
@ -515,9 +515,8 @@ func (r *DualReadWriter) authorize(ctx context.Context, parsed *ParsedResource,
|
|||
Resource: parsed.GVR.Resource,
|
||||
Namespace: id.GetNamespace(),
|
||||
Name: name,
|
||||
Folder: parsed.Meta.GetFolder(),
|
||||
Verb: verb,
|
||||
})
|
||||
}, parsed.Meta.GetFolder())
|
||||
if err != nil || !rsp.Allowed {
|
||||
return apierrors.NewForbidden(parsed.GVR.GroupResource(), parsed.Obj.GetName(),
|
||||
fmt.Errorf("no access to read the embedded file"))
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ func (s *LocalInlineSecureValueService) canIdentityReadSecureValue(ctx context.C
|
|||
Resource: secretv1beta1.SecureValuesResourceInfo.GroupResource().Resource,
|
||||
Namespace: namespace.String(),
|
||||
Name: name,
|
||||
})
|
||||
}, "")
|
||||
if err != nil {
|
||||
return fmt.Errorf("checking access for secure value %s: %w", name, err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -187,7 +187,7 @@ func (s *ModuleServer) Run() error {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return sql.ProvideUnifiedStorageGrpcService(s.cfg, s.features, nil, s.log, s.registerer, docBuilders, s.storageMetrics, s.indexMetrics, s.searchServerRing, s.MemberlistKVConfig)
|
||||
return sql.ProvideUnifiedStorageGrpcService(s.cfg, s.features, nil, s.log, s.registerer, docBuilders, s.storageMetrics, s.indexMetrics, s.searchServerRing, s.MemberlistKVConfig, s.httpServerRouter)
|
||||
})
|
||||
|
||||
m.RegisterModule(modules.ZanzanaServer, func() (services.Service, error) {
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ type LegacyAccessClient struct {
|
|||
opts map[string]ResourceAuthorizerOptions
|
||||
}
|
||||
|
||||
func (c *LegacyAccessClient) Check(ctx context.Context, id claims.AuthInfo, req claims.CheckRequest) (claims.CheckResponse, error) {
|
||||
func (c *LegacyAccessClient) Check(ctx context.Context, id claims.AuthInfo, req claims.CheckRequest, folder string) (claims.CheckResponse, error) {
|
||||
ident, ok := id.(identity.Requester)
|
||||
if !ok {
|
||||
return claims.CheckResponse{}, errors.New("expected identity.Requester for legacy access control")
|
||||
|
|
@ -140,6 +140,9 @@ func (c *LegacyAccessClient) Check(ctx context.Context, id claims.AuthInfo, req
|
|||
return claims.CheckResponse{}, err
|
||||
}
|
||||
|
||||
// NOTE: folder is looked up again in the evaluator:
|
||||
// pkg/services/accesscontrol/acimpl/accesscontrol.go#L77
|
||||
|
||||
return claims.CheckResponse{Allowed: allowed}, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ func TestLegacyAccessClient_Check(t *testing.T) {
|
|||
Resource: "dashboards",
|
||||
Namespace: "default",
|
||||
Name: "1",
|
||||
})
|
||||
}, "")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, false, res.Allowed)
|
||||
})
|
||||
|
|
@ -47,7 +47,7 @@ func TestLegacyAccessClient_Check(t *testing.T) {
|
|||
Namespace: "default",
|
||||
Resource: "dashboards",
|
||||
Name: "1",
|
||||
})
|
||||
}, "")
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, false, res.Allowed)
|
||||
|
|
@ -70,7 +70,7 @@ func TestLegacyAccessClient_Check(t *testing.T) {
|
|||
Verb: "list",
|
||||
Namespace: "default",
|
||||
Resource: "dashboards",
|
||||
})
|
||||
}, "")
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, true, res.Allowed)
|
||||
|
|
@ -94,7 +94,7 @@ func TestLegacyAccessClient_Check(t *testing.T) {
|
|||
Namespace: "default",
|
||||
Resource: "dashboards",
|
||||
Name: "1",
|
||||
})
|
||||
}, "")
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, true, res.Allowed)
|
||||
|
|
@ -119,7 +119,7 @@ func TestLegacyAccessClient_Check(t *testing.T) {
|
|||
Namespace: "default",
|
||||
Resource: "dashboards",
|
||||
Name: "1",
|
||||
})
|
||||
}, "")
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, true, res.Allowed)
|
||||
|
|
@ -129,7 +129,7 @@ func TestLegacyAccessClient_Check(t *testing.T) {
|
|||
Namespace: "default",
|
||||
Resource: "dashboards",
|
||||
Name: "1",
|
||||
})
|
||||
}, "")
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, false, res.Allowed)
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ func (r ResourceAuthorizer) Authorize(ctx context.Context, attr authorizer.Attri
|
|||
Name: attr.GetName(),
|
||||
Subresource: attr.GetSubresource(),
|
||||
Path: attr.GetPath(),
|
||||
})
|
||||
}, "") // NOTE: we do not know the folder in this context
|
||||
|
||||
if err != nil {
|
||||
return authorizer.DecisionDeny, "", err
|
||||
|
|
|
|||
|
|
@ -3,11 +3,12 @@ package client
|
|||
import (
|
||||
"context"
|
||||
|
||||
"go.opentelemetry.io/otel"
|
||||
"google.golang.org/grpc"
|
||||
|
||||
authzlib "github.com/grafana/authlib/authz"
|
||||
authzv1 "github.com/grafana/authlib/authz/proto/v1"
|
||||
authlib "github.com/grafana/authlib/types"
|
||||
"go.opentelemetry.io/otel"
|
||||
"google.golang.org/grpc"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
authzextv1 "github.com/grafana/grafana/pkg/services/authz/proto/v1"
|
||||
|
|
@ -36,11 +37,11 @@ func New(cc grpc.ClientConnInterface) (*Client, error) {
|
|||
return c, nil
|
||||
}
|
||||
|
||||
func (c *Client) Check(ctx context.Context, id authlib.AuthInfo, req authlib.CheckRequest) (authlib.CheckResponse, error) {
|
||||
func (c *Client) Check(ctx context.Context, id authlib.AuthInfo, req authlib.CheckRequest, folder string) (authlib.CheckResponse, error) {
|
||||
ctx, span := tracer.Start(ctx, "authlib.zanzana.client.Check")
|
||||
defer span.End()
|
||||
|
||||
return c.authzlibclient.Check(ctx, id, req)
|
||||
return c.authzlibclient.Check(ctx, id, req, folder)
|
||||
}
|
||||
|
||||
func (c *Client) Compile(ctx context.Context, id authlib.AuthInfo, req authlib.ListRequest) (authlib.ItemChecker, authlib.Zookie, error) {
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ func NewNoop() *NoopClient {
|
|||
|
||||
type NoopClient struct{}
|
||||
|
||||
func (nc *NoopClient) Check(ctx context.Context, id authlib.AuthInfo, req authlib.CheckRequest) (authlib.CheckResponse, error) {
|
||||
func (nc *NoopClient) Check(ctx context.Context, id authlib.AuthInfo, req authlib.CheckRequest, folder string) (authlib.CheckResponse, error) {
|
||||
return authlib.CheckResponse{}, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ package client
|
|||
import (
|
||||
"context"
|
||||
|
||||
authlib "github.com/grafana/authlib/types"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
|
||||
authlib "github.com/grafana/authlib/types"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
)
|
||||
|
||||
|
|
@ -29,7 +29,7 @@ func WithShadowClient(accessClient authlib.AccessClient, zanzanaClient authlib.A
|
|||
return client
|
||||
}
|
||||
|
||||
func (c *ShadowClient) Check(ctx context.Context, id authlib.AuthInfo, req authlib.CheckRequest) (authlib.CheckResponse, error) {
|
||||
func (c *ShadowClient) Check(ctx context.Context, id authlib.AuthInfo, req authlib.CheckRequest, folder string) (authlib.CheckResponse, error) {
|
||||
acResChan := make(chan authlib.CheckResponse, 1)
|
||||
acErrChan := make(chan error, 1)
|
||||
|
||||
|
|
@ -42,7 +42,7 @@ func (c *ShadowClient) Check(ctx context.Context, id authlib.AuthInfo, req authl
|
|||
defer timer.ObserveDuration()
|
||||
|
||||
zanzanaCtx := context.WithoutCancel(ctx)
|
||||
res, err := c.zanzanaClient.Check(zanzanaCtx, id, req)
|
||||
res, err := c.zanzanaClient.Check(zanzanaCtx, id, req, folder)
|
||||
if err != nil {
|
||||
c.logger.Error("Failed to run zanzana check", "error", err)
|
||||
}
|
||||
|
|
@ -61,7 +61,7 @@ func (c *ShadowClient) Check(ctx context.Context, id authlib.AuthInfo, req authl
|
|||
}()
|
||||
|
||||
timer := prometheus.NewTimer(c.metrics.evaluationsSeconds.WithLabelValues("rbac"))
|
||||
res, err := c.accessClient.Check(ctx, id, req)
|
||||
res, err := c.accessClient.Check(ctx, id, req, folder)
|
||||
timer.ObserveDuration()
|
||||
acResChan <- res
|
||||
acErrChan <- err
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import (
|
|||
openfgav1 "github.com/openfga/api/proto/openfga/v1"
|
||||
|
||||
authlib "github.com/grafana/authlib/types"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/authz/zanzana/common"
|
||||
)
|
||||
|
||||
|
|
@ -123,7 +122,7 @@ func MergeFolderResourceTuples(a, b *openfgav1.TupleKey) {
|
|||
va.GetListValue().Values = append(va.GetListValue().Values, vb.GetListValue().Values...)
|
||||
}
|
||||
|
||||
func TranslateToCheckRequest(namespace, action, kind, folder, name string) (*authlib.CheckRequest, bool) {
|
||||
func TranslateToCheckRequest(namespace, action, kind, name string) (*authlib.CheckRequest, bool) {
|
||||
translation, ok := resourceTranslations[kind]
|
||||
|
||||
if !ok {
|
||||
|
|
@ -146,7 +145,6 @@ func TranslateToCheckRequest(namespace, action, kind, folder, name string) (*aut
|
|||
Group: translation.group,
|
||||
Resource: translation.resource,
|
||||
Name: name,
|
||||
Folder: folder,
|
||||
}
|
||||
|
||||
return req, true
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import (
|
|||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
dashver "github.com/grafana/grafana/pkg/services/dashboardversion"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
"github.com/grafana/grafana/pkg/services/libraryelements/model"
|
||||
"github.com/grafana/grafana/pkg/services/quota"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||
|
|
@ -96,6 +97,7 @@ func (d *dashboardStore) GetDashboardsByLibraryPanelUID(ctx context.Context, lib
|
|||
return connectedDashboards, err
|
||||
}
|
||||
|
||||
// nolint:gocyclo
|
||||
func (d *dashboardStore) ValidateDashboardBeforeSave(ctx context.Context, dash *dashboards.Dashboard, overwrite bool) (bool, error) {
|
||||
ctx, span := tracer.Start(ctx, "dashboards.database.ValidateDashboardBeforesave")
|
||||
defer span.End()
|
||||
|
|
@ -107,7 +109,7 @@ func (d *dashboardStore) ValidateDashboardBeforeSave(ctx context.Context, dash *
|
|||
|
||||
// we don't save FolderID in kubernetes object when saving through k8s
|
||||
// this block guarantees we save dashboards with folder_id and folder_uid in those cases
|
||||
if !dash.IsFolder && dash.FolderUID != "" && dash.FolderID == 0 { // nolint:staticcheck
|
||||
if !dash.IsFolder && dash.FolderUID != "" && dash.FolderID == 0 && dash.FolderUID != folder.GeneralFolderUID { // nolint:staticcheck
|
||||
var existing dashboards.Dashboard
|
||||
folderIdFound, err := sess.Where("uid=? AND org_id=?", dash.FolderUID, dash.OrgID).Get(&existing)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -1520,6 +1520,16 @@ var (
|
|||
FrontendOnly: true,
|
||||
HideFromDocs: true,
|
||||
},
|
||||
{
|
||||
Name: "alertingUseNewSimplifiedRoutingHashAlgorithm",
|
||||
Description: "",
|
||||
Stage: FeatureStagePublicPreview,
|
||||
Owner: grafanaAlertingSquad,
|
||||
HideFromAdminPage: true,
|
||||
HideFromDocs: true,
|
||||
RequiresRestart: true,
|
||||
Expression: "true",
|
||||
},
|
||||
{
|
||||
Name: "useScopesNavigationEndpoint",
|
||||
Description: "Use the scopes navigation endpoint instead of the dashboardbindings endpoint",
|
||||
|
|
|
|||
|
|
@ -198,6 +198,7 @@ fetchRulesUsingPost,experimental,@grafana/alerting-squad,false,false,false
|
|||
newLogsPanel,experimental,@grafana/observability-logs,false,false,true
|
||||
grafanaconThemes,GA,@grafana/grafana-frontend-platform,false,true,false
|
||||
alertingJiraIntegration,experimental,@grafana/alerting-squad,false,false,true
|
||||
alertingUseNewSimplifiedRoutingHashAlgorithm,preview,@grafana/alerting-squad,false,true,false
|
||||
useScopesNavigationEndpoint,experimental,@grafana/grafana-frontend-platform,false,false,true
|
||||
scopeSearchAllLevels,experimental,@grafana/grafana-frontend-platform,false,false,false
|
||||
alertingRuleVersionHistoryRestore,GA,@grafana/alerting-squad,false,false,true
|
||||
|
|
|
|||
|
|
|
@ -803,6 +803,9 @@ const (
|
|||
// Enables the new Jira integration for contact points in cloud alert managers.
|
||||
FlagAlertingJiraIntegration = "alertingJiraIntegration"
|
||||
|
||||
// FlagAlertingUseNewSimplifiedRoutingHashAlgorithm
|
||||
FlagAlertingUseNewSimplifiedRoutingHashAlgorithm = "alertingUseNewSimplifiedRoutingHashAlgorithm"
|
||||
|
||||
// FlagUseScopesNavigationEndpoint
|
||||
// Use the scopes navigation endpoint instead of the dashboardbindings endpoint
|
||||
FlagUseScopesNavigationEndpoint = "useScopesNavigationEndpoint"
|
||||
|
|
|
|||
|
|
@ -610,6 +610,46 @@
|
|||
"expression": "true"
|
||||
}
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"name": "alertingUseNewSimplifiedRoutingHashAlgorithm",
|
||||
"resourceVersion": "1759339813575",
|
||||
"creationTimestamp": "2025-10-01T17:28:42Z",
|
||||
"deletionTimestamp": "2025-10-01T17:29:29Z",
|
||||
"annotations": {
|
||||
"grafana.app/updatedTimestamp": "2025-10-01 17:30:13.575464 +0000 UTC"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"description": "",
|
||||
"stage": "preview",
|
||||
"codeowner": "@grafana/alerting-squad",
|
||||
"requiresRestart": true,
|
||||
"hideFromAdminPage": true,
|
||||
"hideFromDocs": true,
|
||||
"expression": "true"
|
||||
}
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"name": "alertingUseOldSimplifiedRoutingHashAlgorithm",
|
||||
"resourceVersion": "1759339782639",
|
||||
"creationTimestamp": "2025-10-01T17:29:29Z",
|
||||
"deletionTimestamp": "2025-10-01T17:30:13Z",
|
||||
"annotations": {
|
||||
"grafana.app/updatedTimestamp": "2025-10-01 17:29:42.63941 +0000 UTC"
|
||||
}
|
||||
},
|
||||
"spec": {
|
||||
"description": "",
|
||||
"stage": "deprecated",
|
||||
"codeowner": "@grafana/alerting-squad",
|
||||
"requiresRestart": true,
|
||||
"hideFromAdminPage": true,
|
||||
"hideFromDocs": true,
|
||||
"expression": "false"
|
||||
}
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"name": "alertmanagerRemotePrimary",
|
||||
|
|
|
|||
|
|
@ -48,7 +48,6 @@ const (
|
|||
NavIDAlerting = "alerting"
|
||||
NavIDObservability = "observability"
|
||||
NavIDInfrastructure = "infrastructure"
|
||||
NavIDFrontend = "frontend"
|
||||
NavIDReporting = "reports"
|
||||
NavIDApps = "apps"
|
||||
NavIDCfgGeneral = "cfg/general"
|
||||
|
|
|
|||
|
|
@ -260,10 +260,21 @@ func (s *ServiceImpl) addPluginToSection(c *contextmodel.ReqContext, treeRoot *n
|
|||
}
|
||||
}
|
||||
|
||||
sectionChildren := []*navtree.NavLink{appLink}
|
||||
// asserts pages expand to root Observability section instead of it's own node
|
||||
if plugin.ID == "grafana-asserts-app" {
|
||||
sectionChildren = appLink.Children
|
||||
|
||||
// keep current sorting if the pages, but above all the other apps
|
||||
for _, child := range sectionChildren {
|
||||
child.SortWeight = -100 + child.SortWeight
|
||||
}
|
||||
}
|
||||
|
||||
if sectionID == navtree.NavIDRoot {
|
||||
treeRoot.AddSection(appLink)
|
||||
} else if navNode := treeRoot.FindById(sectionID); navNode != nil {
|
||||
navNode.Children = append(navNode.Children, appLink)
|
||||
navNode.Children = append(navNode.Children, sectionChildren...)
|
||||
} else {
|
||||
switch sectionID {
|
||||
case navtree.NavIDApps:
|
||||
|
|
@ -272,18 +283,19 @@ func (s *ServiceImpl) addPluginToSection(c *contextmodel.ReqContext, treeRoot *n
|
|||
Icon: "layer-group",
|
||||
SubTitle: "App plugins that extend the Grafana experience",
|
||||
Id: navtree.NavIDApps,
|
||||
Children: []*navtree.NavLink{appLink},
|
||||
Children: sectionChildren,
|
||||
SortWeight: navtree.WeightApps,
|
||||
Url: s.cfg.AppSubURL + "/apps",
|
||||
})
|
||||
case navtree.NavIDObservability:
|
||||
|
||||
treeRoot.AddSection(&navtree.NavLink{
|
||||
Text: "Observability",
|
||||
Id: navtree.NavIDObservability,
|
||||
SubTitle: "Monitor infrastructure and applications in real time with Grafana Cloud's fully managed observability suite",
|
||||
Icon: "heart-rate",
|
||||
SortWeight: navtree.WeightObservability,
|
||||
Children: []*navtree.NavLink{appLink},
|
||||
Children: sectionChildren,
|
||||
Url: s.cfg.AppSubURL + "/observability",
|
||||
})
|
||||
case navtree.NavIDInfrastructure:
|
||||
|
|
@ -293,19 +305,9 @@ func (s *ServiceImpl) addPluginToSection(c *contextmodel.ReqContext, treeRoot *n
|
|||
SubTitle: "Understand your infrastructure's health",
|
||||
Icon: "heart-rate",
|
||||
SortWeight: navtree.WeightInfrastructure,
|
||||
Children: []*navtree.NavLink{appLink},
|
||||
Children: sectionChildren,
|
||||
Url: s.cfg.AppSubURL + "/infrastructure",
|
||||
})
|
||||
case navtree.NavIDFrontend:
|
||||
treeRoot.AddSection(&navtree.NavLink{
|
||||
Text: "Frontend",
|
||||
Id: navtree.NavIDFrontend,
|
||||
SubTitle: "Gain real user monitoring insights",
|
||||
Icon: "frontend-observability",
|
||||
SortWeight: navtree.WeightFrontend,
|
||||
Children: []*navtree.NavLink{appLink},
|
||||
Url: s.cfg.AppSubURL + "/frontend",
|
||||
})
|
||||
case navtree.NavIDAlertsAndIncidents:
|
||||
alertsAndIncidentsChildren := []*navtree.NavLink{}
|
||||
for _, alertingNode := range alertingNodes {
|
||||
|
|
@ -332,7 +334,7 @@ func (s *ServiceImpl) addPluginToSection(c *contextmodel.ReqContext, treeRoot *n
|
|||
SubTitle: "Optimize performance with k6 and Synthetic Monitoring insights",
|
||||
Icon: "k6",
|
||||
SortWeight: navtree.WeightTestingAndSynthetics,
|
||||
Children: []*navtree.NavLink{appLink},
|
||||
Children: sectionChildren,
|
||||
Url: s.cfg.AppSubURL + "/testing-and-synthetics",
|
||||
})
|
||||
case navtree.NavIDAdaptiveTelemetry:
|
||||
|
|
@ -372,11 +374,11 @@ func (s *ServiceImpl) hasAccessToInclude(c *contextmodel.ReqContext, pluginID st
|
|||
func (s *ServiceImpl) readNavigationSettings() {
|
||||
s.navigationAppConfig = map[string]NavigationAppConfig{
|
||||
"grafana-asserts-app": {SectionID: navtree.NavIDObservability, SortWeight: 1, Icon: "asserts"},
|
||||
"grafana-app-observability-app": {SectionID: navtree.NavIDObservability, SortWeight: 2, Text: "Application"},
|
||||
"grafana-csp-app": {SectionID: navtree.NavIDObservability, SortWeight: 3, Icon: "cloud-provider"},
|
||||
"grafana-k8s-app": {SectionID: navtree.NavIDObservability, SortWeight: 4, Text: "Kubernetes"},
|
||||
"grafana-dbo11y-app": {SectionID: navtree.NavIDObservability, SortWeight: 5, Text: "Database"},
|
||||
"grafana-kowalski-app": {SectionID: navtree.NavIDObservability, SortWeight: 6, Text: "Frontend"},
|
||||
"grafana-kowalski-app": {SectionID: navtree.NavIDObservability, SortWeight: 2, Text: "Frontend"},
|
||||
"grafana-app-observability-app": {SectionID: navtree.NavIDObservability, SortWeight: 3, Text: "Application"},
|
||||
"grafana-dbo11y-app": {SectionID: navtree.NavIDObservability, SortWeight: 4, Text: "Database"},
|
||||
"grafana-k8s-app": {SectionID: navtree.NavIDObservability, SortWeight: 5, Text: "Kubernetes"},
|
||||
"grafana-csp-app": {SectionID: navtree.NavIDObservability, SortWeight: 6, Icon: "cloud-provider"},
|
||||
"grafana-metricsdrilldown-app": {SectionID: navtree.NavIDDrilldown, SortWeight: 1, Text: "Metrics"},
|
||||
"grafana-lokiexplore-app": {SectionID: navtree.NavIDDrilldown, SortWeight: 2, Text: "Logs"},
|
||||
"grafana-exploretraces-app": {SectionID: navtree.NavIDDrilldown, SortWeight: 3, Text: "Traces"},
|
||||
|
|
|
|||
|
|
@ -387,7 +387,7 @@ func TestReadingNavigationSettings(t *testing.T) {
|
|||
require.Equal(t, "dashboards", service.navigationAppConfig["grafana-k8s-app"].SectionID)
|
||||
require.Equal(t, "admin", service.navigationAppConfig["other-app"].SectionID)
|
||||
|
||||
require.Equal(t, int64(4), service.navigationAppConfig["grafana-k8s-app"].SortWeight)
|
||||
require.Equal(t, int64(5), service.navigationAppConfig["grafana-k8s-app"].SortWeight)
|
||||
require.Equal(t, int64(12), service.navigationAppConfig["other-app"].SortWeight)
|
||||
|
||||
require.Equal(t, "admin", service.navigationAppPathConfig["/a/grafana-k8s-app/foo"].SectionID)
|
||||
|
|
|
|||
|
|
@ -291,7 +291,8 @@ func TestAlertmanagerAutogenConfig(t *testing.T) {
|
|||
1: {AlertmanagerConfiguration: validConfig, OrgID: 1},
|
||||
2: {AlertmanagerConfiguration: validConfigWithoutAutogen, OrgID: 2},
|
||||
}
|
||||
sut.mam = createMultiOrgAlertmanager(t, configs)
|
||||
ft := featuremgmt.WithFeatures(featuremgmt.FlagAlertingUseNewSimplifiedRoutingHashAlgorithm)
|
||||
sut.mam = createMultiOrgAlertmanager(t, configs, withAMFeatureToggles(ft))
|
||||
return sut, configs
|
||||
}
|
||||
|
||||
|
|
@ -577,9 +578,29 @@ func createSut(t *testing.T) AlertmanagerSrv {
|
|||
}
|
||||
}
|
||||
|
||||
func createMultiOrgAlertmanager(t *testing.T, configs map[int64]*ngmodels.AlertConfiguration) *notifier.MultiOrgAlertmanager {
|
||||
type createMultiOrgAMOptions struct {
|
||||
featureToggles featuremgmt.FeatureToggles
|
||||
}
|
||||
|
||||
type createMultiOrgAMOptionsFunc func(*createMultiOrgAMOptions)
|
||||
|
||||
func withAMFeatureToggles(toggles featuremgmt.FeatureToggles) createMultiOrgAMOptionsFunc {
|
||||
return func(opts *createMultiOrgAMOptions) {
|
||||
opts.featureToggles = toggles
|
||||
}
|
||||
}
|
||||
|
||||
func createMultiOrgAlertmanager(t *testing.T, configs map[int64]*ngmodels.AlertConfiguration, opts ...createMultiOrgAMOptionsFunc) *notifier.MultiOrgAlertmanager {
|
||||
t.Helper()
|
||||
|
||||
options := createMultiOrgAMOptions{
|
||||
featureToggles: featuremgmt.WithFeatures(),
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(&options)
|
||||
}
|
||||
|
||||
configStore := notifier.NewFakeConfigStore(t, configs)
|
||||
orgStore := notifier.NewFakeOrgStore(t, []int64{1, 2, 3})
|
||||
provStore := ngfakes.NewFakeProvisioningStore()
|
||||
|
|
@ -610,7 +631,7 @@ func createMultiOrgAlertmanager(t *testing.T, configs map[int64]*ngmodels.AlertC
|
|||
ngfakes.NewFakeReceiverPermissionsService(),
|
||||
log.New("testlogger"),
|
||||
secretsService,
|
||||
featuremgmt.WithManager(),
|
||||
options.featureToggles,
|
||||
nil,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ func (srv TestingApiSrv) RouteTestGrafanaRuleConfig(c *contextmodel.ReqContext,
|
|||
now,
|
||||
rule,
|
||||
results,
|
||||
state.GetRuleExtraLabels(log.New("testing"), rule, folder.Fullpath, includeFolder),
|
||||
state.GetRuleExtraLabels(log.New("testing"), rule, folder.Fullpath, includeFolder, srv.featureManager),
|
||||
nil,
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import (
|
|||
"unsafe"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/data"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/prometheus/common/model"
|
||||
)
|
||||
|
||||
|
|
@ -102,12 +103,12 @@ func (s *NotificationSettings) Validate() error {
|
|||
// - AutogeneratedRouteLabel: "true"
|
||||
// - AutogeneratedRouteReceiverNameLabel: Receiver
|
||||
// - AutogeneratedRouteSettingsHashLabel: Fingerprint (if the NotificationSettings are not all default)
|
||||
func (s *NotificationSettings) ToLabels() data.Labels {
|
||||
func (s *NotificationSettings) ToLabels(features featuremgmt.FeatureToggles) data.Labels {
|
||||
result := make(data.Labels, 3)
|
||||
result[AutogeneratedRouteLabel] = "true"
|
||||
result[AutogeneratedRouteReceiverNameLabel] = s.Receiver
|
||||
if !s.IsAllDefault() {
|
||||
result[AutogeneratedRouteSettingsHashLabel] = s.Fingerprint().String()
|
||||
result[AutogeneratedRouteSettingsHashLabel] = s.Fingerprint(features).String()
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
|
@ -160,7 +161,7 @@ func NewDefaultNotificationSettings(receiver string) NotificationSettings {
|
|||
// Fingerprint calculates a hash value to uniquely identify a NotificationSettings by its attributes.
|
||||
// The hash is calculated by concatenating the strings and durations of the NotificationSettings attributes
|
||||
// and using an invalid UTF-8 sequence as a separator.
|
||||
func (s *NotificationSettings) Fingerprint() data.Fingerprint {
|
||||
func (s *NotificationSettings) Fingerprint(features featuremgmt.FeatureToggles) data.Fingerprint {
|
||||
h := fnv.New64()
|
||||
tmp := make([]byte, 8)
|
||||
|
||||
|
|
@ -192,7 +193,10 @@ func (s *NotificationSettings) Fingerprint() data.Fingerprint {
|
|||
}
|
||||
// Add a separator between the time intervals to avoid collisions
|
||||
// when all settings are the same including interval names except for the interval type (mute vs active).
|
||||
_, _ = h.Write([]byte{255})
|
||||
// Use new algorithm by default, unless feature flag is explicitly disabled
|
||||
if features == nil || (features != nil && features.IsEnabledGlobally(featuremgmt.FlagAlertingUseNewSimplifiedRoutingHashAlgorithm)) {
|
||||
_, _ = h.Write([]byte{255})
|
||||
}
|
||||
for _, interval := range s.ActiveTimeIntervals {
|
||||
writeString(interval)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -195,7 +195,7 @@ func TestNotificationSettingsLabels(t *testing.T) {
|
|||
|
||||
for _, tt := range testCases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
labels := tt.notificationSettings.ToLabels()
|
||||
labels := tt.notificationSettings.ToLabels(nil)
|
||||
require.Equal(t, tt.labels, labels)
|
||||
})
|
||||
}
|
||||
|
|
@ -219,7 +219,7 @@ func TestNotificationSettings_TimeIntervals(t *testing.T) {
|
|||
ActiveTimeIntervals: []string{timeInterval},
|
||||
}
|
||||
|
||||
require.NotEqual(t, activeSettings.Fingerprint(), muteSettings.Fingerprint())
|
||||
require.NotEqual(t, activeSettings.Fingerprint(nil), muteSettings.Fingerprint(nil))
|
||||
}
|
||||
|
||||
func TestNormalizedGroupBy(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -220,7 +220,7 @@ func (ng *AlertNG) init() error {
|
|||
Timeout: ng.Cfg.UnifiedAlerting.RemoteAlertmanager.Timeout,
|
||||
}
|
||||
autogenFn := func(ctx context.Context, logger log.Logger, orgID int64, cfg *definitions.PostableApiAlertingConfig, skipInvalid bool) error {
|
||||
return notifier.AddAutogenConfig(ctx, logger, ng.store, orgID, cfg, skipInvalid)
|
||||
return notifier.AddAutogenConfig(ctx, logger, ng.store, orgID, cfg, skipInvalid, ng.FeatureToggles)
|
||||
}
|
||||
|
||||
// This function will be used by the MOA to create new Alertmanagers.
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ type alertmanager struct {
|
|||
DefaultConfiguration string
|
||||
decryptFn alertingNotify.GetDecryptedValueFn
|
||||
crypto Crypto
|
||||
features featuremgmt.FeatureToggles
|
||||
}
|
||||
|
||||
// maintenanceOptions represent the options for components that need maintenance on a frequency within the Alertmanager.
|
||||
|
|
@ -155,6 +156,7 @@ func NewAlertmanager(ctx context.Context, orgID int64, cfg *setting.Cfg, store A
|
|||
logger: l.New("component", "alertmanager", opts.TenantKey, opts.TenantID), // similar to what the base does
|
||||
decryptFn: decryptFn,
|
||||
crypto: crypto,
|
||||
features: featureToggles,
|
||||
}
|
||||
|
||||
return am, nil
|
||||
|
|
@ -344,7 +346,7 @@ func (am *alertmanager) applyConfig(ctx context.Context, cfg *apimodels.Postable
|
|||
templates := alertingNotify.PostableAPITemplatesToTemplateDefinitions(cfg.GetMergedTemplateDefinitions())
|
||||
|
||||
// Now add autogenerated config to the route.
|
||||
err = AddAutogenConfig(ctx, am.logger, am.Store, am.Base.TenantID(), &amConfig, skipInvalid)
|
||||
err = AddAutogenConfig(ctx, am.logger, am.Store, am.Base.TenantID(), &amConfig, skipInvalid, am.features)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -133,7 +133,7 @@ func (moa *MultiOrgAlertmanager) GetAlertmanagerConfiguration(ctx context.Contex
|
|||
// Otherwise, broken settings (e.g. a receiver that doesn't exist) will cause the config returned here to be
|
||||
// different than the config currently in-use.
|
||||
// TODO: Preferably, we'd be getting the config directly from the in-memory AM so adding the autogen config would not be necessary.
|
||||
err := AddAutogenConfig(ctx, moa.logger, moa.configStore, org, &cfg.AlertmanagerConfig, true)
|
||||
err := AddAutogenConfig(ctx, moa.logger, moa.configStore, org, &cfg.AlertmanagerConfig, true, moa.featureManager)
|
||||
if err != nil {
|
||||
return definitions.GettableUserConfig{}, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import (
|
|||
"golang.org/x/exp/maps"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||
)
|
||||
|
|
@ -22,8 +23,8 @@ type autogenRuleStore interface {
|
|||
|
||||
// AddAutogenConfig creates the autogenerated configuration and adds it to the given apiAlertingConfig.
|
||||
// If skipInvalid is true, then invalid notification settings are skipped, otherwise an error is returned.
|
||||
func AddAutogenConfig[R receiver](ctx context.Context, logger log.Logger, store autogenRuleStore, orgId int64, cfg apiAlertingConfig[R], skipInvalid bool) error {
|
||||
autogenRoute, err := newAutogeneratedRoute(ctx, logger, store, orgId, cfg, skipInvalid)
|
||||
func AddAutogenConfig[R receiver](ctx context.Context, logger log.Logger, store autogenRuleStore, orgId int64, cfg apiAlertingConfig[R], skipInvalid bool, features featuremgmt.FeatureToggles) error {
|
||||
autogenRoute, err := newAutogeneratedRoute(ctx, logger, store, orgId, cfg, skipInvalid, features)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -39,7 +40,7 @@ func AddAutogenConfig[R receiver](ctx context.Context, logger log.Logger, store
|
|||
// newAutogeneratedRoute creates a new autogenerated route based on the notification settings for the given org.
|
||||
// cfg is used to construct the settings validator and to ensure we create a dedicated route for each receiver.
|
||||
// skipInvalid is used to skip invalid settings instead of returning an error.
|
||||
func newAutogeneratedRoute[R receiver](ctx context.Context, logger log.Logger, store autogenRuleStore, orgId int64, cfg apiAlertingConfig[R], skipInvalid bool) (autogeneratedRoute, error) {
|
||||
func newAutogeneratedRoute[R receiver](ctx context.Context, logger log.Logger, store autogenRuleStore, orgId int64, cfg apiAlertingConfig[R], skipInvalid bool, features featuremgmt.FeatureToggles) (autogeneratedRoute, error) {
|
||||
settings, err := store.ListNotificationSettings(ctx, models.ListNotificationSettingsQuery{OrgID: orgId})
|
||||
if err != nil {
|
||||
return autogeneratedRoute{}, fmt.Errorf("failed to list alert rules: %w", err)
|
||||
|
|
@ -50,7 +51,7 @@ func newAutogeneratedRoute[R receiver](ctx context.Context, logger log.Logger, s
|
|||
// contact point even if no rules are using it. This will prevent race conditions between AM sync and rule sync.
|
||||
for _, receiver := range cfg.GetReceivers() {
|
||||
setting := models.NewDefaultNotificationSettings(receiver.GetName())
|
||||
fp := setting.Fingerprint()
|
||||
fp := setting.Fingerprint(features)
|
||||
notificationSettings[fp] = setting
|
||||
}
|
||||
|
||||
|
|
@ -65,7 +66,7 @@ func newAutogeneratedRoute[R receiver](ctx context.Context, logger log.Logger, s
|
|||
}
|
||||
return autogeneratedRoute{}, fmt.Errorf("invalid notification settings for rule %s: %w", ruleKey.UID, err)
|
||||
}
|
||||
fp := setting.Fingerprint()
|
||||
fp := setting.Fingerprint(features)
|
||||
// Keep only unique settings.
|
||||
if _, ok := notificationSettings[fp]; ok {
|
||||
continue
|
||||
|
|
|
|||
|
|
@ -290,7 +290,7 @@ func TestAddAutogenConfig(t *testing.T) {
|
|||
store.notificationSettings[orgId][models.AlertRuleKey{OrgID: orgId, UID: util.GenerateShortUID()}] = []models.NotificationSettings{setting}
|
||||
}
|
||||
|
||||
err := AddAutogenConfig(context.Background(), &logtest.Fake{}, store, orgId, tt.existingConfig, tt.skipInvalid)
|
||||
err := AddAutogenConfig(context.Background(), &logtest.Fake{}, store, orgId, tt.existingConfig, tt.skipInvalid, nil)
|
||||
if tt.expErrorContains != "" {
|
||||
require.Error(t, err)
|
||||
require.ErrorContains(t, err, tt.expErrorContains)
|
||||
|
|
|
|||
|
|
@ -471,7 +471,7 @@ func (a *alertRule) evaluate(ctx context.Context, e *Evaluation, span trace.Span
|
|||
e.scheduledAt,
|
||||
e.rule,
|
||||
results,
|
||||
state.GetRuleExtraLabels(logger, e.rule, e.folderTitle, !a.disableGrafanaFolder),
|
||||
state.GetRuleExtraLabels(logger, e.rule, e.folderTitle, !a.disableGrafanaFolder, a.featureToggles),
|
||||
func(ctx context.Context, statesToSend state.StateTransitions) {
|
||||
start := a.clock.Now()
|
||||
alerts := a.send(ctx, logger, statesToSend)
|
||||
|
|
|
|||
|
|
@ -1317,7 +1317,7 @@ func stateForRule(rule *models.AlertRule, ts time.Time, evalState eval.State) *s
|
|||
for k, v := range rule.Labels {
|
||||
s.Labels[k] = v
|
||||
}
|
||||
for k, v := range state.GetRuleExtraLabels(&logtest.Fake{}, rule, "", true) {
|
||||
for k, v := range state.GetRuleExtraLabels(&logtest.Fake{}, rule, "", true, nil) {
|
||||
if _, ok := s.Labels[k]; !ok {
|
||||
s.Labels[k] = v
|
||||
}
|
||||
|
|
|
|||
|
|
@ -304,7 +304,7 @@ func (r ruleWithFolder) Fingerprint() fingerprint {
|
|||
}
|
||||
|
||||
for _, setting := range rule.NotificationSettings {
|
||||
binary.LittleEndian.PutUint64(tmp, uint64(setting.Fingerprint()))
|
||||
binary.LittleEndian.PutUint64(tmp, uint64(setting.Fingerprint(nil)))
|
||||
writeBytes(tmp)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import (
|
|||
"github.com/grafana/grafana/pkg/apimachinery/errutil"
|
||||
"github.com/grafana/grafana/pkg/expr"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/eval"
|
||||
"github.com/grafana/grafana/pkg/services/ngalert/models"
|
||||
"github.com/grafana/grafana/pkg/services/screenshot"
|
||||
|
|
@ -753,7 +754,7 @@ func ParseFormattedState(stateStr string) (eval.State, string, error) {
|
|||
}
|
||||
|
||||
// GetRuleExtraLabels returns a map of built-in labels that should be added to an alert before it is sent to the Alertmanager or its state is cached.
|
||||
func GetRuleExtraLabels(l log.Logger, rule *models.AlertRule, folderTitle string, includeFolder bool) map[string]string {
|
||||
func GetRuleExtraLabels(l log.Logger, rule *models.AlertRule, folderTitle string, includeFolder bool, features featuremgmt.FeatureToggles) map[string]string {
|
||||
extraLabels := make(map[string]string, 4)
|
||||
|
||||
extraLabels[alertingModels.NamespaceUIDLabel] = rule.NamespaceUID
|
||||
|
|
@ -771,7 +772,7 @@ func GetRuleExtraLabels(l log.Logger, rule *models.AlertRule, folderTitle string
|
|||
ignored, _ := json.Marshal(rule.NotificationSettings[1:])
|
||||
l.Error("Detected multiple notification settings, which is not supported. Only the first will be applied", "ignored_settings", string(ignored))
|
||||
}
|
||||
return mergeLabels(extraLabels, rule.NotificationSettings[0].ToLabels())
|
||||
return mergeLabels(extraLabels, rule.NotificationSettings[0].ToLabels(features))
|
||||
}
|
||||
return extraLabels
|
||||
}
|
||||
|
|
|
|||
|
|
@ -779,7 +779,7 @@ func TestGetRuleExtraLabels(t *testing.T) {
|
|||
models.RuleUIDLabel: rule.UID,
|
||||
ngmodels.AutogeneratedRouteLabel: "true",
|
||||
ngmodels.AutogeneratedRouteReceiverNameLabel: ns.Receiver,
|
||||
ngmodels.AutogeneratedRouteSettingsHashLabel: ns.Fingerprint().String(),
|
||||
ngmodels.AutogeneratedRouteSettingsHashLabel: ns.Fingerprint(nil).String(),
|
||||
},
|
||||
},
|
||||
"ignore_multiple_notifications": {
|
||||
|
|
@ -794,14 +794,14 @@ func TestGetRuleExtraLabels(t *testing.T) {
|
|||
models.RuleUIDLabel: rule.UID,
|
||||
ngmodels.AutogeneratedRouteLabel: "true",
|
||||
ngmodels.AutogeneratedRouteReceiverNameLabel: ns.Receiver,
|
||||
ngmodels.AutogeneratedRouteSettingsHashLabel: ns.Fingerprint().String(),
|
||||
ngmodels.AutogeneratedRouteSettingsHashLabel: ns.Fingerprint(nil).String(),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
result := GetRuleExtraLabels(logger, tc.rule, folderTitle, tc.includeFolder)
|
||||
result := GetRuleExtraLabels(logger, tc.rule, folderTitle, tc.includeFolder, nil)
|
||||
require.Equal(t, tc.expected, result)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -334,6 +334,9 @@ func filterOutSpecialDatasources(dash *DashboardSummaryInfo) {
|
|||
case "-- Dashboard --":
|
||||
// The `Dashboard` datasource refers to the results of the query used in another panel
|
||||
continue
|
||||
case "grafana":
|
||||
// this is the uid for the -- Grafana -- datasource
|
||||
continue
|
||||
default:
|
||||
dsRefs = append(dsRefs, ds)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,24 +2,12 @@
|
|||
"id": 250,
|
||||
"title": "fast streaming",
|
||||
"tags": null,
|
||||
"datasource": [
|
||||
{
|
||||
"uid": "grafana",
|
||||
"type": "datasource"
|
||||
}
|
||||
],
|
||||
"panels": [
|
||||
{
|
||||
"id": 3,
|
||||
"title": "Panel Title",
|
||||
"type": "timeseries",
|
||||
"pluginVersion": "7.5.0-pre",
|
||||
"datasource": [
|
||||
{
|
||||
"uid": "grafana",
|
||||
"type": "datasource"
|
||||
}
|
||||
]
|
||||
"pluginVersion": "7.5.0-pre"
|
||||
}
|
||||
],
|
||||
"schemaVersion": 27,
|
||||
|
|
|
|||
|
|
@ -3,10 +3,6 @@
|
|||
"title": "special ds",
|
||||
"tags": null,
|
||||
"datasource": [
|
||||
{
|
||||
"uid": "grafana",
|
||||
"type": "datasource"
|
||||
},
|
||||
{
|
||||
"uid": "dgd92lq7k",
|
||||
"type": "frser-sqlite-datasource"
|
||||
|
|
@ -22,10 +18,6 @@
|
|||
"title": "mixed ds with grafana ds",
|
||||
"type": "timeseries",
|
||||
"datasource": [
|
||||
{
|
||||
"uid": "grafana",
|
||||
"type": "datasource"
|
||||
},
|
||||
{
|
||||
"uid": "dgd92lq7k",
|
||||
"type": "frser-sqlite-datasource"
|
||||
|
|
@ -45,13 +37,7 @@
|
|||
{
|
||||
"id": 6,
|
||||
"title": "grafana ds",
|
||||
"type": "timeseries",
|
||||
"datasource": [
|
||||
{
|
||||
"uid": "grafana",
|
||||
"type": "datasource"
|
||||
}
|
||||
]
|
||||
"type": "timeseries"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue