mirror of
https://github.com/grafana/grafana.git
synced 2024-11-30 20:54:22 -06:00
173 lines
6.1 KiB
Go
173 lines
6.1 KiB
Go
package azuremonitor
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
|
|
"github.com/Masterminds/semver"
|
|
"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/resource/httpadapter"
|
|
"github.com/grafana/grafana/pkg/components/simplejson"
|
|
"github.com/grafana/grafana/pkg/infra/tracing"
|
|
"github.com/grafana/grafana/pkg/setting"
|
|
"github.com/grafana/grafana/pkg/tsdb/azuremonitor/deprecated"
|
|
"github.com/grafana/grafana/pkg/tsdb/azuremonitor/loganalytics"
|
|
"github.com/grafana/grafana/pkg/tsdb/azuremonitor/metrics"
|
|
"github.com/grafana/grafana/pkg/tsdb/azuremonitor/resourcegraph"
|
|
"github.com/grafana/grafana/pkg/tsdb/azuremonitor/types"
|
|
)
|
|
|
|
func ProvideService(cfg *setting.Cfg, httpClientProvider *httpclient.Provider, tracer tracing.Tracer) *Service {
|
|
proxy := &httpServiceProxy{}
|
|
executors := map[string]azDatasourceExecutor{
|
|
azureMonitor: &metrics.AzureMonitorDatasource{Proxy: proxy},
|
|
azureLogAnalytics: &loganalytics.AzureLogAnalyticsDatasource{Proxy: proxy},
|
|
azureResourceGraph: &resourcegraph.AzureResourceGraphDatasource{Proxy: proxy},
|
|
}
|
|
|
|
// Insights Analytics and Application Insights were deprecated in Grafana 8.x and
|
|
// will be finally removed with Grafana 9
|
|
if setting.BuildVersion != "" && semver.MustParse(setting.BuildVersion).Compare(semver.MustParse("9.0.0-beta1")) < 0 {
|
|
executors[deprecated.InsightsAnalytics] = &deprecated.InsightsAnalyticsDatasource{Proxy: proxy}
|
|
executors[deprecated.AppInsights] = &deprecated.ApplicationInsightsDatasource{Proxy: proxy}
|
|
}
|
|
|
|
im := datasource.NewInstanceManager(NewInstanceSettings(cfg, *httpClientProvider, executors))
|
|
|
|
s := &Service{
|
|
im: im,
|
|
executors: executors,
|
|
tracer: tracer,
|
|
}
|
|
|
|
s.queryMux = s.newQueryMux()
|
|
s.resourceHandler = httpadapter.New(s.newResourceMux())
|
|
|
|
return s
|
|
}
|
|
|
|
func (s *Service) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
|
|
return s.queryMux.QueryData(ctx, req)
|
|
}
|
|
|
|
func (s *Service) CallResource(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error {
|
|
return s.resourceHandler.CallResource(ctx, req, sender)
|
|
}
|
|
|
|
type Service struct {
|
|
im instancemgmt.InstanceManager
|
|
executors map[string]azDatasourceExecutor
|
|
|
|
queryMux *datasource.QueryTypeMux
|
|
resourceHandler backend.CallResourceHandler
|
|
tracer tracing.Tracer
|
|
}
|
|
|
|
func getDatasourceService(cfg *setting.Cfg, clientProvider httpclient.Provider, dsInfo types.DatasourceInfo, routeName string) (types.DatasourceService, error) {
|
|
route := dsInfo.Routes[routeName]
|
|
client, err := newHTTPClient(route, dsInfo, cfg, clientProvider)
|
|
if err != nil {
|
|
return types.DatasourceService{}, err
|
|
}
|
|
return types.DatasourceService{
|
|
URL: dsInfo.Routes[routeName].URL,
|
|
HTTPClient: client,
|
|
}, nil
|
|
}
|
|
|
|
func NewInstanceSettings(cfg *setting.Cfg, clientProvider httpclient.Provider, executors map[string]azDatasourceExecutor) datasource.InstanceFactoryFunc {
|
|
return func(settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
|
jsonData, err := simplejson.NewJson(settings.JSONData)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error reading settings: %w", err)
|
|
}
|
|
|
|
jsonDataObj := map[string]interface{}{}
|
|
err = json.Unmarshal(settings.JSONData, &jsonDataObj)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error reading settings: %w", err)
|
|
}
|
|
|
|
azMonitorSettings := types.AzureMonitorSettings{}
|
|
err = json.Unmarshal(settings.JSONData, &azMonitorSettings)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error reading settings: %w", err)
|
|
}
|
|
|
|
cloud, err := getAzureCloud(cfg, jsonData)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error getting credentials: %w", err)
|
|
}
|
|
|
|
credentials, err := getAzureCredentials(cfg, jsonData, settings.DecryptedSecureJSONData)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error getting credentials: %w", err)
|
|
}
|
|
|
|
model := types.DatasourceInfo{
|
|
Cloud: cloud,
|
|
Credentials: credentials,
|
|
Settings: azMonitorSettings,
|
|
JSONData: jsonDataObj,
|
|
DecryptedSecureJSONData: settings.DecryptedSecureJSONData,
|
|
DatasourceID: settings.ID,
|
|
Routes: routes[cloud],
|
|
Services: map[string]types.DatasourceService{},
|
|
}
|
|
|
|
for routeName := range executors {
|
|
service, err := getDatasourceService(cfg, clientProvider, model, routeName)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
model.Services[routeName] = service
|
|
}
|
|
|
|
return model, nil
|
|
}
|
|
}
|
|
|
|
type azDatasourceExecutor interface {
|
|
ExecuteTimeSeriesQuery(ctx context.Context, originalQueries []backend.DataQuery, dsInfo types.DatasourceInfo, client *http.Client, url string, tracer tracing.Tracer) (*backend.QueryDataResponse, error)
|
|
ResourceRequest(rw http.ResponseWriter, req *http.Request, cli *http.Client)
|
|
}
|
|
|
|
func (s *Service) getDataSourceFromPluginReq(req *backend.QueryDataRequest) (types.DatasourceInfo, error) {
|
|
i, err := s.im.Get(req.PluginContext)
|
|
if err != nil {
|
|
return types.DatasourceInfo{}, err
|
|
}
|
|
dsInfo, ok := i.(types.DatasourceInfo)
|
|
if !ok {
|
|
return types.DatasourceInfo{}, fmt.Errorf("unable to convert datasource from service instance")
|
|
}
|
|
dsInfo.OrgID = req.PluginContext.OrgID
|
|
return dsInfo, nil
|
|
}
|
|
|
|
func (s *Service) newQueryMux() *datasource.QueryTypeMux {
|
|
mux := datasource.NewQueryTypeMux()
|
|
for dsType := range s.executors {
|
|
// Make a copy of the string to keep the reference after the iterator
|
|
dst := dsType
|
|
mux.HandleFunc(dsType, func(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
|
|
executor := s.executors[dst]
|
|
dsInfo, err := s.getDataSourceFromPluginReq(req)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
service, ok := dsInfo.Services[dst]
|
|
if !ok {
|
|
return nil, fmt.Errorf("missing service for %s", dst)
|
|
}
|
|
return executor.ExecuteTimeSeriesQuery(ctx, req.Queries, dsInfo, service.HTTPClient, service.URL, s.tracer)
|
|
})
|
|
}
|
|
return mux
|
|
}
|