mirror of
https://github.com/grafana/grafana.git
synced 2026-01-14 13:21:26 +00:00
Compare commits
11 Commits
sqlkv-enab
...
ale/apiext
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3ef7d6d2a7 | ||
|
|
8d20008b84 | ||
|
|
14d2507f3b | ||
|
|
39c34f85f4 | ||
|
|
9e4e93bf5e | ||
|
|
8df2debd34 | ||
|
|
d146d2c539 | ||
|
|
1bd36486e9 | ||
|
|
b99639fe7a | ||
|
|
719d779171 | ||
|
|
09d98402c4 |
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
@@ -1325,6 +1325,7 @@ 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
|
||||
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -135,6 +135,10 @@ 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
|
||||
@@ -262,3 +266,4 @@ public/mockServiceWorker.js
|
||||
|
||||
# Ignore grafana/hippocampus local cache folder
|
||||
.hippo
|
||||
devenv/blocks/auth/signer/keys/ec_private_key.pem
|
||||
|
||||
53
conf/apiextensions.ini
Normal file
53
conf/apiextensions.ini
Normal file
@@ -0,0 +1,53 @@
|
||||
; 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"
|
||||
2
go.mod
2
go.mod
@@ -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 // indirect
|
||||
k8s.io/apiextensions-apiserver v0.34.3
|
||||
k8s.io/kms v0.34.3 // indirect
|
||||
modernc.org/libc v1.66.10 // indirect
|
||||
modernc.org/mathutil v1.7.1 // indirect
|
||||
|
||||
17
go.work.sum
17
go.work.sum
@@ -737,6 +737,7 @@ 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=
|
||||
@@ -990,6 +991,7 @@ 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=
|
||||
@@ -1460,6 +1462,7 @@ 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=
|
||||
@@ -1493,6 +1496,7 @@ 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=
|
||||
@@ -1642,10 +1646,13 @@ 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=
|
||||
@@ -1969,6 +1976,7 @@ 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=
|
||||
@@ -2251,24 +2259,30 @@ 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=
|
||||
@@ -2282,7 +2296,9 @@ 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=
|
||||
@@ -2318,6 +2334,7 @@ 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=
|
||||
|
||||
@@ -474,6 +474,10 @@ 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;
|
||||
|
||||
@@ -163,6 +163,7 @@ 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,19 +131,31 @@ func NamespaceKeyFunc(gr schema.GroupResource) func(ctx context.Context, name st
|
||||
}
|
||||
}
|
||||
|
||||
// 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.")
|
||||
// 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
|
||||
}
|
||||
}
|
||||
|
||||
// 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,6 +1,8 @@
|
||||
package generic
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
@@ -28,10 +30,21 @@ 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
|
||||
@@ -47,10 +60,10 @@ func NewRegistryStoreWithSelectableFields(scheme *runtime.Scheme, resourceInfo u
|
||||
store := ®istry.Store{
|
||||
NewFunc: resourceInfo.NewFunc,
|
||||
NewListFunc: resourceInfo.NewListFunc,
|
||||
KeyRootFunc: KeyRootFunc(resourceInfo.GroupResource()),
|
||||
KeyFunc: NamespaceKeyFunc(resourceInfo.GroupResource()),
|
||||
KeyRootFunc: keyRootFunc,
|
||||
KeyFunc: keyFunc,
|
||||
PredicateFunc: predicateFunc,
|
||||
DefaultQualifiedResource: resourceInfo.GroupResource(),
|
||||
DefaultQualifiedResource: gr,
|
||||
SingularQualifiedResource: resourceInfo.SingularGroupResource(),
|
||||
TableConvertor: resourceInfo.TableConverter(),
|
||||
CreateStrategy: strategy,
|
||||
|
||||
@@ -3,6 +3,7 @@ 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"
|
||||
|
||||
@@ -21,6 +22,10 @@ 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,6 +3,7 @@ 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"
|
||||
|
||||
@@ -21,4 +22,8 @@ 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,6 +346,7 @@ 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 {
|
||||
@@ -355,9 +356,9 @@ func (s *service) start(ctx context.Context) error {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
getter := apistore.NewRESTOptionsGetterForClient(s.unified, s.secrets, o.RecommendedOptions.Etcd.StorageConfig, s.restConfigProvider)
|
||||
optsregister = getter.RegisterOptions
|
||||
serverConfig.RESTOptionsGetter = getter
|
||||
restOptsGetter = apistore.NewRESTOptionsGetterForClient(s.unified, s.secrets, o.RecommendedOptions.Etcd.StorageConfig, s.restConfigProvider)
|
||||
optsregister = restOptsGetter.RegisterOptions
|
||||
serverConfig.RESTOptionsGetter = restOptsGetter
|
||||
}
|
||||
|
||||
defGetters := []common.GetOpenAPIDefinitions{
|
||||
@@ -398,8 +399,11 @@ func (s *service) start(ctx context.Context) error {
|
||||
return fmt.Errorf("failed to register post start hooks for app installers: %w", err)
|
||||
}
|
||||
|
||||
// Create the server
|
||||
server, err := serverConfig.Complete().New("grafana-apiserver", genericapiserver.NewEmptyDelegateWithCustomHandler(notFoundHandler))
|
||||
// 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)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -671,4 +675,4 @@ func useNamespaceFromPath(path string, user *user.SignedInUser) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -777,6 +777,13 @@ 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",
|
||||
|
||||
1
pkg/services/featuremgmt/toggles_gen.csv
generated
1
pkg/services/featuremgmt/toggles_gen.csv
generated
@@ -107,6 +107,7 @@ 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
|
||||
|
||||
|
4
pkg/services/featuremgmt/toggles_gen.go
generated
4
pkg/services/featuremgmt/toggles_gen.go
generated
@@ -319,6 +319,10 @@ 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"
|
||||
|
||||
13
pkg/services/featuremgmt/toggles_gen.json
generated
13
pkg/services/featuremgmt/toggles_gen.json
generated
@@ -632,6 +632,19 @@
|
||||
"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",
|
||||
|
||||
@@ -177,6 +177,7 @@ 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")
|
||||
|
||||
Reference in New Issue
Block a user