grafana/pkg/registry/apis/datasource/sub_resource.go
2024-04-02 20:09:18 +02:00

101 lines
2.3 KiB
Go

package datasource
import (
"context"
"fmt"
"io"
"net/http"
"net/url"
"strings"
"github.com/grafana/grafana-plugin-sdk-go/backend"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apiserver/pkg/registry/rest"
"github.com/grafana/grafana/pkg/plugins/httpresponsesender"
)
type subResourceREST struct {
builder *DataSourceAPIBuilder
}
var _ = rest.Connecter(&subResourceREST{})
func (r *subResourceREST) New() runtime.Object {
return &metav1.Status{}
}
func (r *subResourceREST) Destroy() {
}
func (r *subResourceREST) ConnectMethods() []string {
// All for now??? ideally we have a schema for resource and limit this
return []string{
http.MethodGet,
http.MethodHead,
http.MethodPost,
http.MethodPut,
http.MethodPatch,
http.MethodDelete,
http.MethodOptions,
}
}
func (r *subResourceREST) NewConnectOptions() (runtime.Object, bool, string) {
return nil, true, ""
}
func (r *subResourceREST) Connect(ctx context.Context, name string, opts runtime.Object, responder rest.Responder) (http.Handler, error) {
pluginCtx, err := r.builder.getPluginContext(ctx, name)
if err != nil {
return nil, err
}
ctx = backend.WithGrafanaConfig(ctx, pluginCtx.GrafanaConfig)
ctx = contextualMiddlewares(ctx)
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
clonedReq, err := resourceRequest(req)
if err != nil {
responder.Error(err)
return
}
body, err := io.ReadAll(req.Body)
if err != nil {
responder.Error(err)
return
}
err = r.builder.client.CallResource(ctx, &backend.CallResourceRequest{
PluginContext: pluginCtx,
Path: clonedReq.URL.Path,
Method: req.Method,
URL: clonedReq.URL.String(),
Body: body,
Headers: req.Header,
}, httpresponsesender.New(w))
if err != nil {
responder.Error(err)
}
}), nil
}
func resourceRequest(req *http.Request) (*http.Request, error) {
idx := strings.LastIndex(req.URL.Path, "/resource")
if idx < 0 {
return nil, fmt.Errorf("expected resource path") // 400?
}
clonedReq := req.Clone(req.Context())
rawURL := strings.TrimLeft(req.URL.Path[idx+len("/resource"):], "/")
clonedReq.URL = &url.URL{
Path: rawURL,
RawQuery: clonedReq.URL.RawQuery,
}
return clonedReq, nil
}