mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
AzureMonitor: Use plugin SDK contracts (#34729)
This commit is contained in:
committed by
GitHub
parent
e8bc48a796
commit
d225323049
@@ -2,19 +2,27 @@ package azuremonitor
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"regexp"
|
||||
|
||||
"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/instancemgmt"
|
||||
"github.com/grafana/grafana/pkg/infra/httpclient"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/plugins/backendplugin"
|
||||
"github.com/grafana/grafana/pkg/plugins/backendplugin/coreplugin"
|
||||
"github.com/grafana/grafana/pkg/registry"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
const timeSeries = "time_series"
|
||||
const (
|
||||
timeSeries = "time_series"
|
||||
dsName = "grafana-azure-monitor-datasource"
|
||||
)
|
||||
|
||||
var (
|
||||
azlog = log.New("tsdb.azuremonitor")
|
||||
@@ -30,147 +38,111 @@ func init() {
|
||||
}
|
||||
|
||||
type Service struct {
|
||||
PluginManager plugins.Manager `inject:""`
|
||||
HTTPClientProvider httpclient.Provider `inject:""`
|
||||
Cfg *setting.Cfg `inject:""`
|
||||
PluginManager plugins.Manager `inject:""`
|
||||
HTTPClientProvider httpclient.Provider `inject:""`
|
||||
Cfg *setting.Cfg `inject:""`
|
||||
BackendPluginManager backendplugin.Manager `inject:""`
|
||||
}
|
||||
|
||||
type azureMonitorSettings struct {
|
||||
AppInsightsAppId string `json:"appInsightsAppId"`
|
||||
AzureLogAnalyticsSameAs bool `json:"azureLogAnalyticsSameAs"`
|
||||
ClientId string `json:"clientId"`
|
||||
CloudName string `json:"cloudName"`
|
||||
LogAnalyticsClientId string `json:"logAnalyticsClientId"`
|
||||
LogAnalyticsDefaultWorkspace string `json:"logAnalyticsDefaultWorkspace"`
|
||||
LogAnalyticsSubscriptionId string `json:"logAnalyticsSubscriptionId"`
|
||||
LogAnalyticsTenantId string `json:"logAnalyticsTenantId"`
|
||||
SubscriptionId string `json:"subscriptionId"`
|
||||
TenantId string `json:"tenantId"`
|
||||
AzureAuthType string `json:"azureAuthType,omitempty"`
|
||||
}
|
||||
|
||||
type datasourceInfo struct {
|
||||
Settings azureMonitorSettings
|
||||
|
||||
HTTPClient *http.Client
|
||||
URL string
|
||||
JSONData map[string]interface{}
|
||||
DecryptedSecureJSONData map[string]string
|
||||
DatasourceID int64
|
||||
OrgID int64
|
||||
}
|
||||
|
||||
func NewInstanceSettings(httpClientProvider httpclient.Provider) datasource.InstanceFactoryFunc {
|
||||
return func(settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
opts, err := settings.HTTPClientOptions()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
client, err := httpClientProvider.New(opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
jsonData := map[string]interface{}{}
|
||||
err = json.Unmarshal(settings.JSONData, &jsonData)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading settings: %w", err)
|
||||
}
|
||||
|
||||
azMonitorSettings := azureMonitorSettings{}
|
||||
err = json.Unmarshal(settings.JSONData, &azMonitorSettings)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error reading settings: %w", err)
|
||||
}
|
||||
model := datasourceInfo{
|
||||
Settings: azMonitorSettings,
|
||||
HTTPClient: client,
|
||||
URL: settings.URL,
|
||||
JSONData: jsonData,
|
||||
DecryptedSecureJSONData: settings.DecryptedSecureJSONData,
|
||||
DatasourceID: settings.ID,
|
||||
}
|
||||
|
||||
return model, nil
|
||||
}
|
||||
}
|
||||
|
||||
type azDatasourceExecutor interface {
|
||||
executeTimeSeriesQuery(ctx context.Context, originalQueries []backend.DataQuery, dsInfo datasourceInfo) (*backend.QueryDataResponse, error)
|
||||
}
|
||||
|
||||
func newExecutor(im instancemgmt.InstanceManager, pm plugins.Manager, httpC httpclient.Provider, cfg *setting.Cfg) *datasource.QueryTypeMux {
|
||||
mux := datasource.NewQueryTypeMux()
|
||||
executors := map[string]azDatasourceExecutor{
|
||||
"Azure Monitor": &AzureMonitorDatasource{pm, cfg},
|
||||
"Application Insights": &ApplicationInsightsDatasource{pm, cfg},
|
||||
"Azure Log Analytics": &AzureLogAnalyticsDatasource{pm, cfg},
|
||||
"Insights Analytics": &InsightsAnalyticsDatasource{pm, cfg},
|
||||
"Azure Resource Graph": &AzureResourceGraphDatasource{pm, cfg},
|
||||
}
|
||||
for dsType := range 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) {
|
||||
i, err := im.Get(req.PluginContext)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dsInfo := i.(datasourceInfo)
|
||||
dsInfo.OrgID = req.PluginContext.OrgID
|
||||
ds := executors[dst]
|
||||
return ds.executeTimeSeriesQuery(ctx, req.Queries, dsInfo)
|
||||
})
|
||||
}
|
||||
return mux
|
||||
}
|
||||
|
||||
func (s *Service) Init() error {
|
||||
im := datasource.NewInstanceManager(NewInstanceSettings(s.HTTPClientProvider))
|
||||
factory := coreplugin.New(backend.ServeOpts{
|
||||
QueryDataHandler: newExecutor(im, s.PluginManager, s.HTTPClientProvider, s.Cfg),
|
||||
})
|
||||
|
||||
if err := s.BackendPluginManager.Register(dsName, factory); err != nil {
|
||||
azlog.Error("Failed to register plugin", "error", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AzureMonitorExecutor executes queries for the Azure Monitor datasource - all four services
|
||||
type AzureMonitorExecutor struct {
|
||||
httpClient *http.Client
|
||||
dsInfo *models.DataSource
|
||||
pluginManager plugins.Manager
|
||||
cfg *setting.Cfg
|
||||
}
|
||||
|
||||
// NewAzureMonitorExecutor initializes a http client
|
||||
//nolint: staticcheck // plugins.DataPlugin deprecated
|
||||
func (s *Service) NewExecutor(dsInfo *models.DataSource) (plugins.DataPlugin, error) {
|
||||
httpClient, err := dsInfo.GetHTTPClient(s.HTTPClientProvider)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &AzureMonitorExecutor{
|
||||
httpClient: httpClient,
|
||||
dsInfo: dsInfo,
|
||||
pluginManager: s.PluginManager,
|
||||
cfg: s.Cfg,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Query takes in the frontend queries, parses them into the query format
|
||||
// expected by chosen Azure Monitor service (Azure Monitor, App Insights etc.)
|
||||
// executes the queries against the API and parses the response into
|
||||
// the right format
|
||||
//nolint: staticcheck // plugins.DataPlugin deprecated
|
||||
func (e *AzureMonitorExecutor) DataQuery(ctx context.Context, dsInfo *models.DataSource,
|
||||
tsdbQuery plugins.DataQuery) (plugins.DataResponse, error) {
|
||||
var err error
|
||||
|
||||
var azureMonitorQueries []plugins.DataSubQuery
|
||||
var applicationInsightsQueries []plugins.DataSubQuery
|
||||
var azureLogAnalyticsQueries []plugins.DataSubQuery
|
||||
var insightsAnalyticsQueries []plugins.DataSubQuery
|
||||
var azureResourceGraphQueries []plugins.DataSubQuery
|
||||
|
||||
for _, query := range tsdbQuery.Queries {
|
||||
queryType := query.Model.Get("queryType").MustString("")
|
||||
|
||||
switch queryType {
|
||||
case "Azure Monitor":
|
||||
azureMonitorQueries = append(azureMonitorQueries, query)
|
||||
case "Application Insights":
|
||||
applicationInsightsQueries = append(applicationInsightsQueries, query)
|
||||
case "Azure Log Analytics":
|
||||
azureLogAnalyticsQueries = append(azureLogAnalyticsQueries, query)
|
||||
case "Insights Analytics":
|
||||
insightsAnalyticsQueries = append(insightsAnalyticsQueries, query)
|
||||
case "Azure Resource Graph":
|
||||
azureResourceGraphQueries = append(azureResourceGraphQueries, query)
|
||||
default:
|
||||
return plugins.DataResponse{}, fmt.Errorf("alerting not supported for %q", queryType)
|
||||
}
|
||||
}
|
||||
|
||||
azDatasource := &AzureMonitorDatasource{
|
||||
httpClient: e.httpClient,
|
||||
dsInfo: e.dsInfo,
|
||||
pluginManager: e.pluginManager,
|
||||
cfg: e.cfg,
|
||||
}
|
||||
|
||||
aiDatasource := &ApplicationInsightsDatasource{
|
||||
httpClient: e.httpClient,
|
||||
dsInfo: e.dsInfo,
|
||||
pluginManager: e.pluginManager,
|
||||
cfg: e.cfg,
|
||||
}
|
||||
|
||||
alaDatasource := &AzureLogAnalyticsDatasource{
|
||||
httpClient: e.httpClient,
|
||||
dsInfo: e.dsInfo,
|
||||
pluginManager: e.pluginManager,
|
||||
cfg: e.cfg,
|
||||
}
|
||||
|
||||
iaDatasource := &InsightsAnalyticsDatasource{
|
||||
httpClient: e.httpClient,
|
||||
dsInfo: e.dsInfo,
|
||||
pluginManager: e.pluginManager,
|
||||
cfg: e.cfg,
|
||||
}
|
||||
|
||||
argDatasource := &AzureResourceGraphDatasource{
|
||||
httpClient: e.httpClient,
|
||||
dsInfo: e.dsInfo,
|
||||
pluginManager: e.pluginManager,
|
||||
}
|
||||
|
||||
azResult, err := azDatasource.executeTimeSeriesQuery(ctx, azureMonitorQueries, *tsdbQuery.TimeRange)
|
||||
if err != nil {
|
||||
return plugins.DataResponse{}, err
|
||||
}
|
||||
|
||||
aiResult, err := aiDatasource.executeTimeSeriesQuery(ctx, applicationInsightsQueries, *tsdbQuery.TimeRange)
|
||||
if err != nil {
|
||||
return plugins.DataResponse{}, err
|
||||
}
|
||||
|
||||
alaResult, err := alaDatasource.executeTimeSeriesQuery(ctx, azureLogAnalyticsQueries, *tsdbQuery.TimeRange)
|
||||
if err != nil {
|
||||
return plugins.DataResponse{}, err
|
||||
}
|
||||
|
||||
iaResult, err := iaDatasource.executeTimeSeriesQuery(ctx, insightsAnalyticsQueries, *tsdbQuery.TimeRange)
|
||||
if err != nil {
|
||||
return plugins.DataResponse{}, err
|
||||
}
|
||||
|
||||
argResult, err := argDatasource.executeTimeSeriesQuery(ctx, azureResourceGraphQueries, *tsdbQuery.TimeRange)
|
||||
if err != nil {
|
||||
return plugins.DataResponse{}, err
|
||||
}
|
||||
|
||||
for k, v := range aiResult.Results {
|
||||
azResult.Results[k] = v
|
||||
}
|
||||
|
||||
for k, v := range alaResult.Results {
|
||||
azResult.Results[k] = v
|
||||
}
|
||||
|
||||
for k, v := range iaResult.Results {
|
||||
azResult.Results[k] = v
|
||||
}
|
||||
|
||||
for k, v := range argResult.Responses {
|
||||
azResult.Results[k] = plugins.DataQueryResult{Error: v.Error, Dataframes: plugins.NewDecodedDataFrames(v.Frames)}
|
||||
}
|
||||
|
||||
return azResult, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user