K8S: cleanup and consolidate feature toggles (#63212)

This commit is contained in:
Ryan McKinley 2023-02-09 09:54:00 -08:00 committed by GitHub
parent 94241f6676
commit 0018c8e9c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 2 additions and 455 deletions

View File

@ -101,8 +101,6 @@ The following toggles require explicitly setting Grafana's [app mode]({{< relref
| ------------------------------ | ----------------------------------------------------------------------- | | ------------------------------ | ----------------------------------------------------------------------- |
| `publicDashboardsEmailSharing` | Allows public dashboard sharing to be restricted to only allowed emails | | `publicDashboardsEmailSharing` | Allows public dashboard sharing to be restricted to only allowed emails |
| `k8s` | Explore native k8s integrations | | `k8s` | Explore native k8s integrations |
| `k8sDashboards` | Save dashboards via k8s |
| `apiserver` | Add a k8s API server proxy |
| `dashboardsFromStorage` | Load dashboards from the generic storage interface | | `dashboardsFromStorage` | Load dashboards from the generic storage interface |
| `export` | Export grafana instance (to git, etc) | | `export` | Export grafana instance (to git, etc) |
| `grpcServer` | Run GRPC server | | `grpcServer` | Run GRPC server |

10
go.mod
View File

@ -25,10 +25,8 @@ replace cuelang.org/go => github.com/sdboyer/cue v0.5.0-beta.2.0.20221218111347-
replace k8s.io/client-go => k8s.io/client-go v0.25.3 replace k8s.io/client-go => k8s.io/client-go v0.25.3
require ( require (
k8s.io/api v0.25.3 // indirect
k8s.io/apiextensions-apiserver v0.25.3 k8s.io/apiextensions-apiserver v0.25.3
k8s.io/apimachinery v0.25.3 k8s.io/apimachinery v0.25.3
k8s.io/client-go v12.0.0+incompatible
) )
require ( require (
@ -130,7 +128,7 @@ require (
gopkg.in/square/go-jose.v2 v2.5.1 gopkg.in/square/go-jose.v2 v2.5.1
gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 gopkg.in/yaml.v3 v3.0.1
xorm.io/builder v0.3.6 xorm.io/builder v0.3.6 // indirect
xorm.io/core v0.7.3 xorm.io/core v0.7.3
xorm.io/xorm v0.8.2 xorm.io/xorm v0.8.2
) )
@ -298,11 +296,9 @@ require (
github.com/drone/drone-go v1.7.1 // indirect github.com/drone/drone-go v1.7.1 // indirect
github.com/drone/envsubst v1.0.3 // indirect github.com/drone/envsubst v1.0.3 // indirect
github.com/drone/runner-go v1.12.0 // indirect github.com/drone/runner-go v1.12.0 // indirect
github.com/emicklei/go-restful/v3 v3.8.0 // indirect
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1 // indirect github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1 // indirect
github.com/envoyproxy/protoc-gen-validate v0.6.7 // indirect github.com/envoyproxy/protoc-gen-validate v0.6.7 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/google/gnostic v0.5.7-v3refs // indirect
github.com/google/go-querystring v1.1.0 // indirect github.com/google/go-querystring v1.1.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect github.com/google/gofuzz v1.2.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.2.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.2.0 // indirect
@ -321,7 +317,6 @@ require (
github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 // indirect github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 // indirect
github.com/rivo/uniseg v0.3.4 // indirect github.com/rivo/uniseg v0.3.4 // indirect
@ -330,17 +325,14 @@ require (
github.com/segmentio/asm v1.1.4 // indirect github.com/segmentio/asm v1.1.4 // indirect
github.com/shopspring/decimal v1.2.0 // indirect github.com/shopspring/decimal v1.2.0 // indirect
github.com/spf13/cast v1.5.0 // indirect github.com/spf13/cast v1.5.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/unknwon/bra v0.0.0-20200517080246-1e3013ecaff8 // indirect github.com/unknwon/bra v0.0.0-20200517080246-1e3013ecaff8 // indirect
github.com/unknwon/com v1.0.1 // indirect github.com/unknwon/com v1.0.1 // indirect
github.com/unknwon/log v0.0.0-20150304194804-e617c87089d3 // indirect github.com/unknwon/log v0.0.0-20150304194804-e617c87089d3 // indirect
go.opentelemetry.io/otel/metric v0.34.0 // indirect go.opentelemetry.io/otel/metric v0.34.0 // indirect
go.starlark.net v0.0.0-20221020143700-22309ac47eac // indirect go.starlark.net v0.0.0-20221020143700-22309ac47eac // indirect
golang.org/x/term v0.3.0 // indirect
gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect gopkg.in/fsnotify/fsnotify.v1 v1.4.7 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect
k8s.io/klog/v2 v2.80.0 // indirect k8s.io/klog/v2 v2.80.0 // indirect
k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1 // indirect
k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed // indirect k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed // indirect
sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect

2
go.sum
View File

@ -727,6 +727,7 @@ github.com/elazarl/goproxy v0.0.0-20220115173737-adb46da277ac/go.mod h1:Ro8st/El
github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
github.com/elazarl/goproxy/ext v0.0.0-20220115173737-adb46da277ac h1:9yrT5tmn9Zc0ytWPASlaPwQfQMQYnRf0RSDe1XvHw0Q= github.com/elazarl/goproxy/ext v0.0.0-20220115173737-adb46da277ac h1:9yrT5tmn9Zc0ytWPASlaPwQfQMQYnRf0RSDe1XvHw0Q=
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/emicklei/go-restful v2.9.5+incompatible h1:spTtZBk5DYEvbxMVutUuTyh1Ao2r4iyvLdACqsl/Ljk=
github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/emicklei/go-restful/v3 v3.8.0 h1:eCZ8ulSerjdAiaNpF7GxXIE7ZCMo1moN1qX+S609eVw= github.com/emicklei/go-restful/v3 v3.8.0 h1:eCZ8ulSerjdAiaNpF7GxXIE7ZCMo1moN1qX+S609eVw=
github.com/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
@ -1839,7 +1840,6 @@ github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vv
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU= github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU=
github.com/onsi/ginkgo/v2 v2.1.6 h1:Fx2POJZfKRQcM1pH49qSZiYeu319wji004qX+GDovrU=
github.com/onsi/ginkgo/v2 v2.1.6/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk= github.com/onsi/ginkgo/v2 v2.1.6/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk=
github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v0.0.0-20151007035656-2152b45fa28a/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=

View File

@ -37,8 +37,6 @@ export interface FeatureToggles {
migrationLocking?: boolean; migrationLocking?: boolean;
storage?: boolean; storage?: boolean;
k8s?: boolean; k8s?: boolean;
k8sDashboards?: boolean;
apiserver?: boolean;
supportBundles?: boolean; supportBundles?: boolean;
dashboardsFromStorage?: boolean; dashboardsFromStorage?: boolean;
export?: boolean; export?: boolean;

View File

@ -93,7 +93,6 @@ import (
"github.com/grafana/grafana/pkg/services/stats" "github.com/grafana/grafana/pkg/services/stats"
"github.com/grafana/grafana/pkg/services/store" "github.com/grafana/grafana/pkg/services/store"
"github.com/grafana/grafana/pkg/services/store/entity/httpentitystore" "github.com/grafana/grafana/pkg/services/store/entity/httpentitystore"
"github.com/grafana/grafana/pkg/services/store/k8saccess"
"github.com/grafana/grafana/pkg/services/tag" "github.com/grafana/grafana/pkg/services/tag"
"github.com/grafana/grafana/pkg/services/team" "github.com/grafana/grafana/pkg/services/team"
"github.com/grafana/grafana/pkg/services/teamguardian" "github.com/grafana/grafana/pkg/services/teamguardian"
@ -258,7 +257,6 @@ func ProvideHTTPServer(opts ServerOptions, cfg *setting.Cfg, routeRegister routi
annotationRepo annotations.Repository, tagService tag.Service, searchv2HTTPService searchV2.SearchHTTPService, annotationRepo annotations.Repository, tagService tag.Service, searchv2HTTPService searchV2.SearchHTTPService,
queryLibraryHTTPService querylibrary.HTTPService, queryLibraryService querylibrary.Service, oauthTokenService oauthtoken.OAuthTokenService, queryLibraryHTTPService querylibrary.HTTPService, queryLibraryService querylibrary.Service, oauthTokenService oauthtoken.OAuthTokenService,
statsService stats.Service, authnService authn.Service, pluginsCDNService *pluginscdn.Service, statsService stats.Service, authnService authn.Service, pluginsCDNService *pluginscdn.Service,
k8saccess k8saccess.K8SAccess, // required so that the router is registered
starApi *starApi.API, starApi *starApi.API,
) (*HTTPServer, error) { ) (*HTTPServer, error) {
web.Env = cfg.Env web.Env = cfg.Env

View File

@ -124,7 +124,6 @@ import (
"github.com/grafana/grafana/pkg/services/store" "github.com/grafana/grafana/pkg/services/store"
"github.com/grafana/grafana/pkg/services/store/entity/httpentitystore" "github.com/grafana/grafana/pkg/services/store/entity/httpentitystore"
"github.com/grafana/grafana/pkg/services/store/entity/sqlstash" "github.com/grafana/grafana/pkg/services/store/entity/sqlstash"
"github.com/grafana/grafana/pkg/services/store/k8saccess"
"github.com/grafana/grafana/pkg/services/store/kind" "github.com/grafana/grafana/pkg/services/store/kind"
"github.com/grafana/grafana/pkg/services/store/resolver" "github.com/grafana/grafana/pkg/services/store/resolver"
"github.com/grafana/grafana/pkg/services/store/sanitizer" "github.com/grafana/grafana/pkg/services/store/sanitizer"
@ -365,7 +364,6 @@ var wireBasicSet = wire.NewSet(
wire.Bind(new(tag.Service), new(*tagimpl.Service)), wire.Bind(new(tag.Service), new(*tagimpl.Service)),
authnimpl.ProvideService, authnimpl.ProvideService,
wire.Bind(new(authn.Service), new(*authnimpl.Service)), wire.Bind(new(authn.Service), new(*authnimpl.Service)),
k8saccess.ProvideK8SAccess,
supportbundlesimpl.ProvideService, supportbundlesimpl.ProvideService,
) )

View File

@ -3,22 +3,12 @@ package service
import ( import (
"github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/featuremgmt" "github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/store/entity"
"github.com/grafana/grafana/pkg/services/store/k8saccess"
) )
func ProvideSimpleDashboardService( func ProvideSimpleDashboardService(
features featuremgmt.FeatureToggles, features featuremgmt.FeatureToggles,
svc *DashboardServiceImpl, svc *DashboardServiceImpl,
k8s k8saccess.K8SAccess,
store entity.EntityStoreServer,
) dashboards.DashboardService { ) dashboards.DashboardService {
if features.IsEnabled(featuremgmt.FlagK8sDashboards) {
if k8s.GetSystemClient() == nil {
panic("k8s dashboards requires the k8s client registered")
}
return k8saccess.NewDashboardService(svc, store)
}
return svc return svc
} }

View File

@ -119,18 +119,6 @@ var (
State: FeatureStateAlpha, State: FeatureStateAlpha,
RequiresDevMode: true, RequiresDevMode: true,
}, },
{
Name: "k8sDashboards",
Description: "Save dashboards via k8s",
State: FeatureStateAlpha,
RequiresDevMode: true,
},
{
Name: "apiserver",
Description: "Add a k8s API server proxy",
State: FeatureStateAlpha,
RequiresDevMode: true,
},
{ {
Name: "supportBundles", Name: "supportBundles",
Description: "Support bundles for troubleshooting", Description: "Support bundles for troubleshooting",

View File

@ -91,14 +91,6 @@ const (
// Explore native k8s integrations // Explore native k8s integrations
FlagK8s = "k8s" FlagK8s = "k8s"
// FlagK8sDashboards
// Save dashboards via k8s
FlagK8sDashboards = "k8sDashboards"
// FlagApiserver
// Add a k8s API server proxy
FlagApiserver = "apiserver"
// FlagSupportBundles // FlagSupportBundles
// Support bundles for troubleshooting // Support bundles for troubleshooting
FlagSupportBundles = "supportBundles" FlagSupportBundles = "supportBundles"

View File

@ -25,7 +25,6 @@ func TestFeatureToggleFiles(t *testing.T) {
"live-pipeline": true, "live-pipeline": true,
"live-service-web-worker": true, "live-service-web-worker": true,
"k8s": true, // Camel case does not like this one "k8s": true, // Camel case does not like this one
"k8sDashboards": true, // or this one
} }
t.Run("check registry constraints", func(t *testing.T) { t.Run("check registry constraints", func(t *testing.T) {

View File

@ -170,16 +170,6 @@ func (s *ServiceImpl) getServerAdminNode(c *contextmodel.ReqContext) *navtree.Na
Url: s.cfg.AppSubURL + "/admin/storage/export", Url: s.cfg.AppSubURL + "/admin/storage/export",
}) })
} }
if s.features.IsEnabled(featuremgmt.FlagK8s) {
storage.Children = append(storage.Children, &navtree.NavLink{
Text: "Kubernetes",
Id: "k8s",
SubTitle: "Manage k8s storage",
Icon: "cube",
Url: s.cfg.AppSubURL + "/admin/storage/k8s",
})
}
} }
if s.cfg.LDAPEnabled && hasAccess(ac.ReqGrafanaAdmin, ac.EvalPermission(ac.ActionLDAPStatusRead)) { if s.cfg.LDAPEnabled && hasAccess(ac.ReqGrafanaAdmin, ac.EvalPermission(ac.ActionLDAPStatusRead)) {

View File

@ -1,100 +0,0 @@
package k8saccess
import (
"net/http"
"net/url"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
"github.com/grafana/grafana/pkg/web"
)
type clientWrapper struct {
err error
baseURL *url.URL
client *kubernetes.Clientset
config *rest.Config
httpClient *http.Client
}
func newClientWrapper(config *rest.Config) *clientWrapper {
if config.UserAgent == "" {
config.UserAgent = rest.DefaultKubernetesUserAgent()
}
url, _, err := defaultServerUrlFor(config)
wrapper := &clientWrapper{
config: config,
baseURL: url,
err: err,
}
if err == nil && config != nil {
// share the transport between all clients
wrapper.httpClient, wrapper.err = rest.HTTPClientFor(config)
if wrapper.err == nil {
wrapper.client, wrapper.err = kubernetes.NewForConfigAndClient(config, wrapper.httpClient)
}
}
return wrapper
}
func (s *clientWrapper) getInfo() map[string]interface{} {
info := make(map[string]interface{}, 0)
if s.err != nil {
info["error"] = s.err.Error()
}
if s.baseURL != nil {
info["baseURL"] = s.baseURL.String()
}
if s.client != nil {
v, err := s.client.ServerVersion()
if err != nil {
info["version_error"] = err.Error()
}
if v != nil {
info["k8s.version"] = v
}
}
return info
}
// defaultServerUrlFor is shared between IsConfigTransportTLS and RESTClientFor. It
// requires Host and Version to be set prior to being called.
func defaultServerUrlFor(config *rest.Config) (*url.URL, string, error) {
// TODO: move the default to secure when the apiserver supports TLS by default
// config.Insecure is taken to mean "I want HTTPS but don't bother checking the certs against a CA."
hasCA := len(config.CAFile) != 0 || len(config.CAData) != 0
hasCert := len(config.CertFile) != 0 || len(config.CertData) != 0
defaultTLS := hasCA || hasCert || config.Insecure
host := config.Host
if host == "" {
host = "localhost"
}
if config.GroupVersion != nil {
return rest.DefaultServerURL(host, config.APIPath, *config.GroupVersion, defaultTLS)
}
return rest.DefaultServerURL(host, config.APIPath, schema.GroupVersion{}, defaultTLS)
}
func (s *clientWrapper) doProxy(c *contextmodel.ReqContext) {
if s.baseURL == nil {
c.Resp.WriteHeader(500)
return
}
params := web.Params(c.Req)
path := params["*"]
url := s.baseURL.JoinPath(path)
_, _ = c.Resp.Write([]byte("TODO, proxy: " + url.String()))
}

View File

@ -1,93 +0,0 @@
package k8saccess
import (
"context"
"fmt"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/folder"
"github.com/grafana/grafana/pkg/services/store/entity"
)
type k8sDashboardService struct {
orig dashboards.DashboardService
store entity.EntityStoreServer
}
var _ dashboards.DashboardService = (*k8sDashboardService)(nil)
func NewDashboardService(orig dashboards.DashboardService, store entity.EntityStoreServer) dashboards.DashboardService {
return &k8sDashboardService{
orig: orig,
store: store,
}
}
func (s *k8sDashboardService) BuildSaveDashboardCommand(ctx context.Context, dto *dashboards.SaveDashboardDTO, shouldValidateAlerts bool, validateProvisionedDashboard bool) (*dashboards.SaveDashboardCommand, error) {
return s.orig.BuildSaveDashboardCommand(ctx, dto, shouldValidateAlerts, validateProvisionedDashboard)
}
func (s *k8sDashboardService) DeleteDashboard(ctx context.Context, dashboardId int64, orgId int64) error {
return s.orig.DeleteDashboard(ctx, dashboardId, orgId)
}
func (s *k8sDashboardService) FindDashboards(ctx context.Context, query *dashboards.FindPersistedDashboardsQuery) ([]dashboards.DashboardSearchProjection, error) {
return s.orig.FindDashboards(ctx, query)
}
func (s *k8sDashboardService) GetDashboard(ctx context.Context, query *dashboards.GetDashboardQuery) (*dashboards.Dashboard, error) {
return s.orig.GetDashboard(ctx, query)
}
func (s *k8sDashboardService) GetDashboardACLInfoList(ctx context.Context, query *dashboards.GetDashboardACLInfoListQuery) ([]*dashboards.DashboardACLInfoDTO, error) {
return s.orig.GetDashboardACLInfoList(ctx, query)
}
func (s *k8sDashboardService) GetDashboards(ctx context.Context, query *dashboards.GetDashboardsQuery) ([]*dashboards.Dashboard, error) {
return s.orig.GetDashboards(ctx, query)
}
func (s *k8sDashboardService) GetDashboardTags(ctx context.Context, query *dashboards.GetDashboardTagsQuery) ([]*dashboards.DashboardTagCloudItem, error) {
return s.orig.GetDashboardTags(ctx, query)
}
func (s *k8sDashboardService) GetDashboardUIDByID(ctx context.Context, query *dashboards.GetDashboardRefByIDQuery) (*dashboards.DashboardRef, error) {
return s.orig.GetDashboardUIDByID(ctx, query)
}
func (s *k8sDashboardService) HasAdminPermissionInDashboardsOrFolders(ctx context.Context, query *folder.HasAdminPermissionInDashboardsOrFoldersQuery) (bool, error) {
return s.orig.HasAdminPermissionInDashboardsOrFolders(ctx, query)
}
func (s *k8sDashboardService) HasEditPermissionInFolders(ctx context.Context, query *folder.HasEditPermissionInFoldersQuery) (bool, error) {
return s.orig.HasEditPermissionInFolders(ctx, query)
}
func (s *k8sDashboardService) ImportDashboard(ctx context.Context, dto *dashboards.SaveDashboardDTO) (*dashboards.Dashboard, error) {
return s.orig.ImportDashboard(ctx, dto)
}
func (s *k8sDashboardService) MakeUserAdmin(ctx context.Context, orgID int64, userID, dashboardID int64, setViewAndEditPermissions bool) error {
return s.orig.MakeUserAdmin(ctx, orgID, userID, dashboardID, setViewAndEditPermissions)
}
func (s *k8sDashboardService) SaveDashboard(ctx context.Context, dto *dashboards.SaveDashboardDTO, allowUiUpdate bool) (*dashboards.Dashboard, error) {
fmt.Printf("SAVE: " + dto.Dashboard.UID)
return s.orig.SaveDashboard(ctx, dto, allowUiUpdate)
}
func (s *k8sDashboardService) SearchDashboards(ctx context.Context, query *dashboards.FindPersistedDashboardsQuery) error {
return s.orig.SearchDashboards(ctx, query)
}
func (s *k8sDashboardService) UpdateDashboardACL(ctx context.Context, uid int64, items []*dashboards.DashboardACL) error {
return s.orig.UpdateDashboardACL(ctx, uid, items)
}
func (s *k8sDashboardService) DeleteACLByUser(ctx context.Context, userID int64) error {
return s.orig.DeleteACLByUser(ctx, userID)
}
func (s *k8sDashboardService) CountDashboardsInFolder(ctx context.Context, query *dashboards.CountDashboardsInFolderQuery) (int64, error) {
return s.orig.CountDashboardsInFolder(ctx, query)
}

View File

@ -1,52 +0,0 @@
package k8saccess
import (
"github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/api/routing"
"github.com/grafana/grafana/pkg/middleware"
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
)
type httpHelper struct {
access *k8sAccess
}
func newHTTPHelper(access *k8sAccess, router routing.RouteRegister) *httpHelper {
s := &httpHelper{
access: access,
}
// Must be admin for everything
router.Group("/api/k8s", func(k8sRoute routing.RouteRegister) {
k8sRoute.Get("/info", middleware.ReqOrgAdmin, routing.Wrap(s.showClientInfo))
k8sRoute.Any("/proxy/*", middleware.ReqOrgAdmin, s.doProxy)
})
return s
}
func (s *httpHelper) showClientInfo(c *contextmodel.ReqContext) response.Response {
if s.access.sys != nil {
info := s.access.sys.getInfo()
if s.access.sys.err != nil {
return response.JSON(500, info)
}
return response.JSON(200, info)
}
return response.JSON(500, map[string]interface{}{
"error": "no client initialized",
})
}
func (s *httpHelper) doProxy(c *contextmodel.ReqContext) {
// TODO... this does not yet do a real proxy
if s.access.sys != nil {
if s.access.sys.err == nil {
s.access.sys.doProxy(c)
} else {
c.Resp.WriteHeader(500)
}
return
}
_, _ = c.Resp.Write([]byte("??"))
}

View File

@ -1,81 +0,0 @@
package k8saccess
import (
"os"
"path/filepath"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"github.com/grafana/grafana/pkg/api/routing"
"github.com/grafana/grafana/pkg/registry"
"github.com/grafana/grafana/pkg/services/featuremgmt"
)
type K8SAccess interface {
registry.CanBeDisabled
// Get the system client
GetSystemClient() *kubernetes.Clientset
}
var _ K8SAccess = &k8sAccess{}
type k8sAccess struct {
enabled bool
apihelper *httpHelper
sys *clientWrapper
}
func ProvideK8SAccess(toggles featuremgmt.FeatureToggles, router routing.RouteRegister) K8SAccess {
access := &k8sAccess{
enabled: toggles.IsEnabled(featuremgmt.FlagK8s),
}
// Skips setting up any HTTP routing
if !access.enabled {
return access // dummy
}
// If we are in a cluster, this is the
config, err := rest.InClusterConfig()
// Look for kube config setup
if err != nil {
var home string
var configBytes []byte
home, err = os.UserHomeDir()
if err == nil {
fpath := filepath.Join(home, ".kube", "config")
//nolint:gosec
configBytes, err = os.ReadFile(fpath)
if err == nil {
config, err = clientcmd.RESTConfigFromKubeConfig(configBytes)
}
}
}
if err == nil && config != nil {
access.sys = newClientWrapper(config)
} else {
access.sys = &clientWrapper{
err: err,
}
}
access.apihelper = newHTTPHelper(access, router)
return access
}
func (s *k8sAccess) IsDisabled() bool {
return !s.enabled
}
// Return access to the system k8s client
func (s *k8sAccess) GetSystemClient() *kubernetes.Clientset {
if s.sys != nil {
return s.sys.client
}
return nil
}

View File

@ -1,63 +0,0 @@
import { css } from '@emotion/css';
import React from 'react';
import { useAsync } from 'react-use';
import { GrafanaTheme2 } from '@grafana/data';
import { getBackendSrv } from '@grafana/runtime';
import { useStyles2, Spinner, Alert } from '@grafana/ui';
import { Page } from 'app/core/components/Page/Page';
import { useNavModel } from 'app/core/hooks/useNavModel';
import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
interface RouteParams {
// path: string;
}
interface QueryParams {
// view: StorageView;
}
interface Props extends GrafanaRouteComponentProps<RouteParams, QueryParams> {}
export default function K8SPage(props: Props) {
const styles = useStyles2(getStyles);
const navModel = useNavModel('k8s');
const info = useAsync(() => {
return getBackendSrv().get('/api/k8s/info');
});
const renderView = () => {
if (info.value) {
return <pre>{JSON.stringify(info.value, null, 2)}</pre>;
}
if (info.loading) {
return <Spinner />;
}
return (
<div className={styles.wrapper}>
<Alert title="No k8s client configured." severity="warning" />
At startup, a service tries to load a client using:
<ul>
<li>
Default <a href="https://github.com/kubernetes/client-go/blob/master/rest/config.go#L511">in cluster</a>{' '}
configs
</li>
<li>$HOME/.kube/config, perhaps with minikube running</li>
</ul>
</div>
);
};
return (
<Page navModel={navModel}>
<Page.Contents isLoading={info.loading}>{renderView()}</Page.Contents>
</Page>
);
}
const getStyles = (theme: GrafanaTheme2) => ({
wrapper: css`
display: block;
`,
});

View File

@ -366,13 +366,6 @@ export function getAppRoutes(): RouteDescriptor[] {
() => import(/* webpackChunkName: "AdminEditOrgPage" */ 'app/features/admin/AdminEditOrgPage') () => import(/* webpackChunkName: "AdminEditOrgPage" */ 'app/features/admin/AdminEditOrgPage')
), ),
}, },
{
path: '/admin/storage/k8s',
roles: () => ['Admin'],
component: SafeDynamicImport(
() => import(/* webpackChunkName: "K8SStoragePage" */ 'app/features/storage/k8s/K8SPage')
),
},
{ {
path: '/admin/storage/export', path: '/admin/storage/export',
roles: () => ['Admin'], roles: () => ['Admin'],