mirror of
https://github.com/grafana/grafana.git
synced 2025-07-29 02:12:16 +08:00

* App Platform: Remove mutable globals * chore: clarify why this exists * fix: support multi-tenant mode * refactor: call builder providers directly * CI: Force re-build
87 lines
2.7 KiB
Go
87 lines
2.7 KiB
Go
package apiserver
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"net/http"
|
|
|
|
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
|
|
clientrest "k8s.io/client-go/rest"
|
|
)
|
|
|
|
type RestConfigProvider interface {
|
|
GetRestConfig(context.Context) (*clientrest.Config, error)
|
|
}
|
|
|
|
type RestConfigProviderFunc func(context.Context) (*clientrest.Config, error)
|
|
|
|
func (f RestConfigProviderFunc) GetRestConfig(ctx context.Context) (*clientrest.Config, error) {
|
|
return f(ctx)
|
|
}
|
|
|
|
// WithoutRestConfig is a RestConfigProvider that always returns an error.
|
|
// This is intended for use in unit tests where the rest config is not needed.
|
|
var WithoutRestConfig = RestConfigProviderFunc(func(context.Context) (*clientrest.Config, error) {
|
|
return nil, errors.New("rest config will not be available (unit test?)")
|
|
})
|
|
|
|
type DirectRestConfigProvider interface {
|
|
// GetDirectRestConfig returns a k8s client configuration that will use the same
|
|
// logged in user as the current request context. This is useful when
|
|
// creating clients that map legacy API handlers to k8s backed services
|
|
GetDirectRestConfig(c *contextmodel.ReqContext) *clientrest.Config
|
|
|
|
// This can be used to rewrite incoming requests to path now supported under /apis
|
|
DirectlyServeHTTP(w http.ResponseWriter, r *http.Request)
|
|
}
|
|
|
|
func ProvideEventualRestConfigProvider() *eventualRestConfigProvider {
|
|
return &eventualRestConfigProvider{
|
|
ready: make(chan struct{}),
|
|
}
|
|
}
|
|
|
|
var (
|
|
_ RestConfigProvider = (*eventualRestConfigProvider)(nil)
|
|
_ DirectRestConfigProvider = (*eventualRestConfigProvider)(nil)
|
|
)
|
|
|
|
// eventualRestConfigProvider is a RestConfigProvider that will not return a rest config until the ready channel is closed.
|
|
// This exists to alleviate a circular dependency between the apiserver.server's dependencies and their dependencies wanting a rest config.
|
|
// Importantly, this is handled by wire as opposed to a mutable global.
|
|
type eventualRestConfigProvider struct {
|
|
// When this channel is closed, we can start returning the rest config.
|
|
ready chan struct{}
|
|
cfg interface {
|
|
RestConfigProvider
|
|
DirectRestConfigProvider
|
|
}
|
|
}
|
|
|
|
func (e *eventualRestConfigProvider) GetRestConfig(ctx context.Context) (*clientrest.Config, error) {
|
|
select {
|
|
case <-e.ready:
|
|
return e.cfg.GetRestConfig(ctx)
|
|
case <-ctx.Done():
|
|
return nil, ctx.Err()
|
|
}
|
|
}
|
|
|
|
func (e *eventualRestConfigProvider) GetDirectRestConfig(c *contextmodel.ReqContext) *clientrest.Config {
|
|
select {
|
|
case <-e.ready:
|
|
return e.cfg.GetDirectRestConfig(c)
|
|
case <-c.Req.Context().Done():
|
|
return nil
|
|
}
|
|
}
|
|
|
|
func (e *eventualRestConfigProvider) DirectlyServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
select {
|
|
case <-e.ready:
|
|
e.cfg.DirectlyServeHTTP(w, r)
|
|
case <-r.Context().Done():
|
|
// Do nothing: the request has been cancelled.
|
|
}
|
|
}
|