137 lines
3.4 KiB
Go
137 lines
3.4 KiB
Go
package graphite
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
"net/url"
|
|
"path"
|
|
|
|
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
|
"github.com/grafana/grafana-plugin-sdk-go/backend/datasource"
|
|
"github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
|
|
"github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt"
|
|
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
|
|
"github.com/grafana/grafana-plugin-sdk-go/backend/resource/httpadapter"
|
|
"go.opentelemetry.io/otel/trace"
|
|
)
|
|
|
|
type Service struct {
|
|
im instancemgmt.InstanceManager
|
|
tracer trace.Tracer
|
|
logger log.Logger
|
|
resourceHandler backend.CallResourceHandler
|
|
HTTPClient *http.Client
|
|
}
|
|
|
|
const (
|
|
TargetFullModelField = "targetFull"
|
|
TargetModelField = "target"
|
|
)
|
|
|
|
func ProvideService(httpClientProvider *httpclient.Provider, tracer trace.Tracer) *Service {
|
|
logger := backend.NewLoggerWith("logger", "graphite")
|
|
s := &Service{
|
|
im: datasource.NewInstanceManager(newInstanceSettings(httpClientProvider)),
|
|
tracer: tracer,
|
|
logger: logger,
|
|
}
|
|
|
|
s.resourceHandler = httpadapter.New(s.newResourceMux())
|
|
|
|
return s
|
|
}
|
|
|
|
type datasourceInfo struct {
|
|
HTTPClient *http.Client
|
|
URL string
|
|
Id int64
|
|
}
|
|
|
|
func newInstanceSettings(httpClientProvider *httpclient.Provider) datasource.InstanceFactoryFunc {
|
|
return func(ctx context.Context, settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
|
opts, err := settings.HTTPClientOptions(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
client, err := httpClientProvider.New(opts)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
model := datasourceInfo{
|
|
HTTPClient: client,
|
|
URL: settings.URL,
|
|
Id: settings.ID,
|
|
}
|
|
|
|
return model, nil
|
|
}
|
|
}
|
|
|
|
func (s *Service) getDSInfo(ctx context.Context, pluginCtx backend.PluginContext) (*datasourceInfo, error) {
|
|
i, err := s.im.Get(ctx, pluginCtx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
instance := i.(datasourceInfo)
|
|
return &instance, nil
|
|
}
|
|
|
|
func (s *Service) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
|
|
if len(req.Queries) == 0 {
|
|
return nil, fmt.Errorf("query contains no queries")
|
|
}
|
|
|
|
// get datasource info from context
|
|
dsInfo, err := s.getDSInfo(ctx, req.PluginContext)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return s.RunQuery(ctx, req, dsInfo)
|
|
}
|
|
|
|
func (s *Service) CallResource(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error {
|
|
return s.resourceHandler.CallResource(ctx, req, sender)
|
|
}
|
|
|
|
func (s *Service) createRequest(ctx context.Context, dsInfo *datasourceInfo, params URLParams) (*http.Request, error) {
|
|
u, err := url.Parse(dsInfo.URL)
|
|
if err != nil {
|
|
return nil, backend.DownstreamError(err)
|
|
}
|
|
|
|
if params.SubPath != "" {
|
|
u.Path = path.Join(u.Path, params.SubPath)
|
|
}
|
|
|
|
if params.QueryParams != nil {
|
|
queryValues := u.Query()
|
|
for key, values := range params.QueryParams {
|
|
for _, value := range values {
|
|
queryValues.Add(key, value)
|
|
}
|
|
}
|
|
u.RawQuery = queryValues.Encode()
|
|
}
|
|
|
|
method := params.Method
|
|
if method == "" {
|
|
method = http.MethodGet
|
|
}
|
|
|
|
req, err := http.NewRequestWithContext(ctx, method, u.String(), params.Body)
|
|
if err != nil {
|
|
s.logger.Info("Failed to create request", "error", err)
|
|
return nil, backend.PluginError(fmt.Errorf("failed to create request: %w", err))
|
|
}
|
|
|
|
for k, v := range params.Headers {
|
|
req.Header.Add(k, v)
|
|
}
|
|
|
|
return req, err
|
|
}
|