Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3d182d36e7 | ||
|
|
5beeec8560 |
@@ -1325,7 +1325,6 @@ embed.go @grafana/grafana-as-code
|
||||
/conf/provisioning/datasources/ @grafana/plugins-platform-backend
|
||||
/conf/provisioning/plugins/ @grafana/plugins-platform-backend
|
||||
/conf/provisioning/sample/ @grafana/grafana-git-ui-sync-team
|
||||
/conf/apiextensions.ini @grafana/grafana-app-platform-squad
|
||||
|
||||
# Security
|
||||
/relyance.yaml @grafana/security-team
|
||||
|
||||
@@ -135,10 +135,6 @@ profile.cov
|
||||
/pkg/operators/enterprise_*
|
||||
/pkg/operators/**/enterprise_*
|
||||
|
||||
# Enterprise apiextensions server
|
||||
pkg/registry/apis/apiextensions/*
|
||||
!pkg/registry/apis/apiextensions/register.go
|
||||
|
||||
debug.test
|
||||
/examples/*/dist
|
||||
/packaging/**/*.rpm
|
||||
@@ -266,4 +262,3 @@ public/mockServiceWorker.js
|
||||
|
||||
# Ignore grafana/hippocampus local cache folder
|
||||
.hippo
|
||||
devenv/blocks/auth/signer/keys/ec_private_key.pem
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
; Run locally unified storage with SQLite to test
|
||||
; new API registration changes
|
||||
app_mode = development
|
||||
target = all
|
||||
|
||||
[log]
|
||||
level = debug
|
||||
|
||||
[server]
|
||||
; HTTPS is required for kubectl (but HTTP works for testing with curl)
|
||||
protocol = https
|
||||
http_port = 1111
|
||||
|
||||
[feature_toggles]
|
||||
; Enable the apiextensions feature
|
||||
apiExtensions = true
|
||||
; Enable unified storage globally
|
||||
unifiedStorage = true
|
||||
; Enable search indexing for unified storage
|
||||
unifiedStorageSearch = true
|
||||
; Enable the grafana-apiserver explicitly
|
||||
grafanaAPIServer = true
|
||||
; Enable K8s aggregator for API discovery aggregation
|
||||
; NOTE: This is an enterprise-only feature that requires TLS certificates
|
||||
; This will surface the new registered group APIs to the `/apis` endpoint.
|
||||
kubernetesAggregator = true
|
||||
|
||||
[grafana-apiserver]
|
||||
; Use unified storage backed by SQL (uses your Grafana database)
|
||||
storage_type = unified
|
||||
; Certificates for the Kubernetes aggregator (generated by hack/make-aggregator-pki.sh)
|
||||
proxy_client_cert_file = data/grafana-aggregator/client.crt
|
||||
proxy_client_key_file = data/grafana-aggregator/client.key
|
||||
|
||||
; Configure dashboards to use unified storage
|
||||
[unified_storage.dashboards.dashboard.grafana.app]
|
||||
dualWriterMode = 5
|
||||
|
||||
; Configure folders to use unified storage (required for dashboards)
|
||||
[unified_storage.folders.folder.grafana.app]
|
||||
dualWriterMode = 5
|
||||
|
||||
[database]
|
||||
; SQLite database for testing
|
||||
type = sqlite3
|
||||
path = grafana.db
|
||||
high_availability = false
|
||||
|
||||
; Will only be used for the MT grafana
|
||||
; apiextensions service
|
||||
; [auth.extended_jwt]
|
||||
; enabled = true
|
||||
; jwks_url = "http://localhost:6481/jwks"
|
||||
@@ -642,7 +642,7 @@ require (
|
||||
gopkg.in/telebot.v3 v3.3.8 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
k8s.io/apiextensions-apiserver v0.34.3
|
||||
k8s.io/apiextensions-apiserver v0.34.3 // indirect
|
||||
k8s.io/kms v0.34.3 // indirect
|
||||
modernc.org/libc v1.66.10 // indirect
|
||||
modernc.org/mathutil v1.7.1 // indirect
|
||||
|
||||
-17
@@ -737,7 +737,6 @@ github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRr
|
||||
github.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
github.com/emicklei/proto v1.10.0/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A=
|
||||
github.com/emicklei/proto v1.13.2/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A=
|
||||
github.com/envoyproxy/go-control-plane v0.13.4/go.mod h1:kDfuBlDVsSj2MjrLEtRWtHlsWIFcGyB2RMO44Dc5GZA=
|
||||
github.com/envoyproxy/go-control-plane/envoy v1.32.3/go.mod h1:F6hWupPfh75TBXGKA++MCT/CZHFq5r9/uwt/kQYkZfE=
|
||||
github.com/envoyproxy/go-control-plane/envoy v1.32.4/go.mod h1:Gzjc5k8JcJswLjAx1Zm+wSYE20UrLtt7JZMWiWQXQEw=
|
||||
@@ -991,7 +990,6 @@ github.com/grafana/nanogit v0.0.0-20250616082354-5e94194d02ed/go.mod h1:OIAAKNgG
|
||||
github.com/grafana/nanogit v0.0.0-20250619160700-ebf70d342aa5 h1:MAQ2B0cu0V1S91ZjVa7NomNZFjaR2SmdtvdwhqBtyhU=
|
||||
github.com/grafana/nanogit v0.0.0-20250619160700-ebf70d342aa5/go.mod h1:tN93IZUaAmnSWgL0IgnKdLv6DNeIhTJGvl1wvQMrWco=
|
||||
github.com/grafana/nanogit v0.0.0-20250723104447-68f58f5ecec0/go.mod h1:ToqLjIdvV3AZQa3K6e5m9hy/nsGaUByc2dWQlctB9iA=
|
||||
github.com/grafana/nanogit v0.0.0-20251106115617-c622d3e0fc4b/go.mod h1:ToqLjIdvV3AZQa3K6e5m9hy/nsGaUByc2dWQlctB9iA=
|
||||
github.com/grafana/prometheus-alertmanager v0.25.1-0.20240930132144-b5e64e81e8d3 h1:6D2gGAwyQBElSrp3E+9lSr7k8gLuP3Aiy20rweLWeBw=
|
||||
github.com/grafana/prometheus-alertmanager v0.25.1-0.20240930132144-b5e64e81e8d3/go.mod h1:YeND+6FDA7OuFgDzYODN8kfPhXLCehcpxe4T9mdnpCY=
|
||||
github.com/grafana/prometheus-alertmanager v0.25.1-0.20250331083058-4563aec7a975 h1:4/BZkGObFWZf4cLbE2Vqg/1VTz67Q0AJ7LHspWLKJoQ=
|
||||
@@ -1462,7 +1460,6 @@ github.com/schollz/closestmatch v2.1.0+incompatible h1:Uel2GXEpJqOWBrlyI+oY9LTiy
|
||||
github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g=
|
||||
github.com/schollz/progressbar/v3 v3.14.6 h1:GyjwcWBAf+GFDMLziwerKvpuS7ZF+mNTAXIB2aspiZs=
|
||||
github.com/schollz/progressbar/v3 v3.14.6/go.mod h1:Nrzpuw3Nl0srLY0VlTvC4V6RL50pcEymjy6qyJAaLa0=
|
||||
github.com/sclevine/spec v1.4.0 h1:z/Q9idDcay5m5irkZ28M7PtQM4aOISzOpj4bUPkDee8=
|
||||
github.com/sclevine/spec v1.4.0/go.mod h1:LvpgJaFyvQzRvc1kaDs0bulYwzC70PbiYjC4QnFHkOM=
|
||||
github.com/segmentio/asm v1.1.4/go.mod h1:Ld3L4ZXGNcSLRg4JBsZ3//1+f/TjYl0Mzen/DQy1EJg=
|
||||
github.com/segmentio/fasthash v1.0.3 h1:EI9+KE1EwvMLBWwjpRDc+fEM+prwxDYbslddQGtrmhM=
|
||||
@@ -1496,7 +1493,6 @@ github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB
|
||||
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
|
||||
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
|
||||
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
|
||||
github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0=
|
||||
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
|
||||
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
@@ -1646,13 +1642,10 @@ go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489 h1:1JFLBqwIgdyHN1Zt
|
||||
go.etcd.io/etcd v3.3.25+incompatible h1:V1RzkZJj9LqsJRy+TUBgpWSbZXITLB819lstuTFoZOY=
|
||||
go.etcd.io/etcd v3.3.25+incompatible/go.mod h1:yaeTdrJi5lOmYerz05bd8+V7KubZs8YSFZfzsF9A6aI=
|
||||
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
|
||||
go.etcd.io/etcd/api/v3 v3.6.4/go.mod h1:eFhhvfR8Px1P6SEuLT600v+vrhdDTdcfMzmnxVXXSbk=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.6.4/go.mod h1:sbdzr2cl3HzVmxNw//PH7aLGVtY4QySjQFuaCgcRFAI=
|
||||
go.etcd.io/etcd/client/v2 v2.305.4 h1:Dcx3/MYyfKcPNLpR4VVQUP5KgYrBeJtktBwEKkw08Ao=
|
||||
go.etcd.io/etcd/client/v2 v2.305.5/go.mod h1:zQjKllfqfBVyVStbt4FaosoX2iYd8fV/GRy/PbowgP4=
|
||||
go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0=
|
||||
go.etcd.io/etcd/client/v3 v3.6.4/go.mod h1:jaNNHCyg2FdALyKWnd7hxZXZxZANb0+KGY+YQaEMISo=
|
||||
go.etcd.io/etcd/raft/v3 v3.5.5/go.mod h1:76TA48q03g1y1VpTue92jZLr9lIHKUNcYdZOOGyx8rI=
|
||||
go.etcd.io/gofail v0.2.0 h1:p19drv16FKK345a09a1iubchlw/vmRuksmRzgBIGjcA=
|
||||
go.etcd.io/gofail v0.2.0/go.mod h1:nL3ILMGfkXTekKI3clMBNazKnjUZjYLKmBHzsVAnC1o=
|
||||
@@ -1976,7 +1969,6 @@ golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sU
|
||||
golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
|
||||
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
|
||||
golang.org/x/crypto v0.44.0/go.mod h1:013i+Nw79BMiQiMsOPcVCB5ZIJbYkerPrGnOa00tvmc=
|
||||
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
|
||||
golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
||||
golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
|
||||
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ=
|
||||
@@ -2259,30 +2251,24 @@ k8s.io/api v0.26.2/go.mod h1:1kjMQsFE+QHPfskEcVNgL3+Hp88B80uj0QtSOlj8itU=
|
||||
k8s.io/api v0.33.3/go.mod h1:01Y/iLUjNBM3TAvypct7DIj0M0NIZc+PzAHCIo0CYGE=
|
||||
k8s.io/api v0.34.0/go.mod h1:YzgkIzOOlhl9uwWCZNqpw6RJy9L2FK4dlJeayUoydug=
|
||||
k8s.io/api v0.34.1/go.mod h1:SB80FxFtXn5/gwzCoN6QCtPD7Vbu5w2n1S0J5gFfTYk=
|
||||
k8s.io/api v0.34.2/go.mod h1:MMBPaWlED2a8w4RSeanD76f7opUoypY8TFYkSM+3XHw=
|
||||
k8s.io/apiextensions-apiserver v0.33.3/go.mod h1:oROuctgo27mUsyp9+Obahos6CWcMISSAPzQ77CAQGz8=
|
||||
k8s.io/apiextensions-apiserver v0.34.1/go.mod h1:hP9Rld3zF5Ay2Of3BeEpLAToP+l4s5UlxiHfqRaRcMc=
|
||||
k8s.io/apiextensions-apiserver v0.34.2/go.mod h1:398CJrsgXF1wytdaanynDpJ67zG4Xq7yj91GrmYN2SE=
|
||||
k8s.io/apimachinery v0.26.2/go.mod h1:ats7nN1LExKHvJ9TmwootT00Yz05MuYqPXEXaVeOy5I=
|
||||
k8s.io/apimachinery v0.33.3/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
|
||||
k8s.io/apimachinery v0.34.0/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw=
|
||||
k8s.io/apimachinery v0.34.1/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw=
|
||||
k8s.io/apimachinery v0.34.2/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw=
|
||||
k8s.io/apiserver v0.26.2/go.mod h1:GHcozwXgXsPuOJ28EnQ/jXEM9QeG6HT22YxSNmpYNh8=
|
||||
k8s.io/apiserver v0.33.3/go.mod h1:05632ifFEe6TxwjdAIrwINHWE2hLwyADFk5mBsQa15E=
|
||||
k8s.io/apiserver v0.34.1/go.mod h1:eOOc9nrVqlBI1AFCvVzsob0OxtPZUCPiUJL45JOTBG0=
|
||||
k8s.io/apiserver v0.34.2/go.mod h1:gqJQy2yDOB50R3JUReHSFr+cwJnL8G1dzTA0YLEqAPI=
|
||||
k8s.io/client-go v0.26.2/go.mod h1:u5EjOuSyBa09yqqyY7m3abZeovO/7D/WehVVlZ2qcqU=
|
||||
k8s.io/client-go v0.33.3/go.mod h1:luqKBQggEf3shbxHY4uVENAxrDISLOarxpTKMiUuujg=
|
||||
k8s.io/client-go v0.34.0/go.mod h1:ozgMnEKXkRjeMvBZdV1AijMHLTh3pbACPvK7zFR+QQY=
|
||||
k8s.io/client-go v0.34.1/go.mod h1:kA8v0FP+tk6sZA0yKLRG67LWjqufAoSHA2xVGKw9Of8=
|
||||
k8s.io/client-go v0.34.2/go.mod h1:2VYDl1XXJsdcAxw7BenFslRQX28Dxz91U9MWKjX97fE=
|
||||
k8s.io/code-generator v0.34.3 h1:6ipJKsJZZ9q21BO8I2jEj4OLN3y8/1n4aihKN0xKmQk=
|
||||
k8s.io/code-generator v0.34.3/go.mod h1:oW73UPYpGLsbRN8Ozkhd6ZzkF8hzFCiYmvEuWZDroI4=
|
||||
k8s.io/component-base v0.26.2/go.mod h1:DxbuIe9M3IZPRxPIzhch2m1eT7uFrSBJUBuVCQEBivs=
|
||||
k8s.io/component-base v0.33.3/go.mod h1:ktBVsBzkI3imDuxYXmVxZ2zxJnYTZ4HAsVj9iF09qp4=
|
||||
k8s.io/component-base v0.34.1/go.mod h1:mknCpLlTSKHzAQJJnnHVKqjxR7gBeHRv0rPXA7gdtQ0=
|
||||
k8s.io/component-base v0.34.2/go.mod h1:9xw2FHJavUHBFpiGkZoKuYZ5pdtLKe97DEByaA+hHbM=
|
||||
k8s.io/cri-api v0.27.1/go.mod h1:+Ts/AVYbIo04S86XbTD73UPp/DkTiYxtsFeOFEu32L0=
|
||||
k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6 h1:4s3/R4+OYYYUKptXPhZKjQ04WJ6EhQQVFdjOFvCazDk=
|
||||
k8s.io/gengo/v2 v2.0.0-20250604051438-85fd79dbfd9f h1:SLb+kxmzfA87x4E4brQzB33VBbT2+x7Zq9ROIHmGn9Q=
|
||||
@@ -2296,9 +2282,7 @@ k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
|
||||
k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
|
||||
k8s.io/klog/v2 v2.90.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
|
||||
k8s.io/kms v0.34.1/go.mod h1:s1CFkLG7w9eaTYvctOxosx88fl4spqmixnNpys0JAtM=
|
||||
k8s.io/kms v0.34.2/go.mod h1:s1CFkLG7w9eaTYvctOxosx88fl4spqmixnNpys0JAtM=
|
||||
k8s.io/kube-aggregator v0.34.1/go.mod h1:RU8j+5ERfp0h+gIvWtxRPfsa5nK7rboDm8RST8BJfYQ=
|
||||
k8s.io/kube-aggregator v0.34.2/go.mod h1:/tp4cc/1p2AvICsS4mjjSJakdrbhcGbRmj0mdHTdR2Q=
|
||||
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff/go.mod h1:5jIi+8yX4RIb8wk3XwBo5Pq2ccx4FP10ohkbSKCZoK8=
|
||||
k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b/go.mod h1:UZ2yyWbFTpuhSbFhv24aGNOdoRdJZgsIObGBUaYVsts=
|
||||
k8s.io/utils v0.0.0-20230220204549-a5ecb0141aa5/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||
@@ -2334,7 +2318,6 @@ rsc.io/binaryregexp v0.2.0 h1:HfqmD5MEmC0zvwBuF187nq9mdnXjXsSivRiXN7SmRkE=
|
||||
rsc.io/pdf v0.1.1 h1:k1MczvYDUvJBe93bYd7wrZLLUEcLZAuF824/I4e5Xr4=
|
||||
rsc.io/quote/v3 v3.1.0 h1:9JKUTTIUgS6kzR9mK1YuGKv6Nl+DijDNIc0ghT58FaY=
|
||||
rsc.io/sampler v1.3.0 h1:7uVkIFmeBqHfdjD+gZwtXXI+RODJ2Wc4O7MPEh/QiW4=
|
||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw=
|
||||
sigs.k8s.io/controller-runtime v0.22.1 h1:Ah1T7I+0A7ize291nJZdS1CabF/lB4E++WizgV24Eqg=
|
||||
sigs.k8s.io/controller-runtime v0.22.1/go.mod h1:FwiwRjkRPbiN+zp2QRp7wlTCzbUXxZ/D4OzuQUDwBHY=
|
||||
sigs.k8s.io/controller-runtime v0.22.4 h1:GEjV7KV3TY8e+tJ2LCTxUTanW4z/FmNB7l327UfMq9A=
|
||||
|
||||
+4
-4
@@ -474,10 +474,6 @@ export interface FeatureToggles {
|
||||
*/
|
||||
kubernetesAggregatorCapTokenAuth?: boolean;
|
||||
/**
|
||||
* Enable Kubernetes CustomResourceDefinition (CRD) support with dynamic API registration
|
||||
*/
|
||||
apiExtensions?: boolean;
|
||||
/**
|
||||
* Enable groupBy variable support in scenes dashboards
|
||||
*/
|
||||
groupByVariable?: boolean;
|
||||
@@ -699,6 +695,10 @@ export interface FeatureToggles {
|
||||
*/
|
||||
passwordlessMagicLinkAuthentication?: boolean;
|
||||
/**
|
||||
* Display Related Logs in Grafana Metrics Drilldown
|
||||
*/
|
||||
exploreMetricsRelatedLogs?: boolean;
|
||||
/**
|
||||
* Adds support for quotes and special characters in label values for Prometheus queries
|
||||
*/
|
||||
prometheusSpecialCharsInLabelValues?: boolean;
|
||||
|
||||
@@ -163,7 +163,6 @@ var serviceIdentityTokenPermissions = []string{
|
||||
"plugins.grafana.app:*",
|
||||
"historian.alerting.grafana.app:*",
|
||||
"advisor.grafana.app:*",
|
||||
"apiextensions.grafana.app:*",
|
||||
|
||||
// Secrets Manager uses a custom verb for secret decryption, and its authorizer does not allow wildcard permissions.
|
||||
"secret.grafana.app/securevalues:decrypt",
|
||||
|
||||
@@ -131,31 +131,19 @@ func NamespaceKeyFunc(gr schema.GroupResource) func(ctx context.Context, name st
|
||||
}
|
||||
}
|
||||
|
||||
// ClusterScopedKeyFunc constructs storage paths for cluster-scoped resources (no namespace).
|
||||
func ClusterScopedKeyFunc(gr schema.GroupResource) func(ctx context.Context, name string) (string, error) {
|
||||
return func(ctx context.Context, name string) (string, error) {
|
||||
if len(name) == 0 {
|
||||
return "", apierrors.NewBadRequest("Name parameter required.")
|
||||
}
|
||||
if msgs := path.IsValidPathSegmentName(name); len(msgs) != 0 {
|
||||
return "", apierrors.NewBadRequest(fmt.Sprintf("Name parameter invalid: %q: %s", name, strings.Join(msgs, ";")))
|
||||
}
|
||||
key := &Key{
|
||||
Group: gr.Group,
|
||||
Resource: gr.Resource,
|
||||
Name: name,
|
||||
}
|
||||
return key.String(), nil
|
||||
// NoNamespaceKeyFunc is the default function for constructing storage paths
|
||||
// to a resource relative to the given prefix without a namespace.
|
||||
func NoNamespaceKeyFunc(ctx context.Context, prefix string, gr schema.GroupResource, name string) (string, error) {
|
||||
if len(name) == 0 {
|
||||
return "", apierrors.NewBadRequest("Name parameter required.")
|
||||
}
|
||||
}
|
||||
|
||||
// ClusterScopedKeyRootFunc is used by the generic registry store for cluster-scoped resources.
|
||||
func ClusterScopedKeyRootFunc(gr schema.GroupResource) func(ctx context.Context) string {
|
||||
return func(ctx context.Context) string {
|
||||
key := &Key{
|
||||
Group: gr.Group,
|
||||
Resource: gr.Resource,
|
||||
}
|
||||
return key.String()
|
||||
if msgs := path.IsValidPathSegmentName(name); len(msgs) != 0 {
|
||||
return "", apierrors.NewBadRequest(fmt.Sprintf("Name parameter invalid: %q: %s", name, strings.Join(msgs, ";")))
|
||||
}
|
||||
key := &Key{
|
||||
Group: gr.Group,
|
||||
Resource: gr.Resource,
|
||||
Name: name,
|
||||
}
|
||||
return prefix + key.String(), nil
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package generic
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
@@ -30,21 +28,10 @@ func NewRegistryStoreWithSelectableFields(scheme *runtime.Scheme, resourceInfo u
|
||||
gv := resourceInfo.GroupVersion()
|
||||
gv.Version = runtime.APIVersionInternal
|
||||
strategy := NewStrategy(scheme, gv)
|
||||
|
||||
gr := resourceInfo.GroupResource()
|
||||
var keyRootFunc func(ctx context.Context) string
|
||||
var keyFunc func(ctx context.Context, name string) (string, error)
|
||||
|
||||
if resourceInfo.IsClusterScoped() {
|
||||
strategy = strategy.WithClusterScope()
|
||||
keyRootFunc = ClusterScopedKeyRootFunc(gr)
|
||||
keyFunc = ClusterScopedKeyFunc(gr)
|
||||
} else {
|
||||
keyRootFunc = KeyRootFunc(gr)
|
||||
keyFunc = NamespaceKeyFunc(gr)
|
||||
}
|
||||
|
||||
|
||||
// Use custom GetAttrs if provided, otherwise use default
|
||||
var attrFunc storage.AttrFunc
|
||||
var predicateFunc func(label labels.Selector, field fields.Selector) storage.SelectionPredicate
|
||||
@@ -60,10 +47,10 @@ func NewRegistryStoreWithSelectableFields(scheme *runtime.Scheme, resourceInfo u
|
||||
store := ®istry.Store{
|
||||
NewFunc: resourceInfo.NewFunc,
|
||||
NewListFunc: resourceInfo.NewListFunc,
|
||||
KeyRootFunc: keyRootFunc,
|
||||
KeyFunc: keyFunc,
|
||||
KeyRootFunc: KeyRootFunc(resourceInfo.GroupResource()),
|
||||
KeyFunc: NamespaceKeyFunc(resourceInfo.GroupResource()),
|
||||
PredicateFunc: predicateFunc,
|
||||
DefaultQualifiedResource: gr,
|
||||
DefaultQualifiedResource: resourceInfo.GroupResource(),
|
||||
SingularQualifiedResource: resourceInfo.SingularGroupResource(),
|
||||
TableConvertor: resourceInfo.TableConverter(),
|
||||
CreateStrategy: strategy,
|
||||
|
||||
@@ -3,7 +3,6 @@ package aggregatorrunner
|
||||
import (
|
||||
"context"
|
||||
|
||||
apiextensionsinformers "k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions/apiextensions/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
genericapiserver "k8s.io/apiserver/pkg/server"
|
||||
|
||||
@@ -22,10 +21,6 @@ func (n NoopAggregatorConfigurator) Run(ctx context.Context, transport *options.
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (n *NoopAggregatorConfigurator) SetCRDInformer(_ apiextensionsinformers.CustomResourceDefinitionInformer) {
|
||||
// noop
|
||||
}
|
||||
|
||||
func ProvideNoopAggregatorConfigurator() AggregatorRunner {
|
||||
return &NoopAggregatorConfigurator{}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package aggregatorrunner
|
||||
import (
|
||||
"context"
|
||||
|
||||
apiextensionsinformers "k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions/apiextensions/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
genericapiserver "k8s.io/apiserver/pkg/server"
|
||||
|
||||
@@ -22,8 +21,4 @@ type AggregatorRunner interface {
|
||||
|
||||
// Run starts the complete apiserver chain, expects it executes any logic inside a goroutine and doesn't block. Returns the running server.
|
||||
Run(ctx context.Context, transport *options.RoundTripperFunc, stoppedCh chan error) (*genericapiserver.GenericAPIServer, error)
|
||||
|
||||
// SetCRDInformer sets the CRD informer for auto-registering APIServices for CRDs.
|
||||
// This should be called before Configure if CRD API is enabled.
|
||||
SetCRDInformer(informer apiextensionsinformers.CustomResourceDefinitionInformer)
|
||||
}
|
||||
|
||||
@@ -346,7 +346,6 @@ func (s *service) start(ctx context.Context) error {
|
||||
serverConfig.MaxRequestBodyBytes = MaxRequestBodyBytes
|
||||
|
||||
var optsregister apistore.StorageOptionsRegister
|
||||
var restOptsGetter *apistore.RESTOptionsGetter
|
||||
|
||||
if o.StorageOptions.StorageType == grafanaapiserveroptions.StorageTypeEtcd {
|
||||
if err := o.RecommendedOptions.Etcd.Validate(); len(err) > 0 {
|
||||
@@ -356,9 +355,9 @@ func (s *service) start(ctx context.Context) error {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
restOptsGetter = apistore.NewRESTOptionsGetterForClient(s.unified, s.secrets, o.RecommendedOptions.Etcd.StorageConfig, s.restConfigProvider)
|
||||
optsregister = restOptsGetter.RegisterOptions
|
||||
serverConfig.RESTOptionsGetter = restOptsGetter
|
||||
getter := apistore.NewRESTOptionsGetterForClient(s.unified, s.secrets, o.RecommendedOptions.Etcd.StorageConfig, s.restConfigProvider)
|
||||
optsregister = getter.RegisterOptions
|
||||
serverConfig.RESTOptionsGetter = getter
|
||||
}
|
||||
|
||||
defGetters := []common.GetOpenAPIDefinitions{
|
||||
@@ -399,11 +398,8 @@ func (s *service) start(ctx context.Context) error {
|
||||
return fmt.Errorf("failed to register post start hooks for app installers: %w", err)
|
||||
}
|
||||
|
||||
// Determine the delegate for the main server
|
||||
var delegationTarget = genericapiserver.NewEmptyDelegateWithCustomHandler(notFoundHandler)
|
||||
|
||||
// Create the main Grafana API server
|
||||
server, err := serverConfig.Complete().New("grafana-apiserver", delegationTarget)
|
||||
// Create the server
|
||||
server, err := serverConfig.Complete().New("grafana-apiserver", genericapiserver.NewEmptyDelegateWithCustomHandler(notFoundHandler))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -675,4 +671,4 @@ func useNamespaceFromPath(path string, user *user.SignedInUser) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -777,13 +777,6 @@ var (
|
||||
Owner: grafanaAppPlatformSquad,
|
||||
RequiresRestart: true,
|
||||
},
|
||||
{
|
||||
Name: "apiExtensions",
|
||||
Description: "Enable Kubernetes CustomResourceDefinition (CRD) support with dynamic API registration (Enterprise + MT-only)",
|
||||
Stage: FeatureStageExperimental,
|
||||
Owner: grafanaAppPlatformSquad,
|
||||
RequiresRestart: true,
|
||||
},
|
||||
{
|
||||
Name: "groupByVariable",
|
||||
Description: "Enable groupBy variable support in scenes dashboards",
|
||||
@@ -1155,6 +1148,14 @@ var (
|
||||
Owner: identityAccessTeam,
|
||||
HideFromDocs: true,
|
||||
},
|
||||
{
|
||||
Name: "exploreMetricsRelatedLogs",
|
||||
Description: "Display Related Logs in Grafana Metrics Drilldown",
|
||||
Stage: FeatureStageExperimental,
|
||||
Owner: grafanaObservabilityMetricsSquad,
|
||||
FrontendOnly: true,
|
||||
HideFromDocs: false,
|
||||
},
|
||||
{
|
||||
Name: "prometheusSpecialCharsInLabelValues",
|
||||
Description: "Adds support for quotes and special characters in label values for Prometheus queries",
|
||||
|
||||
Generated
+1
-1
@@ -107,7 +107,6 @@ sqlExpressions,preview,@grafana/grafana-datasources-core-services,false,false,fa
|
||||
sqlExpressionsColumnAutoComplete,experimental,@grafana/datapro,false,false,true
|
||||
kubernetesAggregator,experimental,@grafana/grafana-app-platform-squad,false,true,false
|
||||
kubernetesAggregatorCapTokenAuth,experimental,@grafana/grafana-app-platform-squad,false,true,false
|
||||
apiExtensions,experimental,@grafana/grafana-app-platform-squad,false,true,false
|
||||
groupByVariable,experimental,@grafana/dashboards-squad,false,false,false
|
||||
scopeFilters,experimental,@grafana/dashboards-squad,false,false,false
|
||||
oauthRequireSubClaim,experimental,@grafana/identity-access-team,false,false,false
|
||||
@@ -160,6 +159,7 @@ newTimeRangeZoomShortcuts,experimental,@grafana/dataviz-squad,false,false,true
|
||||
azureMonitorDisableLogLimit,GA,@grafana/partner-datasources,false,false,false
|
||||
playlistsReconciler,experimental,@grafana/grafana-app-platform-squad,false,true,false
|
||||
passwordlessMagicLinkAuthentication,experimental,@grafana/identity-access-team,false,false,false
|
||||
exploreMetricsRelatedLogs,experimental,@grafana/observability-metrics,false,false,true
|
||||
prometheusSpecialCharsInLabelValues,experimental,@grafana/oss-big-tent,false,false,true
|
||||
enableExtensionsAdminPage,experimental,@grafana/plugins-platform-backend,false,true,false
|
||||
enableSCIM,preview,@grafana/identity-access-team,false,false,false
|
||||
|
||||
|
Generated
-4
@@ -319,10 +319,6 @@ const (
|
||||
// Enable CAP token based authentication in grafana's embedded kube-aggregator
|
||||
FlagKubernetesAggregatorCapTokenAuth = "kubernetesAggregatorCapTokenAuth"
|
||||
|
||||
// FlagApiExtensions
|
||||
// Enable Kubernetes CustomResourceDefinition (CRD) support with dynamic API registration
|
||||
FlagApiExtensions = "apiExtensions"
|
||||
|
||||
// FlagGroupByVariable
|
||||
// Enable groupBy variable support in scenes dashboards
|
||||
FlagGroupByVariable = "groupByVariable"
|
||||
|
||||
+1
-15
@@ -632,19 +632,6 @@
|
||||
"expression": "true"
|
||||
}
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"name": "apiExtensions",
|
||||
"resourceVersion": "1764159104213",
|
||||
"creationTimestamp": "2025-11-26T12:11:44Z"
|
||||
},
|
||||
"spec": {
|
||||
"description": "Enable Kubernetes CustomResourceDefinition (CRD) support with dynamic API registration",
|
||||
"stage": "experimental",
|
||||
"codeowner": "@grafana/grafana-app-platform-squad",
|
||||
"requiresRestart": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"metadata": {
|
||||
"name": "appPlatformGrpcClientAuth",
|
||||
@@ -1421,8 +1408,7 @@
|
||||
"metadata": {
|
||||
"name": "exploreMetricsRelatedLogs",
|
||||
"resourceVersion": "1764664939750",
|
||||
"creationTimestamp": "2024-11-05T16:28:43Z",
|
||||
"deletionTimestamp": "2026-01-09T22:14:53Z"
|
||||
"creationTimestamp": "2024-11-05T16:28:43Z"
|
||||
},
|
||||
"spec": {
|
||||
"description": "Display Related Logs in Grafana Metrics Drilldown",
|
||||
|
||||
@@ -177,7 +177,6 @@ func (c authzLimitedClient) Compile(ctx context.Context, id claims.AuthInfo, req
|
||||
return true
|
||||
}, claims.NoopZookie{}, nil
|
||||
}
|
||||
|
||||
if !claims.NamespaceMatches(id.GetNamespace(), req.Namespace) {
|
||||
span.SetAttributes(attribute.Bool("allowed", false))
|
||||
span.SetStatus(codes.Error, "Namespace mismatch")
|
||||
|
||||
@@ -242,6 +242,23 @@ func (b *backend) initPruner(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *backend) initGarbageCollection(ctx context.Context) error {
|
||||
// TODO
|
||||
|
||||
/*
|
||||
# Garbage collect every minute?
|
||||
|
||||
gr = getGroupResources()
|
||||
for each gr in grs:
|
||||
rows = garbageCollect(gr)
|
||||
log rows deleted
|
||||
sleep 1s
|
||||
|
||||
*/
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *backend) IsHealthy(ctx context.Context, _ *resourcepb.HealthCheckRequest) (*resourcepb.HealthCheckResponse, error) {
|
||||
// ctxLogger := s.log.FromContext(log.WithContextualAttributes(ctx, []any{"method", "isHealthy"}))
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
DELETE FROM {{ .Ident "resource_history" }} h
|
||||
WHERE h.{{ .Ident "group" }} = {{ .Arg .Group }}
|
||||
AND h.{{ .Ident "resource" }} = {{ .Arg .Resource }}
|
||||
AND h.{{ .Ident "action" }} = 3
|
||||
AND h.{{ .Ident "resource_version" }} < {{ .Arg .CutoffTimestamp }}
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM {{ .Ident "resource" }} r
|
||||
WHERE r.{{ .Ident "namespace" }} = h.{{ .Ident "namespace" }}
|
||||
AND r.{{ .Ident "group" }} = h.{{ .Ident "group" }}
|
||||
AND r.{{ .Ident "resource" }} = h.{{ .Ident "resource" }}
|
||||
AND r.{{ .Ident "name" }} = h.{{ .Ident "name" }}
|
||||
)
|
||||
LIMIT {{ .Arg .BatchSize }};
|
||||
@@ -220,5 +220,11 @@ func initResourceTables(mg *migrator.Migrator) string {
|
||||
mg.AddMigration("Change key_path collation of resource_history in postgres", migrator.NewRawSQLMigration("").Postgres(`ALTER TABLE resource_history ALTER COLUMN key_path TYPE VARCHAR(2048) COLLATE "C";`))
|
||||
mg.AddMigration("Change key_path collation of resource_events in postgres", migrator.NewRawSQLMigration("").Postgres(`ALTER TABLE resource_events ALTER COLUMN key_path TYPE VARCHAR(2048) COLLATE "C";`))
|
||||
|
||||
mg.AddMigration("Add index to resource_history for garbage collection", migrator.NewAddIndexMigration(resource_history_table, &migrator.Index{
|
||||
Cols: []string{"group", "resource", "action", "resource_version", "name"},
|
||||
Type: migrator.IndexType,
|
||||
Name: "IDX_resource_history_resource_action_version_name",
|
||||
}))
|
||||
|
||||
return marker
|
||||
}
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
|
||||
import { VariableHide } from '@grafana/data';
|
||||
import { SceneGridLayout, SceneVariable, SceneVariableSet, ScopesVariable, TextBoxVariable } from '@grafana/scenes';
|
||||
|
||||
import { DashboardScene } from './DashboardScene';
|
||||
import { VariableControls } from './VariableControls';
|
||||
import { DefaultGridLayoutManager } from './layout-default/DefaultGridLayoutManager';
|
||||
|
||||
jest.mock('@grafana/runtime', () => {
|
||||
const runtime = jest.requireActual('@grafana/runtime');
|
||||
return {
|
||||
...runtime,
|
||||
config: {
|
||||
...runtime.config,
|
||||
featureToggles: {
|
||||
dashboardNewLayouts: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
describe('VariableControls', () => {
|
||||
it('should not render scopes variable', () => {
|
||||
const variables = [new ScopesVariable({})];
|
||||
const dashboard = buildScene(variables);
|
||||
dashboard.activate();
|
||||
|
||||
render(<VariableControls dashboard={dashboard} />);
|
||||
|
||||
expect(screen.queryByText('__scopes')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should not render regular hidden variables', () => {
|
||||
const hiddenVariable = new TextBoxVariable({
|
||||
name: 'HiddenVar',
|
||||
hide: VariableHide.hideVariable,
|
||||
});
|
||||
const variables = [hiddenVariable];
|
||||
const dashboard = buildScene(variables);
|
||||
dashboard.activate();
|
||||
|
||||
render(<VariableControls dashboard={dashboard} />);
|
||||
|
||||
expect(screen.queryByText('HiddenVar')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should render regular hidden variables in edit mode', async () => {
|
||||
const hiddenVariable = new TextBoxVariable({
|
||||
name: 'HiddenVar',
|
||||
hide: VariableHide.hideVariable,
|
||||
});
|
||||
const variables = [hiddenVariable];
|
||||
const dashboard = buildScene(variables);
|
||||
dashboard.activate();
|
||||
|
||||
dashboard.setState({ isEditing: true });
|
||||
render(<VariableControls dashboard={dashboard} />);
|
||||
|
||||
expect(await screen.findByText('HiddenVar')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should not render variables hidden in controls menu in edit mode', async () => {
|
||||
const dashboard = buildScene([new TextBoxVariable({ name: 'TextVarControls', hide: VariableHide.inControlsMenu })]);
|
||||
dashboard.activate();
|
||||
|
||||
dashboard.setState({ isEditing: true });
|
||||
render(<VariableControls dashboard={dashboard} />);
|
||||
|
||||
expect(screen.queryByText('TextVarControls')).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
function buildScene(variables: SceneVariable[] = []) {
|
||||
const dashboard = new DashboardScene({
|
||||
$variables: new SceneVariableSet({ variables }),
|
||||
body: new DefaultGridLayoutManager({
|
||||
grid: new SceneGridLayout({
|
||||
children: [],
|
||||
}),
|
||||
}),
|
||||
});
|
||||
return dashboard;
|
||||
}
|
||||
@@ -39,9 +39,8 @@ export function VariableControls({ dashboard }: { dashboard: DashboardScene }) {
|
||||
? restVariables.filter((v) => v.state.hide !== VariableHide.inControlsMenu)
|
||||
: variables.filter(
|
||||
(v) =>
|
||||
// used for scopes variables, should always be hidden
|
||||
// if we're editing in dynamic dashboards, still shows hidden variable but greyed out
|
||||
(!v.UNSAFE_renderAsHidden && isEditingNewLayouts && v.state.hide === VariableHide.hideVariable) ||
|
||||
(isEditingNewLayouts && v.state.hide === VariableHide.hideVariable) ||
|
||||
v.state.hide !== VariableHide.inControlsMenu
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user