mirror of https://github.com/grafana/grafana
App Platform: Remove mutable globals (#102962)
* App Platform: Remove mutable globals * chore: clarify why this exists * fix: support multi-tenant mode * refactor: call builder providers directly * CI: Force re-buildfolder-tracing
parent
031a047565
commit
d0d7078953
@ -0,0 +1,32 @@ |
||||
package builder |
||||
|
||||
import ( |
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" |
||||
"k8s.io/apimachinery/pkg/runtime" |
||||
"k8s.io/apimachinery/pkg/runtime/schema" |
||||
"k8s.io/apimachinery/pkg/runtime/serializer" |
||||
) |
||||
|
||||
func ProvideScheme() *runtime.Scheme { |
||||
unversionedVersion := schema.GroupVersion{Group: "", Version: "v1"} |
||||
unversionedTypes := []runtime.Object{ |
||||
&metav1.Status{}, |
||||
&metav1.WatchEvent{}, |
||||
&metav1.APIVersions{}, |
||||
&metav1.APIGroupList{}, |
||||
&metav1.APIGroup{}, |
||||
&metav1.APIResourceList{}, |
||||
&metav1.PartialObjectMetadata{}, |
||||
&metav1.PartialObjectMetadataList{}, |
||||
} |
||||
|
||||
scheme := runtime.NewScheme() |
||||
// we need to add the options to empty v1
|
||||
metav1.AddToGroupVersion(scheme, schema.GroupVersion{Group: "", Version: "v1"}) |
||||
scheme.AddUnversionedTypes(unversionedVersion, unversionedTypes...) |
||||
return scheme |
||||
} |
||||
|
||||
func ProvideCodecFactory(scheme *runtime.Scheme) serializer.CodecFactory { |
||||
return serializer.NewCodecFactory(scheme) |
||||
} |
||||
@ -0,0 +1,86 @@ |
||||
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.
|
||||
} |
||||
} |
||||
Loading…
Reference in new issue