mirror of
https://github.com/grafana/grafana.git
synced 2024-11-21 08:34:25 -06:00
Plugins: Externalise Azure Monitor data source (#79545)
* Set up frontend linting for Azure - Fix final frontend import - Fix other lint issues * Add Azure Monitor to backend linting * Remove featuremgmt dependency * Add intervalv2 to list of disallowed imports * Remove config dependency - Replace with function from azure-sdk * Remove util dependency * Duplicate interval functionality from core * Add required backend wrappers * Update frontend * Add testing helper * Add missing package * Bump minimum grafana dependency * Fix dependency * Regen cue * Fix lint * Update expected response file * Update import and dependency
This commit is contained in:
parent
d680a020cc
commit
dd77ff6bcd
@ -98,6 +98,8 @@
|
||||
"files": [
|
||||
"public/app/plugins/datasource/grafana-testdata-datasource/*.{ts,tsx}",
|
||||
"public/app/plugins/datasource/grafana-testdata-datasource/**/*.{ts,tsx}",
|
||||
"public/app/plugins/datasource/azuremonitor/*.{ts,tsx}",
|
||||
"public/app/plugins/datasource/azuremonitor/**/*.{ts,tsx}",
|
||||
"public/app/plugins/datasource/parca/*.{ts,tsx}",
|
||||
"public/app/plugins/datasource/parca/**/*.{ts,tsx}"
|
||||
],
|
||||
|
@ -52,10 +52,13 @@ deny = [
|
||||
{ pkg = "github.com/grafana/grafana/pkg/server", desc = "Core plugins are not allowed to depend on Grafana core packages" },
|
||||
{ pkg = "github.com/grafana/grafana/pkg/tests", desc = "Core plugins are not allowed to depend on Grafana core packages" },
|
||||
{ pkg = "github.com/grafana/grafana/pkg/web", desc = "Core plugins are not allowed to depend on Grafana core packages" },
|
||||
{ pkg = "github.com/grafana/grafana/pkg/tsdb/intervalv2", desc = "Core plugins are not allowed to depend on Grafana core packages" },
|
||||
]
|
||||
files = [
|
||||
"**/pkg/tsdb/grafana-testdata-datasource/*",
|
||||
"**/pkg/tsdb/grafana-testdata-datasource/**/*",
|
||||
"**/pkg/tsdb/azuremonitor/*",
|
||||
"**/pkg/tsdb/azuremonitor/**/*",
|
||||
"**/pkg/tsdb/parca/*",
|
||||
"**/pkg/tsdb/parca/**/*",
|
||||
]
|
||||
|
@ -243,6 +243,7 @@
|
||||
"@fingerprintjs/fingerprintjs": "^3.4.2",
|
||||
"@floating-ui/react": "0.26.4",
|
||||
"@glideapps/glide-data-grid": "^5.2.1",
|
||||
"@grafana-plugins/grafana-azure-monitor-datasource": "workspace:*",
|
||||
"@grafana-plugins/grafana-testdata-datasource": "workspace:*",
|
||||
"@grafana-plugins/parca": "workspace:*",
|
||||
"@grafana/aws-sdk": "0.3.1",
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
import * as common from '@grafana/schema';
|
||||
|
||||
export const pluginVersion = "1.0.0";
|
||||
export const pluginVersion = "%VERSION%";
|
||||
|
||||
export interface AzureMonitorQuery extends common.DataQuery {
|
||||
/**
|
||||
|
@ -80,7 +80,7 @@ func TestIntegrationPluginManager(t *testing.T) {
|
||||
tracer := tracing.InitializeTracerForTest()
|
||||
|
||||
hcp := httpclient.NewProvider()
|
||||
am := azuremonitor.ProvideService(cfg, hcp, features)
|
||||
am := azuremonitor.ProvideService(hcp)
|
||||
cw := cloudwatch.ProvideService(cfg, hcp, features)
|
||||
cm := cloudmonitoring.ProvideService(hcp, tracer)
|
||||
es := elasticsearch.ProvideService(hcp, tracer)
|
||||
|
@ -156,12 +156,12 @@
|
||||
"path": "/public/app/plugins/datasource/azuremonitor/img/azure_monitor_cpu.png"
|
||||
}
|
||||
],
|
||||
"version": "1.0.0",
|
||||
"version": "",
|
||||
"updated": ""
|
||||
},
|
||||
"dependencies": {
|
||||
"grafanaDependency": "",
|
||||
"grafanaVersion": "5.2.x",
|
||||
"grafanaDependency": ">=10.3.0",
|
||||
"grafanaVersion": "*",
|
||||
"plugins": []
|
||||
},
|
||||
"latestVersion": "",
|
||||
|
@ -18,8 +18,6 @@ import (
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend/resource/httpadapter"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/tsdb/azuremonitor/azmoncredentials"
|
||||
"github.com/grafana/grafana/pkg/tsdb/azuremonitor/loganalytics"
|
||||
"github.com/grafana/grafana/pkg/tsdb/azuremonitor/metrics"
|
||||
@ -27,16 +25,16 @@ import (
|
||||
"github.com/grafana/grafana/pkg/tsdb/azuremonitor/types"
|
||||
)
|
||||
|
||||
func ProvideService(cfg *setting.Cfg, httpClientProvider *httpclient.Provider, features featuremgmt.FeatureToggles) *Service {
|
||||
func ProvideService(httpClientProvider *httpclient.Provider) *Service {
|
||||
proxy := &httpServiceProxy{}
|
||||
executors := map[string]azDatasourceExecutor{
|
||||
azureMonitor: &metrics.AzureMonitorDatasource{Proxy: proxy, Features: features},
|
||||
azureMonitor: &metrics.AzureMonitorDatasource{Proxy: proxy},
|
||||
azureLogAnalytics: &loganalytics.AzureLogAnalyticsDatasource{Proxy: proxy},
|
||||
azureResourceGraph: &resourcegraph.AzureResourceGraphDatasource{Proxy: proxy},
|
||||
azureTraces: &loganalytics.AzureLogAnalyticsDatasource{Proxy: proxy},
|
||||
}
|
||||
|
||||
im := datasource.NewInstanceManager(NewInstanceSettings(cfg, httpClientProvider, executors))
|
||||
im := datasource.NewInstanceManager(NewInstanceSettings(httpClientProvider, executors))
|
||||
|
||||
s := &Service{
|
||||
im: im,
|
||||
@ -65,9 +63,9 @@ type Service struct {
|
||||
resourceHandler backend.CallResourceHandler
|
||||
}
|
||||
|
||||
func getDatasourceService(ctx context.Context, settings *backend.DataSourceInstanceSettings, cfg *setting.Cfg, clientProvider *httpclient.Provider, dsInfo types.DatasourceInfo, routeName string) (types.DatasourceService, error) {
|
||||
func getDatasourceService(ctx context.Context, settings *backend.DataSourceInstanceSettings, azureSettings *azsettings.AzureSettings, clientProvider *httpclient.Provider, dsInfo types.DatasourceInfo, routeName string) (types.DatasourceService, error) {
|
||||
route := dsInfo.Routes[routeName]
|
||||
client, err := newHTTPClient(ctx, route, dsInfo, settings, cfg, clientProvider)
|
||||
client, err := newHTTPClient(ctx, route, dsInfo, settings, azureSettings, clientProvider)
|
||||
if err != nil {
|
||||
return types.DatasourceService{}, err
|
||||
}
|
||||
@ -77,7 +75,7 @@ func getDatasourceService(ctx context.Context, settings *backend.DataSourceInsta
|
||||
}, nil
|
||||
}
|
||||
|
||||
func NewInstanceSettings(cfg *setting.Cfg, clientProvider *httpclient.Provider, executors map[string]azDatasourceExecutor) datasource.InstanceFactoryFunc {
|
||||
func NewInstanceSettings(clientProvider *httpclient.Provider, executors map[string]azDatasourceExecutor) datasource.InstanceFactoryFunc {
|
||||
return func(ctx context.Context, settings backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
jsonData := map[string]any{}
|
||||
err := json.Unmarshal(settings.JSONData, &jsonData)
|
||||
@ -91,14 +89,20 @@ func NewInstanceSettings(cfg *setting.Cfg, clientProvider *httpclient.Provider,
|
||||
return nil, fmt.Errorf("error reading settings: %w", err)
|
||||
}
|
||||
|
||||
azureSettings, err := azsettings.ReadSettings(ctx)
|
||||
if err != nil {
|
||||
backend.Logger.Error("failed to read Azure settings from Grafana", "error", err.Error())
|
||||
return nil, err
|
||||
}
|
||||
|
||||
credentials, err := azmoncredentials.FromDatasourceData(jsonData, settings.DecryptedSecureJSONData)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting credentials: %w", err)
|
||||
} else if credentials == nil {
|
||||
credentials = azmoncredentials.GetDefaultCredentials(cfg.Azure)
|
||||
credentials = azmoncredentials.GetDefaultCredentials(azureSettings)
|
||||
}
|
||||
|
||||
cloud, err := azcredentials.GetAzureCloud(cfg.Azure, credentials)
|
||||
cloud, err := azcredentials.GetAzureCloud(azureSettings, credentials)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting credentials: %w", err)
|
||||
}
|
||||
@ -120,7 +124,7 @@ func NewInstanceSettings(cfg *setting.Cfg, clientProvider *httpclient.Provider,
|
||||
}
|
||||
|
||||
for routeName := range executors {
|
||||
service, err := getDatasourceService(ctx, &settings, cfg, clientProvider, model, routeName)
|
||||
service, err := getDatasourceService(ctx, &settings, azureSettings, clientProvider, model, routeName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -17,7 +17,6 @@ import (
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt"
|
||||
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/tsdb/azuremonitor/types"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@ -86,15 +85,9 @@ func TestNewInstanceSettings(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
cfg := &setting.Cfg{
|
||||
Azure: &azsettings.AzureSettings{
|
||||
Cloud: azsettings.AzurePublic,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
factory := NewInstanceSettings(cfg, &httpclient.Provider{}, map[string]azDatasourceExecutor{})
|
||||
factory := NewInstanceSettings(&httpclient.Provider{}, map[string]azDatasourceExecutor{})
|
||||
instance, err := factory(context.Background(), tt.settings)
|
||||
tt.Err(t, err)
|
||||
if !cmp.Equal(instance, tt.expectedModel) {
|
||||
|
@ -8,10 +8,10 @@ import (
|
||||
|
||||
"github.com/grafana/grafana-azure-sdk-go/azcredentials"
|
||||
"github.com/grafana/grafana-azure-sdk-go/azhttpclient"
|
||||
"github.com/grafana/grafana-azure-sdk-go/azsettings"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
|
||||
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/tsdb/azuremonitor/types"
|
||||
)
|
||||
|
||||
@ -21,7 +21,7 @@ type Provider interface {
|
||||
GetTLSConfig(...httpclient.Options) (*tls.Config, error)
|
||||
}
|
||||
|
||||
func newHTTPClient(ctx context.Context, route types.AzRoute, model types.DatasourceInfo, settings *backend.DataSourceInstanceSettings, cfg *setting.Cfg, clientProvider Provider) (*http.Client, error) {
|
||||
func newHTTPClient(ctx context.Context, route types.AzRoute, model types.DatasourceInfo, settings *backend.DataSourceInstanceSettings, azureSettings *azsettings.AzureSettings, clientProvider Provider) (*http.Client, error) {
|
||||
clientOpts, err := settings.HTTPClientOptions(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting HTTP options: %w", err)
|
||||
@ -37,7 +37,7 @@ func newHTTPClient(ctx context.Context, route types.AzRoute, model types.Datasou
|
||||
return nil, fmt.Errorf("unable to initialize HTTP Client: clientSecret not found")
|
||||
}
|
||||
|
||||
authOpts := azhttpclient.NewAuthOptions(cfg.Azure)
|
||||
authOpts := azhttpclient.NewAuthOptions(azureSettings)
|
||||
authOpts.Scopes(route.Scopes)
|
||||
azhttpclient.AddAzureAuthentication(&clientOpts, authOpts, model.Credentials)
|
||||
}
|
||||
|
@ -8,10 +8,10 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana-azure-sdk-go/azcredentials"
|
||||
"github.com/grafana/grafana-azure-sdk-go/azsettings"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
|
||||
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/tsdb/azuremonitor/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
@ -32,7 +32,9 @@ func TestHttpClient_AzureCredentials(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
cfg := &setting.Cfg{}
|
||||
azureSettings := &azsettings.AzureSettings{
|
||||
Cloud: azsettings.AzurePublic,
|
||||
}
|
||||
provider := &fakeHttpClientProvider{}
|
||||
|
||||
t.Run("should have Azure middleware when scopes provided", func(t *testing.T) {
|
||||
@ -40,7 +42,7 @@ func TestHttpClient_AzureCredentials(t *testing.T) {
|
||||
Scopes: []string{"https://management.azure.com/.default"},
|
||||
}
|
||||
|
||||
_, err := newHTTPClient(context.Background(), route, model, settings, cfg, provider)
|
||||
_, err := newHTTPClient(context.Background(), route, model, settings, azureSettings, provider)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NotNil(t, provider.opts)
|
||||
@ -53,7 +55,7 @@ func TestHttpClient_AzureCredentials(t *testing.T) {
|
||||
Scopes: []string{},
|
||||
}
|
||||
|
||||
_, err := newHTTPClient(context.Background(), route, model, settings, cfg, provider)
|
||||
_, err := newHTTPClient(context.Background(), route, model, settings, azureSettings, provider)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.NotNil(t, provider.opts)
|
||||
@ -74,7 +76,7 @@ func TestHttpClient_AzureCredentials(t *testing.T) {
|
||||
"GrafanaHeader": "GrafanaValue",
|
||||
"AzureHeader": "AzureValue",
|
||||
}
|
||||
_, err := newHTTPClient(context.Background(), route, model, settings, cfg, provider)
|
||||
_, err := newHTTPClient(context.Background(), route, model, settings, azureSettings, provider)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.NotNil(t, provider.opts)
|
||||
|
@ -10,8 +10,8 @@ import (
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
|
||||
"github.com/grafana/grafana/pkg/tsdb/azuremonitor/kinds/dataquery"
|
||||
azTime "github.com/grafana/grafana/pkg/tsdb/azuremonitor/time"
|
||||
"github.com/grafana/grafana/pkg/tsdb/azuremonitor/types"
|
||||
"github.com/grafana/grafana/pkg/tsdb/intervalv2"
|
||||
)
|
||||
|
||||
const rsIdentifier = `__(timeFilter|timeFrom|timeTo|interval|contains|escapeMulti)`
|
||||
@ -126,7 +126,7 @@ func (m *kqlMacroEngine) evaluateMacro(name string, defaultTimeField string, arg
|
||||
if dsInterval, ok = dsInfo.JSONData["interval"].(string); !ok {
|
||||
dsInterval = ""
|
||||
}
|
||||
it, err = intervalv2.GetIntervalFrom(dsInterval, queryInterval.Interval, queryInterval.IntervalMs, defaultInterval)
|
||||
it, err = azTime.GetIntervalFrom(dsInterval, queryInterval.Interval, queryInterval.IntervalMs, defaultInterval)
|
||||
if err != nil {
|
||||
it = defaultInterval
|
||||
}
|
||||
|
@ -19,7 +19,6 @@ import (
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/tsdb/azuremonitor/kinds/dataquery"
|
||||
"github.com/grafana/grafana/pkg/tsdb/azuremonitor/loganalytics"
|
||||
azTime "github.com/grafana/grafana/pkg/tsdb/azuremonitor/time"
|
||||
@ -28,8 +27,7 @@ import (
|
||||
|
||||
// AzureMonitorDatasource calls the Azure Monitor API - one of the four API's supported
|
||||
type AzureMonitorDatasource struct {
|
||||
Proxy types.ServiceProxy
|
||||
Features featuremgmt.FeatureToggles
|
||||
Proxy types.ServiceProxy
|
||||
}
|
||||
|
||||
var (
|
||||
|
@ -23,9 +23,10 @@ import (
|
||||
"github.com/grafana/grafana/pkg/tsdb/azuremonitor/testdata"
|
||||
azTime "github.com/grafana/grafana/pkg/tsdb/azuremonitor/time"
|
||||
"github.com/grafana/grafana/pkg/tsdb/azuremonitor/types"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
)
|
||||
|
||||
func Pointer[T any](v T) *T { return &v }
|
||||
|
||||
func TestAzureMonitorBuildQueries(t *testing.T) {
|
||||
datasource := &AzureMonitorDatasource{}
|
||||
dsInfo := types.DatasourceInfo{
|
||||
@ -117,7 +118,7 @@ func TestAzureMonitorBuildQueries(t *testing.T) {
|
||||
expectedInterval: "PT1M",
|
||||
azureMonitorQueryTarget: "aggregation=Average&api-version=2021-05-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute%2FvirtualMachines×pan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z&top=30",
|
||||
expectedParamFilter: "blob eq '*'",
|
||||
expectedPortalURL: util.Pointer("http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%222018-03-15T13%3A00%3A00Z%22%2C%22endTime%22%3A%222018-03-15T13%3A34%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22grouping%22%3A%7B%22dimension%22%3A%22blob%22%2C%22sort%22%3A2%2C%22top%22%3A10%7D%2C%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22Percentage%20CPU%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22Microsoft.Compute%2FvirtualMachines%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22Percentage%20CPU%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D"),
|
||||
expectedPortalURL: Pointer("http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%222018-03-15T13%3A00%3A00Z%22%2C%22endTime%22%3A%222018-03-15T13%3A34%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22grouping%22%3A%7B%22dimension%22%3A%22blob%22%2C%22sort%22%3A2%2C%22top%22%3A10%7D%2C%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22Percentage%20CPU%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22Microsoft.Compute%2FvirtualMachines%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22Percentage%20CPU%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D"),
|
||||
},
|
||||
{
|
||||
name: "legacy query without resourceURI and has dimensionFilter*s* property with two dimensions",
|
||||
@ -130,7 +131,7 @@ func TestAzureMonitorBuildQueries(t *testing.T) {
|
||||
expectedInterval: "PT1M",
|
||||
azureMonitorQueryTarget: "aggregation=Average&api-version=2021-05-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute%2FvirtualMachines×pan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z&top=30",
|
||||
expectedParamFilter: "blob eq '*' and tier eq '*'",
|
||||
expectedPortalURL: util.Pointer("http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%222018-03-15T13%3A00%3A00Z%22%2C%22endTime%22%3A%222018-03-15T13%3A34%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22grouping%22%3A%7B%22dimension%22%3A%22blob%22%2C%22sort%22%3A2%2C%22top%22%3A10%7D%2C%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22Percentage%20CPU%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22Microsoft.Compute%2FvirtualMachines%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22Percentage%20CPU%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D"),
|
||||
expectedPortalURL: Pointer("http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%222018-03-15T13%3A00%3A00Z%22%2C%22endTime%22%3A%222018-03-15T13%3A34%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22grouping%22%3A%7B%22dimension%22%3A%22blob%22%2C%22sort%22%3A2%2C%22top%22%3A10%7D%2C%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22Percentage%20CPU%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22Microsoft.Compute%2FvirtualMachines%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22Percentage%20CPU%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D"),
|
||||
},
|
||||
{
|
||||
name: "legacy query without resourceURI and has a dimension filter without specifying a top",
|
||||
@ -155,7 +156,7 @@ func TestAzureMonitorBuildQueries(t *testing.T) {
|
||||
expectedInterval: "PT1M",
|
||||
azureMonitorQueryTarget: "aggregation=Average&api-version=2021-05-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute%2FvirtualMachines×pan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z&top=30",
|
||||
expectedParamFilter: "blob ne 'test'",
|
||||
expectedPortalURL: util.Pointer("http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%222018-03-15T13%3A00%3A00Z%22%2C%22endTime%22%3A%222018-03-15T13%3A34%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22filterCollection%22%3A%7B%22filters%22%3A%5B%7B%22key%22%3A%22blob%22%2C%22operator%22%3A1%2C%22values%22%3A%5B%22test%22%5D%7D%5D%7D%2C%22grouping%22%3A%7B%22dimension%22%3A%22blob%22%2C%22sort%22%3A2%2C%22top%22%3A10%7D%2C%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22Percentage%20CPU%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22Microsoft.Compute%2FvirtualMachines%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22Percentage%20CPU%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D"),
|
||||
expectedPortalURL: Pointer("http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%222018-03-15T13%3A00%3A00Z%22%2C%22endTime%22%3A%222018-03-15T13%3A34%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22filterCollection%22%3A%7B%22filters%22%3A%5B%7B%22key%22%3A%22blob%22%2C%22operator%22%3A1%2C%22values%22%3A%5B%22test%22%5D%7D%5D%7D%2C%22grouping%22%3A%7B%22dimension%22%3A%22blob%22%2C%22sort%22%3A2%2C%22top%22%3A10%7D%2C%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22Percentage%20CPU%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22Microsoft.Compute%2FvirtualMachines%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22Percentage%20CPU%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D"),
|
||||
},
|
||||
{
|
||||
name: "has dimensionFilter*s* property with startsWith operator",
|
||||
@ -168,7 +169,7 @@ func TestAzureMonitorBuildQueries(t *testing.T) {
|
||||
expectedInterval: "PT1M",
|
||||
azureMonitorQueryTarget: "aggregation=Average&api-version=2021-05-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute%2FvirtualMachines×pan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z&top=30",
|
||||
expectedParamFilter: "blob sw 'test'",
|
||||
expectedPortalURL: util.Pointer("http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%222018-03-15T13%3A00%3A00Z%22%2C%22endTime%22%3A%222018-03-15T13%3A34%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22filterCollection%22%3A%7B%22filters%22%3A%5B%7B%22key%22%3A%22blob%22%2C%22operator%22%3A3%2C%22values%22%3A%5B%22test%22%5D%7D%5D%7D%2C%22grouping%22%3A%7B%22dimension%22%3A%22blob%22%2C%22sort%22%3A2%2C%22top%22%3A10%7D%2C%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22Percentage%20CPU%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22Microsoft.Compute%2FvirtualMachines%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22Percentage%20CPU%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D"),
|
||||
expectedPortalURL: Pointer("http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%222018-03-15T13%3A00%3A00Z%22%2C%22endTime%22%3A%222018-03-15T13%3A34%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22filterCollection%22%3A%7B%22filters%22%3A%5B%7B%22key%22%3A%22blob%22%2C%22operator%22%3A3%2C%22values%22%3A%5B%22test%22%5D%7D%5D%7D%2C%22grouping%22%3A%7B%22dimension%22%3A%22blob%22%2C%22sort%22%3A2%2C%22top%22%3A10%7D%2C%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22Percentage%20CPU%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22Microsoft.Compute%2FvirtualMachines%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22Percentage%20CPU%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D"),
|
||||
},
|
||||
{
|
||||
name: "correctly sets dimension operator to eq (irrespective of operator) when filter value is '*'",
|
||||
@ -181,7 +182,7 @@ func TestAzureMonitorBuildQueries(t *testing.T) {
|
||||
expectedInterval: "PT1M",
|
||||
azureMonitorQueryTarget: "aggregation=Average&api-version=2021-05-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute%2FvirtualMachines×pan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z&top=30",
|
||||
expectedParamFilter: "blob eq '*' and tier eq '*'",
|
||||
expectedPortalURL: util.Pointer("http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%222018-03-15T13%3A00%3A00Z%22%2C%22endTime%22%3A%222018-03-15T13%3A34%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22grouping%22%3A%7B%22dimension%22%3A%22blob%22%2C%22sort%22%3A2%2C%22top%22%3A10%7D%2C%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22Percentage%20CPU%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22Microsoft.Compute%2FvirtualMachines%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22Percentage%20CPU%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D"),
|
||||
expectedPortalURL: Pointer("http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%222018-03-15T13%3A00%3A00Z%22%2C%22endTime%22%3A%222018-03-15T13%3A34%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22grouping%22%3A%7B%22dimension%22%3A%22blob%22%2C%22sort%22%3A2%2C%22top%22%3A10%7D%2C%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22Percentage%20CPU%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22Microsoft.Compute%2FvirtualMachines%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22Percentage%20CPU%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D"),
|
||||
},
|
||||
{
|
||||
name: "correctly constructs target when multiple filter values are provided for the 'eq' operator",
|
||||
@ -194,7 +195,7 @@ func TestAzureMonitorBuildQueries(t *testing.T) {
|
||||
expectedInterval: "PT1M",
|
||||
azureMonitorQueryTarget: "aggregation=Average&api-version=2021-05-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute%2FvirtualMachines×pan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z&top=30",
|
||||
expectedParamFilter: "blob eq 'test' or blob eq 'test2'",
|
||||
expectedPortalURL: util.Pointer("http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%222018-03-15T13%3A00%3A00Z%22%2C%22endTime%22%3A%222018-03-15T13%3A34%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22filterCollection%22%3A%7B%22filters%22%3A%5B%7B%22key%22%3A%22blob%22%2C%22operator%22%3A0%2C%22values%22%3A%5B%22test%22%2C%22test2%22%5D%7D%5D%7D%2C%22grouping%22%3A%7B%22dimension%22%3A%22blob%22%2C%22sort%22%3A2%2C%22top%22%3A10%7D%2C%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22Percentage%20CPU%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22Microsoft.Compute%2FvirtualMachines%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22Percentage%20CPU%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D"),
|
||||
expectedPortalURL: Pointer("http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%222018-03-15T13%3A00%3A00Z%22%2C%22endTime%22%3A%222018-03-15T13%3A34%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22filterCollection%22%3A%7B%22filters%22%3A%5B%7B%22key%22%3A%22blob%22%2C%22operator%22%3A0%2C%22values%22%3A%5B%22test%22%2C%22test2%22%5D%7D%5D%7D%2C%22grouping%22%3A%7B%22dimension%22%3A%22blob%22%2C%22sort%22%3A2%2C%22top%22%3A10%7D%2C%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22Percentage%20CPU%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22Microsoft.Compute%2FvirtualMachines%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22Percentage%20CPU%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D"),
|
||||
},
|
||||
{
|
||||
name: "correctly constructs target when multiple filter values are provided for ne 'eq' operator",
|
||||
@ -207,7 +208,7 @@ func TestAzureMonitorBuildQueries(t *testing.T) {
|
||||
expectedInterval: "PT1M",
|
||||
azureMonitorQueryTarget: "aggregation=Average&api-version=2021-05-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute%2FvirtualMachines×pan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z&top=30",
|
||||
expectedParamFilter: "blob ne 'test' and blob ne 'test2'",
|
||||
expectedPortalURL: util.Pointer("http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%222018-03-15T13%3A00%3A00Z%22%2C%22endTime%22%3A%222018-03-15T13%3A34%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22filterCollection%22%3A%7B%22filters%22%3A%5B%7B%22key%22%3A%22blob%22%2C%22operator%22%3A1%2C%22values%22%3A%5B%22test%22%2C%22test2%22%5D%7D%5D%7D%2C%22grouping%22%3A%7B%22dimension%22%3A%22blob%22%2C%22sort%22%3A2%2C%22top%22%3A10%7D%2C%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22Percentage%20CPU%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22Microsoft.Compute%2FvirtualMachines%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22Percentage%20CPU%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D"),
|
||||
expectedPortalURL: Pointer("http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%222018-03-15T13%3A00%3A00Z%22%2C%22endTime%22%3A%222018-03-15T13%3A34%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22filterCollection%22%3A%7B%22filters%22%3A%5B%7B%22key%22%3A%22blob%22%2C%22operator%22%3A1%2C%22values%22%3A%5B%22test%22%2C%22test2%22%5D%7D%5D%7D%2C%22grouping%22%3A%7B%22dimension%22%3A%22blob%22%2C%22sort%22%3A2%2C%22top%22%3A10%7D%2C%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22Percentage%20CPU%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22Microsoft.Compute%2FvirtualMachines%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22Percentage%20CPU%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D"),
|
||||
},
|
||||
{
|
||||
name: "Includes a region",
|
||||
@ -257,7 +258,7 @@ func TestAzureMonitorBuildQueries(t *testing.T) {
|
||||
expectedURL: "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/providers/microsoft.insights/metrics",
|
||||
azureMonitorQueryTarget: "aggregation=Average&api-version=2021-05-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute%2FvirtualMachines×pan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z&top=30",
|
||||
expectedBodyFilter: "(Microsoft.ResourceId eq '/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/rg/providers/Microsoft.Compute/virtualMachines/vm' or Microsoft.ResourceId eq '/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/rg2/providers/Microsoft.Compute/virtualMachines/vm2') and (blob ne 'test' and blob ne 'test2')",
|
||||
expectedPortalURL: util.Pointer("http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%222018-03-15T13%3A00%3A00Z%22%2C%22endTime%22%3A%222018-03-15T13%3A34%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22filterCollection%22%3A%7B%22filters%22%3A%5B%7B%22key%22%3A%22blob%22%2C%22operator%22%3A1%2C%22values%22%3A%5B%22test%22%2C%22test2%22%5D%7D%5D%7D%2C%22grouping%22%3A%7B%22dimension%22%3A%22blob%22%2C%22sort%22%3A2%2C%22top%22%3A10%7D%2C%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22Percentage%20CPU%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22Microsoft.Compute%2FvirtualMachines%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22Percentage%20CPU%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D"),
|
||||
expectedPortalURL: Pointer("http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%222018-03-15T13%3A00%3A00Z%22%2C%22endTime%22%3A%222018-03-15T13%3A34%3A00Z%22%7D%7D/ChartDefinition/%7B%22v2charts%22%3A%5B%7B%22filterCollection%22%3A%7B%22filters%22%3A%5B%7B%22key%22%3A%22blob%22%2C%22operator%22%3A1%2C%22values%22%3A%5B%22test%22%2C%22test2%22%5D%7D%5D%7D%2C%22grouping%22%3A%7B%22dimension%22%3A%22blob%22%2C%22sort%22%3A2%2C%22top%22%3A10%7D%2C%22metrics%22%3A%5B%7B%22resourceMetadata%22%3A%7B%22id%22%3A%22%2Fsubscriptions%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanastaging%2Fproviders%2FMicrosoft.Compute%2FvirtualMachines%2Fgrafana%22%7D%2C%22name%22%3A%22Percentage%20CPU%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22Microsoft.Compute%2FvirtualMachines%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22Percentage%20CPU%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D"),
|
||||
},
|
||||
}
|
||||
|
||||
|
38
pkg/tsdb/azuremonitor/standalone/datasource.go
Normal file
38
pkg/tsdb/azuremonitor/standalone/datasource.go
Normal file
@ -0,0 +1,38 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt"
|
||||
azuremonitor "github.com/grafana/grafana/pkg/tsdb/azuremonitor"
|
||||
)
|
||||
|
||||
var (
|
||||
_ backend.QueryDataHandler = (*Datasource)(nil)
|
||||
_ backend.CheckHealthHandler = (*Datasource)(nil)
|
||||
_ backend.CallResourceHandler = (*Datasource)(nil)
|
||||
)
|
||||
|
||||
func NewDatasource(context.Context, backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) {
|
||||
return &Datasource{
|
||||
Service: azuremonitor.ProvideService(httpclient.NewProvider()),
|
||||
}, nil
|
||||
}
|
||||
|
||||
type Datasource struct {
|
||||
Service *azuremonitor.Service
|
||||
}
|
||||
|
||||
func (d *Datasource) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) {
|
||||
return d.Service.QueryData(ctx, req)
|
||||
}
|
||||
|
||||
func (d *Datasource) CallResource(ctx context.Context, req *backend.CallResourceRequest, sender backend.CallResourceResponseSender) error {
|
||||
return d.Service.CallResource(ctx, req, sender)
|
||||
}
|
||||
|
||||
func (d *Datasource) CheckHealth(ctx context.Context, req *backend.CheckHealthRequest) (*backend.CheckHealthResult, error) {
|
||||
return d.Service.CheckHealth(ctx, req)
|
||||
}
|
23
pkg/tsdb/azuremonitor/standalone/main.go
Normal file
23
pkg/tsdb/azuremonitor/standalone/main.go
Normal file
@ -0,0 +1,23 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend/datasource"
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend/log"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Start listening to requests sent from Grafana. This call is blocking so
|
||||
// it won't finish until Grafana shuts down the process or the plugin choose
|
||||
// to exit by itself using os.Exit. Manage automatically manages life cycle
|
||||
// of datasource instances. It accepts datasource instance factory as first
|
||||
// argument. This factory will be automatically called on incoming request
|
||||
// from Grafana to create different instances of SampleDatasource (per datasource
|
||||
// ID). When datasource configuration changed Dispose method will be called and
|
||||
// new datasource instance created using NewSampleDatasource factory.
|
||||
if err := datasource.Manage("grafana-azure-monitor-datasource", NewDatasource, datasource.ManageOpts{}); err != nil {
|
||||
log.DefaultLogger.Error(err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
93
pkg/tsdb/azuremonitor/time/interval.go
Normal file
93
pkg/tsdb/azuremonitor/time/interval.go
Normal file
@ -0,0 +1,93 @@
|
||||
// Copied from https://github.com/grafana/grafana/blob/main/pkg/tsdb/intervalv2/intervalv2.go
|
||||
// We're copying this to not block ourselves from decoupling until the conversation here is resolved
|
||||
// https://raintank-corp.slack.com/archives/C05QFJUHUQ6/p1700064431005089
|
||||
package time
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend/gtime"
|
||||
)
|
||||
|
||||
var (
|
||||
year = time.Hour * 24 * 365
|
||||
day = time.Hour * 24
|
||||
)
|
||||
|
||||
// GetIntervalFrom returns the minimum interval.
|
||||
// dsInterval is the string representation of data source min interval, if configured.
|
||||
// queryInterval is the string representation of query interval (min interval), e.g. "10ms" or "10s".
|
||||
// queryIntervalMS is a pre-calculated numeric representation of the query interval in milliseconds.
|
||||
func GetIntervalFrom(dsInterval, queryInterval string, queryIntervalMS int64, defaultInterval time.Duration) (time.Duration, error) {
|
||||
// Apparently we are setting default value of queryInterval to 0s now
|
||||
interval := queryInterval
|
||||
if interval == "0s" {
|
||||
interval = ""
|
||||
}
|
||||
if interval == "" {
|
||||
if queryIntervalMS != 0 {
|
||||
return time.Duration(queryIntervalMS) * time.Millisecond, nil
|
||||
}
|
||||
}
|
||||
if interval == "" && dsInterval != "" {
|
||||
interval = dsInterval
|
||||
}
|
||||
if interval == "" {
|
||||
return defaultInterval, nil
|
||||
}
|
||||
|
||||
parsedInterval, err := ParseIntervalStringToTimeDuration(interval)
|
||||
if err != nil {
|
||||
return time.Duration(0), err
|
||||
}
|
||||
|
||||
return parsedInterval, nil
|
||||
}
|
||||
|
||||
func ParseIntervalStringToTimeDuration(interval string) (time.Duration, error) {
|
||||
formattedInterval := strings.Replace(strings.Replace(interval, "<", "", 1), ">", "", 1)
|
||||
isPureNum, err := regexp.MatchString(`^\d+$`, formattedInterval)
|
||||
if err != nil {
|
||||
return time.Duration(0), err
|
||||
}
|
||||
if isPureNum {
|
||||
formattedInterval += "s"
|
||||
}
|
||||
parsedInterval, err := gtime.ParseDuration(formattedInterval)
|
||||
if err != nil {
|
||||
return time.Duration(0), err
|
||||
}
|
||||
return parsedInterval, nil
|
||||
}
|
||||
|
||||
// FormatDuration converts a duration into the kbn format e.g. 1m 2h or 3d
|
||||
func FormatDuration(inter time.Duration) string {
|
||||
if inter >= year {
|
||||
return fmt.Sprintf("%dy", inter/year)
|
||||
}
|
||||
|
||||
if inter >= day {
|
||||
return fmt.Sprintf("%dd", inter/day)
|
||||
}
|
||||
|
||||
if inter >= time.Hour {
|
||||
return fmt.Sprintf("%dh", inter/time.Hour)
|
||||
}
|
||||
|
||||
if inter >= time.Minute {
|
||||
return fmt.Sprintf("%dm", inter/time.Minute)
|
||||
}
|
||||
|
||||
if inter >= time.Second {
|
||||
return fmt.Sprintf("%ds", inter/time.Second)
|
||||
}
|
||||
|
||||
if inter >= time.Millisecond {
|
||||
return fmt.Sprintf("%dms", inter/time.Millisecond)
|
||||
}
|
||||
|
||||
return "1ms"
|
||||
}
|
@ -5,8 +5,6 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/tsdb/intervalv2"
|
||||
)
|
||||
|
||||
// TimeGrain handles conversions between
|
||||
@ -17,7 +15,7 @@ var (
|
||||
)
|
||||
|
||||
func CreateISO8601DurationFromIntervalMS(it int64) (string, error) {
|
||||
formatted := intervalv2.FormatDuration(time.Duration(it) * time.Millisecond)
|
||||
formatted := FormatDuration(time.Duration(it) * time.Millisecond)
|
||||
|
||||
if strings.Contains(formatted, "ms") {
|
||||
return "PT1M", nil
|
||||
|
@ -32,7 +32,7 @@ const testDataDSPlugin = async () =>
|
||||
const cloudMonitoringPlugin = async () =>
|
||||
await import(/* webpackChunkName: "cloudMonitoringPlugin" */ 'app/plugins/datasource/cloud-monitoring/module');
|
||||
const azureMonitorPlugin = async () =>
|
||||
await import(/* webpackChunkName: "azureMonitorPlugin" */ 'app/plugins/datasource/azuremonitor/module');
|
||||
await import(/* webpackChunkName: "azureMonitorPlugin" */ '@grafana-plugins/grafana-azure-monitor-datasource/module');
|
||||
const tempoPlugin = async () =>
|
||||
await import(/* webpackChunkName: "tempoPlugin" */ 'app/plugins/datasource/tempo/module');
|
||||
const alertmanagerPlugin = async () =>
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { BaseVariableModel, CustomVariableModel, LoadingState, VariableHide } from '@grafana/data';
|
||||
import { BaseVariableModel, CustomVariableModel, LoadingState, VariableHide, VariableOption } from '@grafana/data';
|
||||
|
||||
const initialVariableModelState: BaseVariableModel = {
|
||||
id: '00000000-0000-0000-0000-000000000000',
|
||||
@ -63,3 +63,14 @@ export const multiVariable: CustomVariableModel = {
|
||||
hide: VariableHide.dontHide,
|
||||
type: 'custom',
|
||||
};
|
||||
|
||||
export const initialCustomVariableModelState: CustomVariableModel = {
|
||||
...initialVariableModelState,
|
||||
type: 'custom',
|
||||
multi: false,
|
||||
includeAll: false,
|
||||
allValue: null,
|
||||
query: '',
|
||||
options: [],
|
||||
current: {} as VariableOption,
|
||||
};
|
||||
|
@ -2,11 +2,11 @@ import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import React from 'react';
|
||||
import { openMenu } from 'react-select-event';
|
||||
import { selectOptionInTest } from 'test/helpers/selectOptionInTest';
|
||||
|
||||
import createMockDatasource from '../../__mocks__/datasource';
|
||||
import createMockPanelData from '../../__mocks__/panelData';
|
||||
import createMockQuery from '../../__mocks__/query';
|
||||
import { selectOptionInTest } from '../../utils/testUtils';
|
||||
|
||||
import DimensionFields from './DimensionFields';
|
||||
import { appendDimensionFilter, setDimensionFilterValue } from './setQueryValue';
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import React from 'react';
|
||||
import { selectOptionInTest } from 'test/helpers/selectOptionInTest';
|
||||
|
||||
import createMockDatasource from '../../__mocks__/datasource';
|
||||
import { createMockInstanceSetttings } from '../../__mocks__/instanceSettings';
|
||||
@ -14,6 +13,7 @@ import {
|
||||
} from '../../__mocks__/resourcePickerRows';
|
||||
import { selectors } from '../../e2e/selectors';
|
||||
import ResourcePickerData from '../../resourcePicker/resourcePickerData';
|
||||
import { selectOptionInTest } from '../../utils/testUtils';
|
||||
|
||||
import MetricsQueryEditor from './MetricsQueryEditor';
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import { selectOptionInTest } from 'test/helpers/selectOptionInTest';
|
||||
|
||||
import * as ui from '@grafana/ui';
|
||||
|
||||
@ -9,6 +8,7 @@ import { invalidNamespaceError } from '../../__mocks__/errors';
|
||||
import createMockQuery from '../../__mocks__/query';
|
||||
import { selectors } from '../../e2e/selectors';
|
||||
import { AzureQueryType } from '../../types';
|
||||
import { selectOptionInTest } from '../../utils/testUtils';
|
||||
|
||||
import QueryEditor from './QueryEditor';
|
||||
|
||||
|
@ -3,7 +3,6 @@ import userEvent from '@testing-library/user-event';
|
||||
import { UserEvent } from '@testing-library/user-event/dist/types/setup/setup';
|
||||
import React from 'react';
|
||||
import { of } from 'rxjs';
|
||||
import { selectOptionInTest } from 'test/helpers/selectOptionInTest';
|
||||
|
||||
import { CoreApp } from '@grafana/data';
|
||||
|
||||
@ -12,6 +11,7 @@ import createMockQuery from '../../__mocks__/query';
|
||||
import { AzureQueryType } from '../../dataquery.gen';
|
||||
import Datasource from '../../datasource';
|
||||
import { AzureMonitorQuery } from '../../types';
|
||||
import { selectOptionInTest } from '../../utils/testUtils';
|
||||
|
||||
import Filters from './Filters';
|
||||
import { setFilters } from './setQueryValue';
|
||||
|
50
public/app/plugins/datasource/azuremonitor/package.json
Normal file
50
public/app/plugins/datasource/azuremonitor/package.json
Normal file
@ -0,0 +1,50 @@
|
||||
{
|
||||
"name": "@grafana-plugins/grafana-azure-monitor-datasource",
|
||||
"description": "Grafana data source for Azure Monitor",
|
||||
"private": true,
|
||||
"version": "10.3.0-pre",
|
||||
"dependencies": {
|
||||
"@emotion/css": "11.11.2",
|
||||
"@grafana/data": "10.3.0-pre",
|
||||
"@grafana/experimental": "1.7.4",
|
||||
"@grafana/runtime": "10.3.0-pre",
|
||||
"@grafana/schema": "10.3.0-pre",
|
||||
"@grafana/ui": "10.3.0-pre",
|
||||
"@kusto/monaco-kusto": "^7.4.0",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"i18next": "^22.0.0",
|
||||
"immer": "10.0.2",
|
||||
"lodash": "4.17.21",
|
||||
"monaco-editor": "0.34.0",
|
||||
"prismjs": "1.29.0",
|
||||
"react": "18.2.0",
|
||||
"react-use": "17.4.0",
|
||||
"rxjs": "7.8.1",
|
||||
"tslib": "2.6.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@grafana/e2e-selectors": "10.3.0-pre",
|
||||
"@grafana/plugin-configs": "10.3.0-pre",
|
||||
"@testing-library/react": "14.0.0",
|
||||
"@testing-library/user-event": "14.5.1",
|
||||
"@types/jest": "29.5.4",
|
||||
"@types/lodash": "4.14.195",
|
||||
"@types/node": "20.8.10",
|
||||
"@types/prismjs": "1.26.0",
|
||||
"@types/react": "18.2.15",
|
||||
"@types/testing-library__jest-dom": "5.14.8",
|
||||
"react-select-event": "5.5.1",
|
||||
"ts-node": "10.9.1",
|
||||
"typescript": "5.2.2",
|
||||
"webpack": "5.89.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@grafana/runtime": "*"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "webpack -c ./webpack.config.ts --env production",
|
||||
"build:commit": "webpack -c ./webpack.config.ts --env production --env commit=$(git rev-parse --short HEAD)",
|
||||
"dev": "webpack -w -c ./webpack.config.ts --env development"
|
||||
},
|
||||
"packageManager": "yarn@3.6.0"
|
||||
}
|
@ -77,7 +77,7 @@
|
||||
},
|
||||
{ "type": "dashboard", "name": "Azure / Resources Overview", "path": "dashboards/arg.json" }
|
||||
],
|
||||
|
||||
"executable": "gpx_azuremonitor",
|
||||
"info": {
|
||||
"description": "Data source for Microsoft Azure Monitor & Application Insights",
|
||||
"author": {
|
||||
@ -98,11 +98,11 @@
|
||||
{ "name": "Azure Monitor Network", "path": "img/azure_monitor_network.png" },
|
||||
{ "name": "Azure Monitor CPU", "path": "img/azure_monitor_cpu.png" }
|
||||
],
|
||||
"version": "1.0.0"
|
||||
"version": "%VERSION%"
|
||||
},
|
||||
|
||||
"dependencies": {
|
||||
"grafanaVersion": "5.2.x",
|
||||
"grafanaDependency": ">=10.3.0",
|
||||
"plugins": []
|
||||
},
|
||||
|
||||
|
4
public/app/plugins/datasource/azuremonitor/tsconfig.json
Normal file
4
public/app/plugins/datasource/azuremonitor/tsconfig.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "@grafana/plugin-configs/tsconfig.json",
|
||||
"include": ["."]
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
import { initialCustomVariableModelState } from 'app/features/variables/custom/reducer';
|
||||
import { initialCustomVariableModelState } from '../__mocks__/variables';
|
||||
|
||||
import { hasOption, interpolateVariable } from './common';
|
||||
|
||||
|
@ -0,0 +1,8 @@
|
||||
import { waitFor } from '@testing-library/react';
|
||||
import { select } from 'react-select-event';
|
||||
|
||||
// Used to select an option or options from a Select in unit tests
|
||||
export const selectOptionInTest = async (
|
||||
input: HTMLElement,
|
||||
optionOrOptions: string | RegExp | Array<string | RegExp>
|
||||
) => await waitFor(() => select(input, optionOrOptions, { container: document.body }));
|
@ -0,0 +1,3 @@
|
||||
import config from '@grafana/plugin-configs/webpack.config';
|
||||
|
||||
export default config;
|
41
yarn.lock
41
yarn.lock
@ -2872,6 +2872,46 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@grafana-plugins/grafana-azure-monitor-datasource@workspace:*, @grafana-plugins/grafana-azure-monitor-datasource@workspace:public/app/plugins/datasource/azuremonitor":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@grafana-plugins/grafana-azure-monitor-datasource@workspace:public/app/plugins/datasource/azuremonitor"
|
||||
dependencies:
|
||||
"@emotion/css": "npm:11.11.2"
|
||||
"@grafana/data": "npm:10.3.0-pre"
|
||||
"@grafana/e2e-selectors": "npm:10.3.0-pre"
|
||||
"@grafana/experimental": "npm:1.7.4"
|
||||
"@grafana/plugin-configs": "npm:10.3.0-pre"
|
||||
"@grafana/runtime": "npm:10.3.0-pre"
|
||||
"@grafana/schema": "npm:10.3.0-pre"
|
||||
"@grafana/ui": "npm:10.3.0-pre"
|
||||
"@kusto/monaco-kusto": "npm:^7.4.0"
|
||||
"@testing-library/react": "npm:14.0.0"
|
||||
"@testing-library/user-event": "npm:14.5.1"
|
||||
"@types/jest": "npm:29.5.4"
|
||||
"@types/lodash": "npm:4.14.195"
|
||||
"@types/node": "npm:20.8.10"
|
||||
"@types/prismjs": "npm:1.26.0"
|
||||
"@types/react": "npm:18.2.15"
|
||||
"@types/testing-library__jest-dom": "npm:5.14.8"
|
||||
fast-deep-equal: "npm:^3.1.3"
|
||||
i18next: "npm:^22.0.0"
|
||||
immer: "npm:10.0.2"
|
||||
lodash: "npm:4.17.21"
|
||||
monaco-editor: "npm:0.34.0"
|
||||
prismjs: "npm:1.29.0"
|
||||
react: "npm:18.2.0"
|
||||
react-select-event: "npm:5.5.1"
|
||||
react-use: "npm:17.4.0"
|
||||
rxjs: "npm:7.8.1"
|
||||
ts-node: "npm:10.9.1"
|
||||
tslib: "npm:2.6.0"
|
||||
typescript: "npm:5.2.2"
|
||||
webpack: "npm:5.89.0"
|
||||
peerDependencies:
|
||||
"@grafana/runtime": "*"
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@grafana-plugins/grafana-testdata-datasource@workspace:*, @grafana-plugins/grafana-testdata-datasource@workspace:public/app/plugins/datasource/grafana-testdata-datasource":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@grafana-plugins/grafana-testdata-datasource@workspace:public/app/plugins/datasource/grafana-testdata-datasource"
|
||||
@ -17363,6 +17403,7 @@ __metadata:
|
||||
"@fingerprintjs/fingerprintjs": "npm:^3.4.2"
|
||||
"@floating-ui/react": "npm:0.26.4"
|
||||
"@glideapps/glide-data-grid": "npm:^5.2.1"
|
||||
"@grafana-plugins/grafana-azure-monitor-datasource": "workspace:*"
|
||||
"@grafana-plugins/grafana-testdata-datasource": "workspace:*"
|
||||
"@grafana-plugins/parca": "workspace:*"
|
||||
"@grafana/aws-sdk": "npm:0.3.1"
|
||||
|
Loading…
Reference in New Issue
Block a user