Skip to content

Commit

Permalink
Azure: AzureMonitorMetrics - change response to be dataplane compliant (
Browse files Browse the repository at this point in the history
#69308)

* Azure: AzureMonitorMetrics - change response to be dataplane compliant
can be disabled via toggle azureMonitorDataplane
Co-authored-by: Andreas Christou <andreas.christou@grafana.com>
  • Loading branch information
kylebrandt committed Jul 24, 2023
1 parent c280f88 commit ee60d8c
Show file tree
Hide file tree
Showing 26 changed files with 515 additions and 30 deletions.
Expand Up @@ -41,6 +41,7 @@ Some features are enabled by default. You can disable these feature by setting t
| `alertingNotificationsPoliciesMatchingInstances` | Enables the preview of matching instances for notification policies | Yes |
| `useCachingService` | When turned on, the new query and resource caching implementation using a wire service inject will be used in place of the previous middleware implementation | |
| `advancedDataSourcePicker` | Enable a new data source picker with contextual information, recently used order and advanced mode | Yes |
| `azureMonitorDataplane` | Adds dataplane compliant frame metadata in the Azure Monitor datasource | Yes |

## Preview feature toggles

Expand Down
1 change: 1 addition & 0 deletions packages/grafana-data/src/types/featureToggles.gen.ts
Expand Up @@ -116,4 +116,5 @@ export interface FeatureToggles {
featureToggleAdminPage?: boolean;
awsAsyncQueryCaching?: boolean;
splitScopes?: boolean;
azureMonitorDataplane?: boolean;
}
2 changes: 1 addition & 1 deletion pkg/plugins/manager/manager_integration_test.go
Expand Up @@ -93,7 +93,7 @@ func TestIntegrationPluginManager(t *testing.T) {
features := featuremgmt.WithFeatures()

hcp := httpclient.NewProvider()
am := azuremonitor.ProvideService(cfg, hcp, tracer)
am := azuremonitor.ProvideService(cfg, hcp, features, tracer)
cw := cloudwatch.ProvideService(cfg, hcp, features)
cm := cloudmonitoring.ProvideService(hcp, tracer)
es := elasticsearch.ProvideService(hcp)
Expand Down
2 changes: 1 addition & 1 deletion pkg/services/featuremgmt/codeowners.go
Expand Up @@ -22,7 +22,7 @@ const (
hostedGrafanaTeam codeowner = "@grafana/hosted-grafana-team"
awsDatasourcesSquad codeowner = "@grafana/aws-datasources"
appO11ySquad codeowner = "@grafana/app-o11y"
grafanaPartnerPluginsSquad codeowner = "@grafana/partner-plugins"
grafanaPartnerPluginsSquad codeowner = "@grafana/partner-datasources"
grafanaOperatorExperienceSquad codeowner = "@grafana/grafana-operator-experience-squad"
enterpriseDatasourcesSquad codeowner = "@grafana/enterprise-datasources"
)
7 changes: 7 additions & 0 deletions pkg/services/featuremgmt/registry.go
Expand Up @@ -669,5 +669,12 @@ var (
Owner: grafanaAuthnzSquad,
RequiresRestart: true,
},
{
Name: "azureMonitorDataplane",
Description: "Adds dataplane compliant frame metadata in the Azure Monitor datasource",
Stage: FeatureStageGeneralAvailability,
Owner: grafanaPartnerPluginsSquad,
Expression: "true", // on by default
},
}
)
1 change: 1 addition & 0 deletions pkg/services/featuremgmt/toggles_gen.csv
Expand Up @@ -97,3 +97,4 @@ grafanaAPIServer,experimental,@grafana/grafana-app-platform-squad,false,false,fa
featureToggleAdminPage,experimental,@grafana/grafana-operator-experience-squad,false,false,true,false
awsAsyncQueryCaching,experimental,@grafana/aws-datasources,false,false,false,false
splitScopes,preview,@grafana/grafana-authnz-team,false,false,true,false
azureMonitorDataplane,GA,@grafana/partner-datasources,false,false,false,false
4 changes: 4 additions & 0 deletions pkg/services/featuremgmt/toggles_gen.go
Expand Up @@ -398,4 +398,8 @@ const (
// FlagSplitScopes
// Support faster dashboard and folder search by splitting permission scopes into parts
FlagSplitScopes = "splitScopes"

// FlagAzureMonitorDataplane
// Adds dataplane compliant frame metadata in the Azure Monitor datasource
FlagAzureMonitorDataplane = "azureMonitorDataplane"
)
5 changes: 3 additions & 2 deletions pkg/tsdb/azuremonitor/azuremonitor.go
Expand Up @@ -19,6 +19,7 @@ import (

"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/tracing"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/tsdb/azuremonitor/loganalytics"
"github.com/grafana/grafana/pkg/tsdb/azuremonitor/metrics"
Expand All @@ -28,10 +29,10 @@ import (

var logger = log.New("tsdb.azuremonitor")

func ProvideService(cfg *setting.Cfg, httpClientProvider *httpclient.Provider, tracer tracing.Tracer) *Service {
func ProvideService(cfg *setting.Cfg, httpClientProvider *httpclient.Provider, features featuremgmt.FeatureToggles, tracer tracing.Tracer) *Service {
proxy := &httpServiceProxy{}
executors := map[string]azDatasourceExecutor{
azureMonitor: &metrics.AzureMonitorDatasource{Proxy: proxy},
azureMonitor: &metrics.AzureMonitorDatasource{Proxy: proxy, Features: features},
azureLogAnalytics: &loganalytics.AzureLogAnalyticsDatasource{Proxy: proxy},
azureResourceGraph: &resourcegraph.AzureResourceGraphDatasource{Proxy: proxy},
azureTraces: &loganalytics.AzureLogAnalyticsDatasource{Proxy: proxy},
Expand Down
7 changes: 6 additions & 1 deletion pkg/tsdb/azuremonitor/metrics/azuremonitor-datasource.go
Expand Up @@ -19,6 +19,7 @@ import (

"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/tracing"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/tsdb/azuremonitor/kinds/dataquery"
"github.com/grafana/grafana/pkg/tsdb/azuremonitor/loganalytics"
Expand All @@ -28,7 +29,8 @@ import (

// AzureMonitorDatasource calls the Azure Monitor API - one of the four API's supported
type AzureMonitorDatasource struct {
Proxy types.ServiceProxy
Proxy types.ServiceProxy
Features featuremgmt.FeatureToggles
}

var (
Expand Down Expand Up @@ -396,6 +398,9 @@ func (e *AzureMonitorDatasource) parseResponse(amr types.AzureMonitorResponse, q
}

frame := data.NewFrameOfFieldTypes("", len(series.Data), data.FieldTypeTime, data.FieldTypeNullableFloat64)
if e.Features.IsEnabled(featuremgmt.FlagAzureMonitorDataplane) {
frame.Meta = &data.FrameMeta{Type: data.FrameTypeTimeSeriesMulti, TypeVersion: data.FrameTypeVersion{0, 1}}
}
frame.RefID = query.RefID
timeField := frame.Fields[0]
timeField.Name = data.TimeSeriesTimeFieldName
Expand Down
40 changes: 38 additions & 2 deletions pkg/tsdb/azuremonitor/metrics/azuremonitor-datasource_test.go
Expand Up @@ -366,18 +366,28 @@ func TestCustomNamespace(t *testing.T) {
})
}

type fakeFeatureToggles struct {
flags map[string]bool
}

func (f *fakeFeatureToggles) IsEnabled(feature string) bool {
return f.flags[feature]
}

func TestAzureMonitorParseResponse(t *testing.T) {
resources := map[string]dataquery.AzureMonitorResource{}
resources["/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana"] =
dataquery.AzureMonitorResource{ResourceGroup: strPtr("grafanastaging"), ResourceName: strPtr("grafana")}
subscription := "12345678-aaaa-bbbb-cccc-123456789abc"
datasource := &AzureMonitorDatasource{Features: &fakeFeatureToggles{flags: map[string]bool{"azureMonitorDataplane": true}}}

tests := []struct {
name string
responseFile string
mockQuery *types.AzureMonitorQuery
expectedFrames data.Frames
queryIntervalMS int64
datasource *AzureMonitorDatasource
}{
{
name: "average aggregate time series response",
Expand All @@ -390,6 +400,7 @@ func TestAzureMonitorParseResponse(t *testing.T) {
Resources: resources,
Subscription: subscription,
},
datasource: datasource,
},
{
name: "total aggregate time series response",
Expand All @@ -402,6 +413,7 @@ func TestAzureMonitorParseResponse(t *testing.T) {
Resources: resources,
Subscription: subscription,
},
datasource: datasource,
},
{
name: "maximum aggregate time series response",
Expand All @@ -414,6 +426,7 @@ func TestAzureMonitorParseResponse(t *testing.T) {
Resources: resources,
Subscription: subscription,
},
datasource: datasource,
},
{
name: "minimum aggregate time series response",
Expand All @@ -426,6 +439,7 @@ func TestAzureMonitorParseResponse(t *testing.T) {
Resources: resources,
Subscription: subscription,
},
datasource: datasource,
},
{
name: "count aggregate time series response",
Expand All @@ -438,6 +452,7 @@ func TestAzureMonitorParseResponse(t *testing.T) {
Resources: resources,
Subscription: subscription,
},
datasource: datasource,
},
{
name: "single dimension time series response",
Expand All @@ -450,6 +465,7 @@ func TestAzureMonitorParseResponse(t *testing.T) {
Resources: resources,
Subscription: subscription,
},
datasource: datasource,
},
{
name: "with alias patterns in the query",
Expand All @@ -463,6 +479,7 @@ func TestAzureMonitorParseResponse(t *testing.T) {
Resources: resources,
Subscription: subscription,
},
datasource: datasource,
},
{
name: "single dimension with alias",
Expand All @@ -476,6 +493,7 @@ func TestAzureMonitorParseResponse(t *testing.T) {
Resources: resources,
Subscription: subscription,
},
datasource: datasource,
},
{
name: "multiple dimension time series response with label alias",
Expand All @@ -489,6 +507,7 @@ func TestAzureMonitorParseResponse(t *testing.T) {
Resources: map[string]dataquery.AzureMonitorResource{"/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanatest/providers/Microsoft.Storage/storageAccounts/testblobaccount/blobServices/default/providers/Microsoft.Insights/metrics": {ResourceGroup: strPtr("grafanatest"), ResourceName: strPtr("testblobaccount")}},
Subscription: subscription,
},
datasource: datasource,
},
{
name: "unspecified unit with alias should not panic",
Expand All @@ -502,6 +521,7 @@ func TestAzureMonitorParseResponse(t *testing.T) {
Resources: resources,
Subscription: subscription,
},
datasource: datasource,
},
{
name: "with legacy azure monitor query properties and without a resource uri",
Expand All @@ -515,6 +535,7 @@ func TestAzureMonitorParseResponse(t *testing.T) {
Resources: resources,
Subscription: subscription,
},
datasource: datasource,
},
{
name: "with legacy azure monitor query properties and with a resource uri it should use the resource uri",
Expand All @@ -528,6 +549,7 @@ func TestAzureMonitorParseResponse(t *testing.T) {
Resources: resources,
Subscription: subscription,
},
datasource: datasource,
},
{
name: "multiple time series response",
Expand All @@ -540,6 +562,7 @@ func TestAzureMonitorParseResponse(t *testing.T) {
Resources: resources,
Subscription: subscription,
},
datasource: datasource,
},
{
name: "multiple time series response with multiple dimensions",
Expand All @@ -552,14 +575,27 @@ func TestAzureMonitorParseResponse(t *testing.T) {
Resources: resources,
Subscription: subscription,
},
datasource: datasource,
},
{
name: "non-dataplane compliant response",
responseFile: "azuremonitor/11-azure-monitor-non-dataplane-response.json",
mockQuery: &types.AzureMonitorQuery{
URL: "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana/providers/microsoft.insights/metrics",
Params: url.Values{
"aggregation": {"Average"},
},
Resources: resources,
Subscription: subscription,
},
datasource: &AzureMonitorDatasource{Features: &fakeFeatureToggles{flags: map[string]bool{"azureMonitorDataplane": false}}},
},
}

datasource := &AzureMonitorDatasource{}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
azData := loadTestFile(t, tt.responseFile)
dframes, err := datasource.parseResponse(azData, tt.mockQuery, "http://ds", "")
dframes, err := tt.datasource.parseResponse(azData, tt.mockQuery, "http://ds", "")
require.NoError(t, err)
require.NotNil(t, dframes)

Expand Down
@@ -1,6 +1,12 @@
// 🌟 This was machine generated. Do not edit. 🌟
//
// Frame[0]
// Frame[0] {
// "type": "timeseries-multi",
// "typeVersion": [
// 0,
// 1
// ]
// }
// Name:
// Dimensions: 2 Fields by 5 Rows
// +-------------------------------+----------------------+
Expand All @@ -22,6 +28,13 @@
"frames": [
{
"schema": {
"meta": {
"type": "timeseries-multi",
"typeVersion": [
0,
1
]
},
"fields": [
{
"name": "Time",
Expand Down

0 comments on commit ee60d8c

Please sign in to comment.