feat: provides MT Dashboard service (#110447)
This commit is contained in:
+11
-1
@@ -4,13 +4,16 @@ go 1.24.6
|
||||
|
||||
require (
|
||||
cuelang.org/go v0.11.1
|
||||
github.com/grafana/authlib/types v0.0.0-20250710201142-9542f2f28d43
|
||||
github.com/grafana/grafana-app-sdk v0.40.3
|
||||
github.com/grafana/grafana-app-sdk/logging v0.40.3
|
||||
github.com/grafana/grafana-plugin-sdk-go v0.278.0
|
||||
github.com/grafana/grafana/pkg/apimachinery v0.0.0-20250514132646-acbc7b54ed9e
|
||||
github.com/prometheus/client_golang v1.23.0
|
||||
github.com/stretchr/testify v1.10.0
|
||||
golang.org/x/net v0.43.0
|
||||
k8s.io/apimachinery v0.33.3
|
||||
k8s.io/apiserver v0.33.3
|
||||
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff
|
||||
k8s.io/utils v0.0.0-20241210054802-24370beab758
|
||||
)
|
||||
@@ -19,6 +22,7 @@ require (
|
||||
github.com/BurntSushi/toml v1.5.0 // indirect
|
||||
github.com/apache/arrow-go/v18 v18.3.0 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/blang/semver/v4 v4.0.0 // indirect
|
||||
github.com/cenkalti/backoff/v5 v5.0.2 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/cheekybits/genny v1.0.0 // indirect
|
||||
@@ -32,6 +36,7 @@ require (
|
||||
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
|
||||
github.com/getkin/kin-openapi v0.132.0 // indirect
|
||||
github.com/go-jose/go-jose/v3 v3.0.4 // indirect
|
||||
github.com/go-logr/logr v1.4.3 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.21.0 // indirect
|
||||
@@ -47,6 +52,8 @@ 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-20250710201142-9542f2f28d43 // indirect
|
||||
github.com/grafana/dskit v0.0.0-20250611075409-46f51e1ce914 // indirect
|
||||
github.com/grafana/otel-profiling-go v0.5.1 // indirect
|
||||
github.com/grafana/pyroscope-go/godeltaprof v0.1.8 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0 // indirect
|
||||
@@ -78,6 +85,7 @@ require (
|
||||
github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect
|
||||
github.com/oklog/run v1.1.0 // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
|
||||
github.com/perimeterx/marshmallow v1.1.5 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.22 // indirect
|
||||
@@ -88,6 +96,7 @@ require (
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/smartystreets/goconvey v1.6.4 // indirect
|
||||
github.com/spf13/pflag v1.0.7 // indirect
|
||||
github.com/stretchr/objx v0.5.2 // indirect
|
||||
github.com/unknwon/bra v0.0.0-20200517080246-1e3013ecaff8 // indirect
|
||||
github.com/unknwon/com v1.0.1 // indirect
|
||||
@@ -110,9 +119,9 @@ require (
|
||||
go.opentelemetry.io/otel/trace v1.37.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.7.0 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.2 // indirect
|
||||
golang.org/x/crypto v0.41.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 // indirect
|
||||
golang.org/x/mod v0.27.0 // indirect
|
||||
golang.org/x/net v0.43.0 // indirect
|
||||
golang.org/x/oauth2 v0.30.0 // indirect
|
||||
golang.org/x/sync v0.16.0 // indirect
|
||||
golang.org/x/sys v0.35.0 // indirect
|
||||
@@ -129,6 +138,7 @@ require (
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/client-go v0.33.3 // indirect
|
||||
k8s.io/component-base v0.33.3 // indirect
|
||||
k8s.io/klog/v2 v2.130.1 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
|
||||
sigs.k8s.io/randfill v1.0.0 // indirect
|
||||
|
||||
@@ -14,6 +14,8 @@ github.com/apache/thrift v0.21.0 h1:tdPmh/ptjE1IJnhbhrcl2++TauVjy242rkV/UzJChnE=
|
||||
github.com/apache/thrift v0.21.0/go.mod h1:W1H8aR/QRtYNvrPeFXBtobyRkd0/YVhTc6i07XIAgDw=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
|
||||
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
|
||||
github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA=
|
||||
github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8=
|
||||
github.com/cenkalti/backoff/v5 v5.0.2 h1:rIfFVxEf1QsI7E1ZHfp/B4DF/6QBAUhmgkxc0H7Zss8=
|
||||
@@ -52,6 +54,8 @@ github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv
|
||||
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
|
||||
github.com/getkin/kin-openapi v0.132.0 h1:3ISeLMsQzcb5v26yeJrBcdTCEQTag36ZjaGk7MIRUwk=
|
||||
github.com/getkin/kin-openapi v0.132.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58=
|
||||
github.com/go-jose/go-jose/v3 v3.0.4 h1:Wp5HA7bLQcKnf6YYao/4kpRpVMp/yf6+pJKV8WFSaNY=
|
||||
github.com/go-jose/go-jose/v3 v3.0.4/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
@@ -94,6 +98,12 @@ github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e h1:JKmoR8x90Iww1
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
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-20250710201142-9542f2f28d43 h1:vVPT0i5Y1vI6qzecYStV2yk7cHKrC3Pc7AgvwT5KydQ=
|
||||
github.com/grafana/authlib v0.0.0-20250710201142-9542f2f28d43/go.mod h1:1fWkOiL+m32NBgRHZtlZGz2ji868tPZACYbqP3nBRJI=
|
||||
github.com/grafana/authlib/types v0.0.0-20250710201142-9542f2f28d43 h1:NlkGMnVi/oUn6Cr90QbJYpQJ4FnjyAIG9Ex5GtTZIzw=
|
||||
github.com/grafana/authlib/types v0.0.0-20250710201142-9542f2f28d43/go.mod h1:qeWYbnWzaYGl88JlL9+DsP1GT2Cudm58rLtx13fKZdw=
|
||||
github.com/grafana/dskit v0.0.0-20250611075409-46f51e1ce914 h1:qcSGhr691f1mmPHwg2svGyO40Ex92G02aOyHzP6XHCE=
|
||||
github.com/grafana/dskit v0.0.0-20250611075409-46f51e1ce914/go.mod h1:OiN4P4aC6LwLzLbEupH3Ue83VfQoNMfG48rsna8jI/E=
|
||||
github.com/grafana/grafana-app-sdk v0.40.3 h1:JFo7uAfbAJUfZ9neD7/4sODKm1xgu9zhckclH/N4DYU=
|
||||
github.com/grafana/grafana-app-sdk v0.40.3/go.mod h1:j0KzHo3Sa6kd+lnwSScBNoV9Vobkg/YY9HtEjxpyPrk=
|
||||
github.com/grafana/grafana-app-sdk/logging v0.40.3 h1:2VXsXXEQiqAavRP8wusRDB6rDqf5lufP7A6NfjELqPE=
|
||||
@@ -198,6 +208,8 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
|
||||
github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
|
||||
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
|
||||
github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s=
|
||||
@@ -242,6 +254,7 @@ github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpE
|
||||
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
@@ -265,6 +278,7 @@ github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
||||
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ=
|
||||
github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
|
||||
github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0=
|
||||
@@ -310,10 +324,16 @@ go.yaml.in/yaml/v3 v3.0.3/go.mod h1:tBHosrYAkRZjRAOREWbDnBXUf08JOwYq++0QNwQiWzI=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4=
|
||||
golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
|
||||
golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 h1:y5zboxd6LQAqYIhHnB48p0ByQ/GnQx2BE33L8BOHQkI=
|
||||
golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6/go.mod h1:U6Lno4MTRCDY+Ba7aCcauB9T60gsv5s4ralQzP72ZoQ=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.27.0 h1:kb+q2PyFnEADO2IEF935ehFUXlWiNjJWtRNgBLSfbxQ=
|
||||
golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
@@ -321,6 +341,10 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
|
||||
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
|
||||
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
|
||||
@@ -328,6 +352,8 @@ golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKl
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
|
||||
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -336,17 +362,33 @@ golang.org/x/sys v0.0.0-20191020152052-9984515f0562/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
|
||||
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4=
|
||||
golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
|
||||
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
|
||||
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
|
||||
@@ -356,6 +398,8 @@ golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg=
|
||||
golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -392,8 +436,12 @@ k8s.io/api v0.33.3 h1:SRd5t//hhkI1buzxb288fy2xvjubstenEKL9K51KBI8=
|
||||
k8s.io/api v0.33.3/go.mod h1:01Y/iLUjNBM3TAvypct7DIj0M0NIZc+PzAHCIo0CYGE=
|
||||
k8s.io/apimachinery v0.33.3 h1:4ZSrmNa0c/ZpZJhAgRdcsFcZOw1PQU1bALVQ0B3I5LA=
|
||||
k8s.io/apimachinery v0.33.3/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
|
||||
k8s.io/apiserver v0.33.3 h1:Wv0hGc+QFdMJB4ZSiHrCgN3zL3QRatu56+rpccKC3J4=
|
||||
k8s.io/apiserver v0.33.3/go.mod h1:05632ifFEe6TxwjdAIrwINHWE2hLwyADFk5mBsQa15E=
|
||||
k8s.io/client-go v0.33.3 h1:M5AfDnKfYmVJif92ngN532gFqakcGi6RvaOF16efrpA=
|
||||
k8s.io/client-go v0.33.3/go.mod h1:luqKBQggEf3shbxHY4uVENAxrDISLOarxpTKMiUuujg=
|
||||
k8s.io/component-base v0.33.3 h1:mlAuyJqyPlKZM7FyaoM/LcunZaaY353RXiOd2+B5tGA=
|
||||
k8s.io/component-base v0.33.3/go.mod h1:ktBVsBzkI3imDuxYXmVxZ2zxJnYTZ4HAsVj9iF09qp4=
|
||||
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
|
||||
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
||||
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4=
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
package conversion
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/authlib/types"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
"k8s.io/apimachinery/pkg/conversion"
|
||||
"k8s.io/utils/ptr"
|
||||
|
||||
@@ -10,6 +14,7 @@ import (
|
||||
dashv2beta1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2beta1"
|
||||
"github.com/grafana/grafana/apps/dashboard/pkg/migration"
|
||||
"github.com/grafana/grafana/apps/dashboard/pkg/migration/schemaversion"
|
||||
"k8s.io/apiserver/pkg/endpoints/request"
|
||||
)
|
||||
|
||||
func Convert_V0_to_V1(in *dashv0.Dashboard, out *dashv1.Dashboard, scope conversion.Scope) error {
|
||||
@@ -23,7 +28,23 @@ func Convert_V0_to_V1(in *dashv0.Dashboard, out *dashv1.Dashboard, scope convers
|
||||
},
|
||||
}
|
||||
|
||||
if err := migration.Migrate(out.Spec.Object, schemaversion.LATEST_VERSION); err != nil {
|
||||
// the scope passed into this function is used in k8s apimachinery for migrations, but we also need the context
|
||||
// to have what grafana expects in the request context, so that we can retrieve datasources for migrating
|
||||
// some of the old dashboard schemas (these migrations used to be run in the frontend)
|
||||
ctx := request.WithNamespace(context.Background(), in.GetNamespace())
|
||||
nsInfo, err := types.ParseNamespace(in.GetNamespace())
|
||||
if err != nil {
|
||||
out.Status.Conversion.Failed = true
|
||||
out.Status.Conversion.Error = ptr.To(err.Error())
|
||||
return nil
|
||||
}
|
||||
|
||||
// a background service identity is used here because the user who is reading the specific dashboard
|
||||
// may not have access to all the datasources in the dashboard, but the migration still needs to take place
|
||||
// in order to be able to convert between k8s versions (so that we have a guaranteed structure to convert between)
|
||||
ctx, _ = identity.WithServiceIdentity(ctx, nsInfo.OrgID)
|
||||
|
||||
if err := migration.Migrate(ctx, out.Spec.Object, schemaversion.LATEST_VERSION); err != nil {
|
||||
out.Status.Conversion.Failed = true
|
||||
out.Status.Conversion.Error = ptr.To(err.Error())
|
||||
return nil
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package migration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
@@ -14,8 +15,8 @@ func Initialize(dsInfoProvider schemaversion.DataSourceInfoProvider, panelProvid
|
||||
|
||||
// Migrate migrates the given dashboard to the target version.
|
||||
// This will block until the migrator is initialized.
|
||||
func Migrate(dash map[string]interface{}, targetVersion int) error {
|
||||
return migratorInstance.migrate(dash, targetVersion)
|
||||
func Migrate(ctx context.Context, dash map[string]interface{}, targetVersion int) error {
|
||||
return migratorInstance.migrate(ctx, dash, targetVersion)
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -38,7 +39,7 @@ func (m *migrator) init(dsInfoProvider schemaversion.DataSourceInfoProvider, pan
|
||||
})
|
||||
}
|
||||
|
||||
func (m *migrator) migrate(dash map[string]interface{}, targetVersion int) error {
|
||||
func (m *migrator) migrate(ctx context.Context, dash map[string]interface{}, targetVersion int) error {
|
||||
if dash == nil {
|
||||
return schemaversion.NewMigrationError("dashboard is nil", 0, targetVersion, "")
|
||||
}
|
||||
@@ -57,7 +58,7 @@ func (m *migrator) migrate(dash map[string]interface{}, targetVersion int) error
|
||||
|
||||
for nextVersion := inputVersion + 1; nextVersion <= targetVersion; nextVersion++ {
|
||||
if migration, ok := m.migrations[nextVersion]; ok {
|
||||
if err := migration(dash); err != nil {
|
||||
if err := migration(ctx, dash); err != nil {
|
||||
functionName := fmt.Sprintf("V%d", nextVersion)
|
||||
return schemaversion.NewMigrationError("migration failed: "+err.Error(), inputVersion, nextVersion, functionName)
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package migration_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
@@ -29,7 +30,7 @@ func TestMigrate(t *testing.T) {
|
||||
migration.Initialize(migrationtestutil.GetTestDataSourceProvider(), migrationtestutil.GetTestPanelProvider())
|
||||
|
||||
t.Run("minimum version check", func(t *testing.T) {
|
||||
err := migration.Migrate(map[string]interface{}{
|
||||
err := migration.Migrate(context.Background(), map[string]interface{}{
|
||||
"schemaVersion": schemaversion.MIN_VERSION - 1,
|
||||
}, schemaversion.MIN_VERSION)
|
||||
|
||||
@@ -52,7 +53,7 @@ func TestMigrate(t *testing.T) {
|
||||
|
||||
t.Run("input check "+f.Name(), func(t *testing.T) {
|
||||
// use input version as the target version to ensure there are no changes
|
||||
require.NoError(t, migration.Migrate(inputDash, inputVersion), "input check migration failed")
|
||||
require.NoError(t, migration.Migrate(context.Background(), inputDash, inputVersion), "input check migration failed")
|
||||
outBytes, err := json.MarshalIndent(inputDash, "", " ")
|
||||
require.NoError(t, err, "failed to marshal migrated dashboard")
|
||||
// We can ignore gosec G304 here since it's a test
|
||||
@@ -71,7 +72,7 @@ func TestMigrate(t *testing.T) {
|
||||
|
||||
func testMigration(t *testing.T, dash map[string]interface{}, inputFileName string, targetVersion int) {
|
||||
t.Helper()
|
||||
require.NoError(t, migration.Migrate(dash, targetVersion), "%d migration failed", targetVersion)
|
||||
require.NoError(t, migration.Migrate(context.Background(), dash, targetVersion), "%d migration failed", targetVersion)
|
||||
|
||||
outPath := filepath.Join(OUTPUT_DIR, inputFileName)
|
||||
outBytes, err := json.MarshalIndent(dash, "", " ")
|
||||
@@ -191,7 +192,7 @@ func TestSchemaMigrationMetrics(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Execute migration
|
||||
err := migration.Migrate(tt.dashboard, tt.targetVersion)
|
||||
err := migration.Migrate(context.Background(), tt.dashboard, tt.targetVersion)
|
||||
|
||||
// Check error expectation
|
||||
if tt.expectSuccess {
|
||||
@@ -261,7 +262,7 @@ func TestSchemaMigrationLogging(t *testing.T) {
|
||||
// and check that the migration behaves correctly (logs are called internally)
|
||||
|
||||
// Execute migration
|
||||
err := migration.Migrate(tt.dashboard, tt.targetVersion)
|
||||
err := migration.Migrate(context.Background(), tt.dashboard, tt.targetVersion)
|
||||
|
||||
// Check error expectation
|
||||
if tt.expectSuccess {
|
||||
@@ -295,7 +296,7 @@ func TestLogMessageStructure(t *testing.T) {
|
||||
}
|
||||
|
||||
// Successful migration - should trigger debug log
|
||||
err := migration.Migrate(dashboard, schemaversion.LATEST_VERSION)
|
||||
err := migration.Migrate(context.Background(), dashboard, schemaversion.LATEST_VERSION)
|
||||
require.NoError(t, err, "migration should succeed")
|
||||
|
||||
// Failed migration - should trigger error log
|
||||
@@ -303,7 +304,7 @@ func TestLogMessageStructure(t *testing.T) {
|
||||
"schemaVersion": schemaversion.MIN_VERSION - 1,
|
||||
"title": "old dashboard",
|
||||
}
|
||||
err = migration.Migrate(oldDashboard, schemaversion.LATEST_VERSION)
|
||||
err = migration.Migrate(context.Background(), oldDashboard, schemaversion.LATEST_VERSION)
|
||||
require.Error(t, err, "migration should fail")
|
||||
|
||||
// Both cases above execute the logging code in reportMigrationMetrics
|
||||
|
||||
@@ -2,6 +2,8 @@ package schemaversion
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -9,7 +11,7 @@ const (
|
||||
LATEST_VERSION = 41
|
||||
)
|
||||
|
||||
type SchemaVersionMigrationFunc func(map[string]interface{}) error
|
||||
type SchemaVersionMigrationFunc func(context.Context, map[string]interface{}) error
|
||||
|
||||
type DataSourceInfo struct {
|
||||
Default bool
|
||||
@@ -21,7 +23,9 @@ type DataSourceInfo struct {
|
||||
}
|
||||
|
||||
type DataSourceInfoProvider interface {
|
||||
GetDataSourceInfo() []DataSourceInfo
|
||||
// GetDataSourceInfo returns a list of all data sources with their info
|
||||
// The context must have the namespace in it
|
||||
GetDataSourceInfo(ctx context.Context) []DataSourceInfo
|
||||
}
|
||||
|
||||
type PanelPluginInfo struct {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package schemaversion_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/apps/dashboard/pkg/migration/schemaversion"
|
||||
@@ -68,7 +69,7 @@ func runMigrationTests(t *testing.T, testCases []migrationTestCase, migrationFun
|
||||
|
||||
for _, tt := range testCases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := migrationFunc(tt.input)
|
||||
err := migrationFunc(context.Background(), tt.input)
|
||||
if tt.expectedError != "" {
|
||||
require.Error(t, err)
|
||||
require.Equal(t, tt.expectedError, err.Error())
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package schemaversion
|
||||
|
||||
import "context"
|
||||
|
||||
// V14 migrates the sharedCrosshair boolean property to graphTooltip integer property.
|
||||
// This migration converts the old boolean shared crosshair setting to the new integer-based
|
||||
// graph tooltip setting for consistency with updated dashboard tooltip behavior.
|
||||
@@ -20,7 +22,7 @@ package schemaversion
|
||||
// "panels": [...]
|
||||
// }
|
||||
|
||||
func V14(dashboard map[string]interface{}) error {
|
||||
func V14(_ context.Context, dashboard map[string]interface{}) error {
|
||||
// Convert sharedCrosshair boolean to graphTooltip integer
|
||||
sharedCrosshair := GetBoolValue(dashboard, "sharedCrosshair")
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package schemaversion
|
||||
|
||||
import "context"
|
||||
|
||||
// V15 migration is a no-op migration
|
||||
// It only updates the schema version to 15
|
||||
// It's created to keep the migration history consistent with frontend migrator
|
||||
@@ -19,7 +21,7 @@ package schemaversion
|
||||
// "panels": [...]
|
||||
// }
|
||||
|
||||
func V15(dashboard map[string]interface{}) error {
|
||||
func V15(_ context.Context, dashboard map[string]interface{}) error {
|
||||
dashboard["schemaVersion"] = 15
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package schemaversion
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math"
|
||||
)
|
||||
|
||||
@@ -16,7 +17,7 @@ const (
|
||||
|
||||
// V16 migrates dashboard layout from the old row-based system to the modern grid-based layout.
|
||||
// This migration follows the exact logic from DashboardMigrator.ts to ensure consistency between frontend and backend.
|
||||
func V16(dashboard map[string]interface{}) error {
|
||||
func V16(_ context.Context, dashboard map[string]interface{}) error {
|
||||
dashboard["schemaVersion"] = 16
|
||||
|
||||
upgradeToGridLayout(dashboard)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package schemaversion
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math"
|
||||
"sort"
|
||||
)
|
||||
@@ -36,7 +37,7 @@ import (
|
||||
// ]
|
||||
//
|
||||
// The minSpan property is removed after conversion.
|
||||
func V17(dashboard map[string]interface{}) error {
|
||||
func V17(_ context.Context, dashboard map[string]interface{}) error {
|
||||
dashboard["schemaVersion"] = 17
|
||||
|
||||
panels, ok := dashboard["panels"].([]interface{})
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package schemaversion
|
||||
|
||||
import "context"
|
||||
|
||||
// V18 migrates gauge panel options from the legacy `options-gauge` format to the new `options` format.
|
||||
// This migration restructures gauge panel configuration to use the modern options structure with valueOptions.
|
||||
//
|
||||
@@ -42,7 +44,7 @@ package schemaversion
|
||||
// }
|
||||
// }
|
||||
// ]
|
||||
func V18(dashboard map[string]interface{}) error {
|
||||
func V18(_ context.Context, dashboard map[string]interface{}) error {
|
||||
dashboard["schemaVersion"] = 18
|
||||
|
||||
panels, ok := dashboard["panels"].([]interface{})
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package schemaversion
|
||||
|
||||
import (
|
||||
"context"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
@@ -36,7 +37,7 @@ import (
|
||||
// ]
|
||||
// }
|
||||
// ]
|
||||
func V19(dashboard map[string]interface{}) error {
|
||||
func V19(_ context.Context, dashboard map[string]interface{}) error {
|
||||
dashboard["schemaVersion"] = 19
|
||||
|
||||
panels, ok := dashboard["panels"].([]interface{})
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package schemaversion
|
||||
|
||||
import (
|
||||
"context"
|
||||
"regexp"
|
||||
|
||||
"github.com/grafana/grafana/apps/dashboard/pkg/migration/utils"
|
||||
@@ -64,7 +65,7 @@ import (
|
||||
// }
|
||||
// }
|
||||
// ]
|
||||
func V20(dashboard map[string]interface{}) error {
|
||||
func V20(_ context.Context, dashboard map[string]interface{}) error {
|
||||
dashboard["schemaVersion"] = 20
|
||||
|
||||
panels, ok := dashboard["panels"].([]interface{})
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package schemaversion
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/grafana/grafana/apps/dashboard/pkg/migration/utils"
|
||||
@@ -55,7 +56,7 @@ import (
|
||||
// }
|
||||
// }
|
||||
// ]
|
||||
func V21(dashboard map[string]interface{}) error {
|
||||
func V21(_ context.Context, dashboard map[string]interface{}) error {
|
||||
dashboard["schemaVersion"] = 21
|
||||
|
||||
panels, ok := dashboard["panels"].([]interface{})
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package schemaversion
|
||||
|
||||
import "context"
|
||||
|
||||
// V22 migrates table panel styles to set align property to 'auto'.
|
||||
// This migration ensures that all table panel styles have their align property
|
||||
// set to 'auto' for consistent alignment behavior.
|
||||
@@ -27,7 +29,7 @@ package schemaversion
|
||||
// ]
|
||||
// }
|
||||
// ]
|
||||
func V22(dashboard map[string]interface{}) error {
|
||||
func V22(_ context.Context, dashboard map[string]interface{}) error {
|
||||
dashboard["schemaVersion"] = 22
|
||||
|
||||
panels, ok := dashboard["panels"].([]interface{})
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
package schemaversion
|
||||
|
||||
import "github.com/grafana/grafana/apps/dashboard/pkg/migration/utils"
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/grafana/apps/dashboard/pkg/migration/utils"
|
||||
)
|
||||
|
||||
// V23 migrates multi variables to ensure their current property is aligned with their multi property.
|
||||
// This migration ensures that variables with multi=true have current.value and current.text as arrays,
|
||||
@@ -23,7 +27,7 @@ import "github.com/grafana/grafana/apps/dashboard/pkg/migration/utils"
|
||||
// { "type": "query", "multi": false, "current": { "value": "B", "text": "B" } }
|
||||
// ]
|
||||
// }
|
||||
func V23(dashboard map[string]interface{}) error {
|
||||
func V23(_ context.Context, dashboard map[string]interface{}) error {
|
||||
dashboard["schemaVersion"] = 23
|
||||
|
||||
templating, ok := dashboard["templating"].(map[string]interface{})
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package schemaversion
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
@@ -199,7 +200,7 @@ func V24(panelProvider PanelPluginInfoProvider) SchemaVersionMigrationFunc {
|
||||
return migrator.migrate
|
||||
}
|
||||
|
||||
func (m *v24Migrator) migrate(dashboard map[string]interface{}) error {
|
||||
func (m *v24Migrator) migrate(_ context.Context, dashboard map[string]interface{}) error {
|
||||
dashboard["schemaVersion"] = 24
|
||||
|
||||
panels, ok := dashboard["panels"].([]interface{})
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package schemaversion
|
||||
|
||||
import "context"
|
||||
|
||||
// V25 migration is a no-op migration
|
||||
// It only updates the schema version to 25
|
||||
// It's created to keep the migration history consistent with frontend migrator
|
||||
@@ -43,7 +45,7 @@ package schemaversion
|
||||
// }
|
||||
// }
|
||||
|
||||
func V25(dashboard map[string]interface{}) error {
|
||||
func V25(_ context.Context, dashboard map[string]interface{}) error {
|
||||
dashboard["schemaVersion"] = int(25)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package schemaversion
|
||||
|
||||
import "context"
|
||||
|
||||
// V26 migration performs two main tasks:
|
||||
// 1. Converts all text2 panels to text panels by changing the type field
|
||||
// 2. Removes the angular field from panel options if it exists
|
||||
@@ -80,7 +82,7 @@ package schemaversion
|
||||
// "title": "Graph Panel"
|
||||
// }
|
||||
// ]
|
||||
func V26(dashboard map[string]interface{}) error {
|
||||
func V26(_ context.Context, dashboard map[string]interface{}) error {
|
||||
dashboard["schemaVersion"] = 26
|
||||
|
||||
panels, ok := dashboard["panels"].([]interface{})
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package schemaversion
|
||||
|
||||
import "context"
|
||||
|
||||
// V27 migrates repeated panels and constant variables.
|
||||
//
|
||||
// The migration performs two main tasks:
|
||||
@@ -73,7 +75,7 @@ package schemaversion
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
func V27(dashboard map[string]interface{}) error {
|
||||
func V27(_ context.Context, dashboard map[string]interface{}) error {
|
||||
dashboard["schemaVersion"] = 27
|
||||
|
||||
// Remove repeated panels
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package schemaversion
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -66,12 +67,12 @@ func V28(panelProvider PanelPluginInfoProvider) SchemaVersionMigrationFunc {
|
||||
statPanelVersion: statPanelVersion,
|
||||
}
|
||||
|
||||
return func(dashboard map[string]interface{}) error {
|
||||
return migrator.migrate(dashboard)
|
||||
return func(ctx context.Context, dashboard map[string]interface{}) error {
|
||||
return migrator.migrate(context.Background(), dashboard)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *v28Migrator) migrate(dashboard map[string]interface{}) error {
|
||||
func (m *v28Migrator) migrate(_ context.Context, dashboard map[string]interface{}) error {
|
||||
dashboard["schemaVersion"] = 28
|
||||
|
||||
// Migrate singlestat panels
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package schemaversion
|
||||
|
||||
import "context"
|
||||
|
||||
// V29 migrates query variables to ensure their refresh property is set to 1 (on dashboard load)
|
||||
// if it is not 1 or 2, and clears their options array if present.
|
||||
//
|
||||
@@ -22,7 +24,7 @@ package schemaversion
|
||||
// { "type": "query", "refresh": 1, "options": [] }
|
||||
// ]
|
||||
// }
|
||||
func V29(dashboard map[string]interface{}) error {
|
||||
func V29(_ context.Context, dashboard map[string]interface{}) error {
|
||||
dashboard["schemaVersion"] = 29
|
||||
|
||||
templating, ok := dashboard["templating"].(map[string]interface{})
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package schemaversion
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
@@ -89,7 +90,7 @@ import (
|
||||
// "tooltip": { "mode": "multi" }
|
||||
// }
|
||||
// }
|
||||
func V30(dashboard map[string]interface{}) error {
|
||||
func V30(_ context.Context, dashboard map[string]interface{}) error {
|
||||
dashboard["schemaVersion"] = 30
|
||||
|
||||
panels, ok := dashboard["panels"].([]interface{})
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package schemaversion
|
||||
|
||||
import "context"
|
||||
|
||||
// V31 adds a merge transformer after any labelsToFields transformer in panel transformations.
|
||||
//
|
||||
// This migration addresses data processing workflow optimization by automatically inserting
|
||||
@@ -48,7 +50,7 @@ package schemaversion
|
||||
// { "id": "merge", "options": {} }
|
||||
// ]
|
||||
// }
|
||||
func V31(dashboard map[string]interface{}) error {
|
||||
func V31(_ context.Context, dashboard map[string]interface{}) error {
|
||||
dashboard["schemaVersion"] = int(31)
|
||||
|
||||
panels, ok := dashboard["panels"].([]interface{})
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package schemaversion
|
||||
|
||||
import "context"
|
||||
|
||||
// V32 is a no-op migration that serves as a placeholder for consistency.
|
||||
//
|
||||
// The migration performs no modifications to the dashboard structure and simply
|
||||
@@ -21,7 +23,7 @@ package schemaversion
|
||||
// "schemaVersion": 32,
|
||||
// "panels": [...] // unchanged
|
||||
// }
|
||||
func V32(dashboard map[string]interface{}) error {
|
||||
func V32(_ context.Context, dashboard map[string]interface{}) error {
|
||||
dashboard["schemaVersion"] = int(32)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
package schemaversion
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
// V33 migrates panel datasource references from string names to UIDs.
|
||||
//
|
||||
// This migration addresses datasource references in dashboard panels and their targets
|
||||
@@ -57,8 +61,8 @@ package schemaversion
|
||||
// ]
|
||||
// }
|
||||
func V33(dsInfo DataSourceInfoProvider) SchemaVersionMigrationFunc {
|
||||
datasources := dsInfo.GetDataSourceInfo()
|
||||
return func(dashboard map[string]interface{}) error {
|
||||
return func(ctx context.Context, dashboard map[string]interface{}) error {
|
||||
datasources := dsInfo.GetDataSourceInfo(ctx)
|
||||
if dashboard == nil {
|
||||
dashboard = map[string]interface{}{}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package schemaversion
|
||||
|
||||
import "context"
|
||||
|
||||
// V34 migrates CloudWatch queries that use multiple statistics into separate queries.
|
||||
//
|
||||
// This migration addresses CloudWatch queries where a single query uses multiple statistics
|
||||
@@ -53,7 +55,7 @@ package schemaversion
|
||||
// { name: "CloudWatch Alerts - Maximum", dimensions: {"InstanceId": "i-123"}, namespace: "AWS/EC2", region: "us-east-1", prefixMatching: false, statistic: "Maximum" },
|
||||
// { name: "CloudWatch Alerts - Minimum", dimensions: {"InstanceId": "i-123"}, namespace: "AWS/EC2", region: "us-east-1", prefixMatching: false, statistic: "Minimum" }
|
||||
// ]
|
||||
func V34(dashboard map[string]interface{}) error {
|
||||
func V34(_ context.Context, dashboard map[string]interface{}) error {
|
||||
dashboard["schemaVersion"] = int(34)
|
||||
|
||||
// Migrate panel queries if panels exist
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package schemaversion
|
||||
|
||||
import "context"
|
||||
|
||||
// V35 ensures x-axis visibility in timeseries panels to prevent dashboard breakage.
|
||||
//
|
||||
// This migration addresses a specific issue where timeseries panels with all axes
|
||||
@@ -33,7 +35,7 @@ package schemaversion
|
||||
// properties: [{ id: "custom.axisPlacement", value: "auto" }]
|
||||
// }]
|
||||
// }
|
||||
func V35(dashboard map[string]interface{}) error {
|
||||
func V35(_ context.Context, dashboard map[string]interface{}) error {
|
||||
dashboard["schemaVersion"] = int(35)
|
||||
|
||||
panels, ok := dashboard["panels"].([]interface{})
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package schemaversion
|
||||
|
||||
import "context"
|
||||
|
||||
// V36 migrates dashboard datasource references from legacy string format to structured UID-based objects.
|
||||
//
|
||||
// This migration addresses a critical evolution in Grafana's datasource architecture where datasource
|
||||
@@ -73,8 +75,8 @@ package schemaversion
|
||||
// }]
|
||||
// }
|
||||
func V36(dsInfo DataSourceInfoProvider) SchemaVersionMigrationFunc {
|
||||
datasources := dsInfo.GetDataSourceInfo()
|
||||
return func(dashboard map[string]interface{}) error {
|
||||
return func(ctx context.Context, dashboard map[string]interface{}) error {
|
||||
datasources := dsInfo.GetDataSourceInfo(ctx)
|
||||
dashboard["schemaVersion"] = int(36)
|
||||
|
||||
migrateAnnotations(dashboard, datasources)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package schemaversion
|
||||
|
||||
import "context"
|
||||
|
||||
// V37 normalizes legend configuration to use `showLegend` property consistently.
|
||||
//
|
||||
// This migration addresses inconsistencies in how legend visibility was handled.
|
||||
@@ -71,7 +73,7 @@ package schemaversion
|
||||
// showLegend: true
|
||||
// }
|
||||
// }
|
||||
func V37(dashboard map[string]interface{}) error {
|
||||
func V37(_ context.Context, dashboard map[string]interface{}) error {
|
||||
dashboard["schemaVersion"] = int(37)
|
||||
|
||||
panels, ok := dashboard["panels"].([]interface{})
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package schemaversion
|
||||
|
||||
import "context"
|
||||
|
||||
// V38 migrates table panel configuration from displayMode to the structured cellOptions format.
|
||||
//
|
||||
// This migration addresses limitations in the original table panel cell display configuration where
|
||||
@@ -70,7 +72,7 @@ package schemaversion
|
||||
// }
|
||||
// }]
|
||||
// }]
|
||||
func V38(dashboard map[string]interface{}) error {
|
||||
func V38(_ context.Context, dashboard map[string]interface{}) error {
|
||||
dashboard["schemaVersion"] = int(38)
|
||||
|
||||
panels, ok := dashboard["panels"].([]interface{})
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package schemaversion
|
||||
|
||||
import "context"
|
||||
|
||||
// V39 migrates timeSeriesTable transformation configuration to support extensible per-query options.
|
||||
//
|
||||
// This migration addresses limitations in the original timeSeriesTable transformation design where
|
||||
@@ -45,7 +47,7 @@ package schemaversion
|
||||
// "C": { stat: "last" }
|
||||
// }
|
||||
// }]
|
||||
func V39(dashboard map[string]interface{}) error {
|
||||
func V39(_ context.Context, dashboard map[string]interface{}) error {
|
||||
dashboard["schemaVersion"] = int(39)
|
||||
|
||||
panels, ok := dashboard["panels"].([]interface{})
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package schemaversion
|
||||
|
||||
import "context"
|
||||
|
||||
// V40 normalizes the dashboard refresh property to ensure consistent string typing.
|
||||
//
|
||||
// This migration addresses type inconsistencies in dashboard refresh configuration that could
|
||||
@@ -33,7 +35,7 @@ package schemaversion
|
||||
// refresh: "" // normalized to empty string
|
||||
// refresh: "" // normalized to empty string
|
||||
// refresh: "" // property added with empty string
|
||||
func V40(dash map[string]interface{}) error {
|
||||
func V40(_ context.Context, dash map[string]interface{}) error {
|
||||
dash["schemaVersion"] = int(40)
|
||||
if _, ok := dash["refresh"].(string); !ok {
|
||||
dash["refresh"] = ""
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package schemaversion
|
||||
|
||||
import "context"
|
||||
|
||||
// V41 removes the deprecated time_options property from dashboard timepicker configuration.
|
||||
//
|
||||
// This migration addresses technical debt by cleaning up legacy timepicker settings that have
|
||||
@@ -30,7 +32,7 @@ package schemaversion
|
||||
// timepicker: {
|
||||
// refresh_intervals: ["5s", "10s", "30s", "1m"]
|
||||
// }
|
||||
func V41(dash map[string]interface{}) error {
|
||||
func V41(_ context.Context, dash map[string]interface{}) error {
|
||||
dash["schemaVersion"] = int(41)
|
||||
if timepicker, ok := dash["timepicker"].(map[string]interface{}); ok {
|
||||
// time_options is a legacy property that was not used since grafana version 5
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package testutil
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/grafana/apps/dashboard/pkg/migration/schemaversion"
|
||||
)
|
||||
|
||||
@@ -10,7 +12,7 @@ type TestPanelProvider struct {
|
||||
customPanels []schemaversion.PanelPluginInfo
|
||||
}
|
||||
|
||||
func (m *TestDataSourceProvider) GetDataSourceInfo() []schemaversion.DataSourceInfo {
|
||||
func (m *TestDataSourceProvider) GetDataSourceInfo(_ context.Context) []schemaversion.DataSourceInfo {
|
||||
return []schemaversion.DataSourceInfo{
|
||||
{
|
||||
Default: true,
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/libraryelements"
|
||||
)
|
||||
|
||||
func GetAuthorizer(ac accesscontrol.AccessControl, l log.Logger) authorizer.Authorizer {
|
||||
func newLegacyAuthorizer(ac accesscontrol.AccessControl, l log.Logger) authorizer.Authorizer {
|
||||
return authorizer.AuthorizerFunc(
|
||||
func(ctx context.Context, attr authorizer.Attributes) (authorized authorizer.Decision, reason string, err error) {
|
||||
// Note that we will return Allow more than expected.
|
||||
|
||||
@@ -11,7 +11,7 @@ type datasourceInfoProvider struct {
|
||||
datasourceService datasources.DataSourceService
|
||||
}
|
||||
|
||||
func (d *datasourceInfoProvider) GetDataSourceInfo() []schemaversion.DataSourceInfo {
|
||||
func (d *datasourceInfoProvider) GetDataSourceInfo(_ context.Context) []schemaversion.DataSourceInfo {
|
||||
query := datasources.GetAllDataSourcesQuery{}
|
||||
dataSources, err := d.datasourceService.GetAllDataSources(context.Background(), &query)
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ func (b *DashboardsAPIBuilder) Mutate(ctx context.Context, a admission.Attribute
|
||||
internalID = int64(id)
|
||||
}
|
||||
resourceInfo = dashboardV1.DashboardResourceInfo
|
||||
migrationErr = migration.Migrate(v.Spec.Object, schemaversion.LATEST_VERSION)
|
||||
migrationErr = migration.Migrate(ctx, v.Spec.Object, schemaversion.LATEST_VERSION)
|
||||
if migrationErr != nil {
|
||||
v.Status.Conversion = &dashboardV1.DashboardConversionStatus{
|
||||
Failed: true,
|
||||
|
||||
@@ -14,10 +14,10 @@ type PluginStorePanelProvider struct {
|
||||
}
|
||||
|
||||
func (p *PluginStorePanelProvider) GetPanels() []schemaversion.PanelPluginInfo {
|
||||
plugins := p.pluginStore.Plugins(context.Background(), plugins.TypePanel)
|
||||
panelPlugins := p.pluginStore.Plugins(context.Background(), plugins.TypePanel)
|
||||
|
||||
panels := make([]schemaversion.PanelPluginInfo, len(plugins))
|
||||
for i, plugin := range plugins {
|
||||
panels := make([]schemaversion.PanelPluginInfo, len(panelPlugins))
|
||||
for i, plugin := range panelPlugins {
|
||||
version := plugin.Info.Version
|
||||
if version == "" {
|
||||
version = p.buildVersion
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
"maps"
|
||||
|
||||
"github.com/grafana/grafana/apps/dashboard/pkg/migration/schemaversion"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -20,7 +21,6 @@ import (
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
|
||||
claims "github.com/grafana/authlib/types"
|
||||
|
||||
internal "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard"
|
||||
dashv0 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v0alpha1"
|
||||
dashv1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v1beta1"
|
||||
@@ -37,9 +37,11 @@ import (
|
||||
"github.com/grafana/grafana/pkg/registry/apis/dashboard/legacy"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/dashboard/legacysearcher"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
authsvc "github.com/grafana/grafana/pkg/services/apiserver/auth/authorizer"
|
||||
"github.com/grafana/grafana/pkg/services/apiserver/builder"
|
||||
"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request"
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
dashsvc "github.com/grafana/grafana/pkg/services/dashboards/service"
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
@@ -77,6 +79,7 @@ type DashboardsAPIBuilder struct {
|
||||
dashboardService dashboards.DashboardService
|
||||
features featuremgmt.FeatureToggles
|
||||
|
||||
authorizer authorizer.Authorizer
|
||||
accessControl accesscontrol.AccessControl
|
||||
accessClient claims.AccessClient
|
||||
legacy *DashboardStorage
|
||||
@@ -92,10 +95,14 @@ type DashboardsAPIBuilder struct {
|
||||
ProvisioningService provisioning.ProvisioningService
|
||||
cfg *setting.Cfg
|
||||
dualWriter dualwrite.Service
|
||||
folderClient client.K8sHandler
|
||||
|
||||
log log.Logger
|
||||
reg prometheus.Registerer
|
||||
// only one of the two is required to be set, folderClientProvider is used when isStandalone is true
|
||||
folderClient client.K8sHandler
|
||||
folderClientProvider client.K8sHandlerProvider
|
||||
|
||||
log log.Logger
|
||||
reg prometheus.Registerer
|
||||
isStandalone bool // skips any handling including anything to do with legacy storage
|
||||
}
|
||||
|
||||
func RegisterAPIService(
|
||||
@@ -128,9 +135,11 @@ func RegisterAPIService(
|
||||
namespacer := request.GetNamespaceMapper(cfg)
|
||||
legacyDashboardSearcher := legacysearcher.NewDashboardSearchClient(dashStore, sorter)
|
||||
folderClient := client.NewK8sHandler(dual, request.GetNamespaceMapper(cfg), folders.FolderResourceInfo.GroupVersionResource(), restConfigProvider.GetRestConfig, dashStore, userService, unified, sorter, features)
|
||||
builder := &DashboardsAPIBuilder{
|
||||
log: log.New("grafana-apiserver.dashboards"),
|
||||
|
||||
dashLog := log.New("grafana-apiserver.dashboards")
|
||||
builder := &DashboardsAPIBuilder{
|
||||
log: dashLog,
|
||||
authorizer: newLegacyAuthorizer(accessControl, dashLog),
|
||||
dashboardService: dashboardService,
|
||||
dashboardPermissions: dashboardPermissions,
|
||||
dashboardPermissionsSvc: dashboardPermissionsSvc,
|
||||
@@ -166,6 +175,37 @@ func RegisterAPIService(
|
||||
return builder
|
||||
}
|
||||
|
||||
func NewAPIService(ac claims.AccessClient, features featuremgmt.FeatureToggles, folderClientProvider client.K8sHandlerProvider, datasourceProvider schemaversion.DataSourceInfoProvider, pluginStore *pluginstore.Service) *DashboardsAPIBuilder {
|
||||
// TODO: Plugin store will soon be removed,
|
||||
// as the cases for plugin fetching is not needed. Keeping it now to not break implementation
|
||||
if pluginStore == nil {
|
||||
panic("pluginStore is nil")
|
||||
}
|
||||
|
||||
logger := log.New("grafana-apiserver.dashboards")
|
||||
|
||||
migration.Initialize(datasourceProvider, &PluginStorePanelProvider{
|
||||
pluginStore: pluginStore,
|
||||
buildVersion: "unknown",
|
||||
})
|
||||
|
||||
return &DashboardsAPIBuilder{
|
||||
log: logger,
|
||||
reg: prometheus.NewRegistry(),
|
||||
|
||||
cfg: &setting.Cfg{
|
||||
MinRefreshInterval: "10s",
|
||||
},
|
||||
accessClient: ac,
|
||||
authorizer: authsvc.NewResourceAuthorizer(ac),
|
||||
features: features,
|
||||
dashboardService: &dashsvc.DashboardServiceImpl{}, // for validation helpers only
|
||||
folderClientProvider: folderClientProvider,
|
||||
|
||||
isStandalone: true,
|
||||
}
|
||||
}
|
||||
|
||||
func (b *DashboardsAPIBuilder) GetGroupVersions() []schema.GroupVersion {
|
||||
if featuremgmt.AnyEnabled(b.features, featuremgmt.FlagDashboardNewLayouts) {
|
||||
// If dashboards v2 is enabled, we want to use v2beta1 as the default API version.
|
||||
@@ -304,12 +344,12 @@ func (b *DashboardsAPIBuilder) validateCreate(ctx context.Context, a admission.A
|
||||
// Validate folder existence if specified
|
||||
if !a.IsDryRun() && accessor.GetFolder() != "" {
|
||||
if err := b.validateFolderExists(ctx, accessor.GetFolder(), id.GetOrgID()); err != nil {
|
||||
return apierrors.NewNotFound(folders.FolderResourceInfo.GroupResource(), accessor.GetFolder())
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Validate quota
|
||||
if !a.IsDryRun() {
|
||||
if !b.isStandalone && !a.IsDryRun() {
|
||||
params := "a.ScopeParameters{}
|
||||
params.OrgID = id.GetOrgID()
|
||||
internalId, err := id.GetInternalID()
|
||||
@@ -388,9 +428,24 @@ func (b *DashboardsAPIBuilder) validateUpdate(ctx context.Context, a admission.A
|
||||
// validateFolderExists checks if a folder exists
|
||||
func (b *DashboardsAPIBuilder) validateFolderExists(ctx context.Context, folderUID string, orgID int64) error {
|
||||
// Check if folder exists using the folder store
|
||||
_, err := b.folderClient.Get(ctx, folderUID, orgID, metav1.GetOptions{})
|
||||
|
||||
var folderClient client.K8sHandler
|
||||
if b.isStandalone {
|
||||
ns, err := request.NamespaceInfoFrom(ctx, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
folderClient = b.folderClientProvider.GetOrCreateHandler(ns.Value)
|
||||
} else {
|
||||
folderClient = b.folderClient
|
||||
}
|
||||
_, err := folderClient.Get(ctx, folderUID, orgID, metav1.GetOptions{})
|
||||
// Check if the error is a context deadline exceeded error
|
||||
if err != nil {
|
||||
// historically, we returned a more verbose error with folder name when its not found, below just keeps that behavior
|
||||
if apierrors.IsNotFound(err) {
|
||||
return apierrors.NewNotFound(folders.FolderResourceInfo.GroupResource(), folderUID)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -426,9 +481,13 @@ func (b *DashboardsAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver
|
||||
storageOpts := apistore.StorageOptions{
|
||||
EnableFolderSupport: true,
|
||||
RequireDeprecatedInternalID: true,
|
||||
}
|
||||
|
||||
if b.isStandalone {
|
||||
// TODO: Sets default root permissions
|
||||
} else {
|
||||
// Sets default root permissions
|
||||
Permissions: b.dashboardPermissions.SetDefaultPermissionsAfterCreate,
|
||||
storageOpts.Permissions = b.dashboardPermissions.SetDefaultPermissionsAfterCreate
|
||||
}
|
||||
|
||||
// Split dashboards when they are large
|
||||
@@ -525,6 +584,16 @@ func (b *DashboardsAPIBuilder) storageForVersion(
|
||||
storage := map[string]rest.Storage{}
|
||||
apiGroupInfo.VersionedResourcesStorageMap[dashboards.GroupVersion().Version] = storage
|
||||
|
||||
if b.isStandalone {
|
||||
store, err := grafanaregistry.NewRegistryStore(opts.Scheme, dashboards, opts.OptsGetter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
storage[dashboards.StoragePath()] = store
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
legacyStore, err := b.legacy.NewStore(dashboards, opts.Scheme, opts.OptsGetter, b.reg, b.dashboardPermissions, b.accessClient)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -607,7 +676,7 @@ func (b *DashboardsAPIBuilder) GetAPIRoutes(gv schema.GroupVersion) *builder.API
|
||||
}
|
||||
|
||||
func (b *DashboardsAPIBuilder) GetAuthorizer() authorizer.Authorizer {
|
||||
return GetAuthorizer(b.accessControl, b.log)
|
||||
return b.authorizer
|
||||
}
|
||||
|
||||
func (b *DashboardsAPIBuilder) verifyFolderAccessPermissions(ctx context.Context, user identity.Requester, folderIds ...string) error {
|
||||
|
||||
@@ -70,7 +70,7 @@ func authorizerFunc(ctx context.Context, attr authorizer.Attributes) (*authorize
|
||||
return &authorizerParams{evaluator: eval, user: user}, nil
|
||||
}
|
||||
|
||||
// newMultiTenantAuthorizer creates an authorizer sutiable to multi-tenant setup.
|
||||
// newMultiTenantAuthorizer creates an authorizer suitable to multi-tenant setup.
|
||||
// For now it only allow authorization of access tokens.
|
||||
func newMultiTenantAuthorizer(ac types.AccessClient) authorizer.Authorizer {
|
||||
return authorizer.AuthorizerFunc(func(ctx context.Context, a authorizer.Attributes) (authorizer.Decision, string, error) {
|
||||
|
||||
@@ -23,6 +23,12 @@ import (
|
||||
"github.com/grafana/grafana/pkg/storage/unified/resourcepb"
|
||||
)
|
||||
|
||||
// K8sHandlerProvider is a provider for K8sHandler instances.
|
||||
// It is used to get a K8sHandler instance for a given namespace.
|
||||
type K8sHandlerProvider interface {
|
||||
GetOrCreateHandler(namespace string) K8sHandler
|
||||
}
|
||||
|
||||
type K8sHandler interface {
|
||||
GetNamespace(orgID int64) string
|
||||
Get(ctx context.Context, name string, orgID int64, options v1.GetOptions, subresource ...string) (*unstructured.Unstructured, error)
|
||||
|
||||
Reference in New Issue
Block a user