Azure Monitor: Deprecate metricDefinition (#52793)

This commit is contained in:
Andres Martinez Gotor
2022-07-27 15:26:32 +02:00
committed by GitHub
parent 976a91cb0a
commit 7505cf418b
26 changed files with 360 additions and 561 deletions
@@ -74,33 +74,28 @@ func (e *AzureMonitorDatasource) buildQueries(queries []backend.DataQuery, dsInf
}
azJSONModel := queryJSONModel.AzureMonitor
// Legacy: If only MetricDefinition is set, use it as namespace
if azJSONModel.MetricDefinition != "" && azJSONModel.MetricNamespace == "" {
azJSONModel.MetricNamespace = azJSONModel.MetricDefinition
}
ub := urlBuilder{
ResourceURI: azJSONModel.ResourceURI,
// Legacy, used to reconstruct resource URI if it's not present
// Alternative, used to reconstruct resource URI if it's not present
DefaultSubscription: dsInfo.Settings.SubscriptionId,
Subscription: queryJSONModel.Subscription,
ResourceGroup: azJSONModel.ResourceGroup,
MetricDefinition: azJSONModel.MetricDefinition,
MetricNamespace: azJSONModel.MetricNamespace,
ResourceName: azJSONModel.ResourceName,
}
azJSONModel.DimensionFilters = MigrateDimensionFilters(azJSONModel.DimensionFilters)
azureURL := ub.BuildMetricsURL()
resourceName := azJSONModel.ResourceName
if resourceName == "" {
resourceName = extractResourceNameFromMetricsURL(azureURL)
if azJSONModel.ResourceName == "" {
azJSONModel.ResourceName = extractResourceNameFromMetricsURL(azureURL)
}
urlComponents := map[string]string{}
urlComponents["resourceURI"] = azJSONModel.ResourceURI
// Legacy fields used for constructing a deep link to display the query in Azure Portal.
urlComponents["subscription"] = queryJSONModel.Subscription
urlComponents["resourceGroup"] = azJSONModel.ResourceGroup
urlComponents["metricDefinition"] = azJSONModel.MetricDefinition
urlComponents["resourceName"] = resourceName
alias := azJSONModel.Alias
timeGrain := azJSONModel.TimeGrain
@@ -156,13 +151,14 @@ func (e *AzureMonitorDatasource) buildQueries(queries []backend.DataQuery, dsInf
}
azureMonitorQueries = append(azureMonitorQueries, &types.AzureMonitorQuery{
URL: azureURL,
UrlComponents: urlComponents,
Target: target,
Params: params,
RefID: query.RefID,
Alias: alias,
TimeRange: query.TimeRange,
ResourceName: azJSONModel.ResourceName,
ResourceURI: ub.buildResourceURI(),
URL: azureURL,
Target: target,
Params: params,
RefID: query.RefID,
Alias: alias,
TimeRange: query.TimeRange,
})
}
@@ -288,7 +284,7 @@ func (e *AzureMonitorDatasource) parseResponse(amr types.AzureMonitorResponse, q
})
}
if query.Alias != "" {
displayName := formatAzureMonitorLegendKey(query.Alias, query.UrlComponents["resourceName"],
displayName := formatAzureMonitorLegendKey(query.Alias, query.ResourceName,
amr.Value[0].Name.LocalizedValue, "", "", amr.Namespace, amr.Value[0].ID, labels)
if dataField.Config != nil {
@@ -353,32 +349,20 @@ func getQueryUrl(query *types.AzureMonitorQuery, azurePortalUrl string) (string,
}
escapedTime := url.QueryEscape(string(timespan))
id := query.UrlComponents["resourceURI"]
if id == "" {
ub := urlBuilder{
Subscription: query.UrlComponents["subscription"],
ResourceGroup: query.UrlComponents["resourceGroup"],
MetricDefinition: query.UrlComponents["metricDefinition"],
ResourceName: query.UrlComponents["resourceName"],
}
id = ub.buildResourceURIFromLegacyQuery()
}
chartDef, err := json.Marshal(map[string]interface{}{
"v2charts": []interface{}{
map[string]interface{}{
"metrics": []types.MetricChartDefinition{
{
ResourceMetadata: map[string]string{
"id": id,
"id": query.ResourceURI,
},
Name: query.Params.Get("metricnames"),
AggregationType: aggregationType,
Namespace: query.Params.Get("metricnamespace"),
MetricVisualization: types.MetricVisualization{
DisplayName: query.Params.Get("metricnames"),
ResourceDisplayName: query.UrlComponents["resourceName"],
ResourceDisplayName: query.ResourceName,
},
},
},
@@ -414,7 +398,7 @@ func formatAzureMonitorLegendKey(alias string, resourceName string, metricName s
for k := range lowerLabels {
keys = append(keys, k)
}
keys = sort.StringSlice(keys)
sort.Strings(keys)
result := types.LegendKeyFormat.ReplaceAllFunc([]byte(alias), func(in []byte) []byte {
metaPartName := strings.Replace(string(in), "{{", "", 1)
@@ -51,7 +51,7 @@ func TestAzureMonitorBuildQueries(t *testing.T) {
},
resourceURI: "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana",
expectedInterval: "PT1M",
azureMonitorQueryTarget: "aggregation=Average&api-version=2018-01-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute-virtualMachines&timespan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z",
azureMonitorQueryTarget: "aggregation=Average&api-version=2018-01-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute%2FvirtualMachines&timespan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z",
},
{
name: "legacy query without resourceURI and time grain set to auto",
@@ -61,7 +61,7 @@ func TestAzureMonitorBuildQueries(t *testing.T) {
},
queryInterval: duration,
expectedInterval: "PT15M",
azureMonitorQueryTarget: "aggregation=Average&api-version=2018-01-01&interval=PT15M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute-virtualMachines&timespan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z",
azureMonitorQueryTarget: "aggregation=Average&api-version=2018-01-01&interval=PT15M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute%2FvirtualMachines&timespan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z",
},
{
name: "legacy query without resourceURI and time grain set to auto",
@@ -72,7 +72,7 @@ func TestAzureMonitorBuildQueries(t *testing.T) {
},
queryInterval: duration,
expectedInterval: "PT5M",
azureMonitorQueryTarget: "aggregation=Average&api-version=2018-01-01&interval=PT5M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute-virtualMachines&timespan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z",
azureMonitorQueryTarget: "aggregation=Average&api-version=2018-01-01&interval=PT5M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute%2FvirtualMachines&timespan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z",
},
{
name: "legacy query without resourceURI and has a dimension filter",
@@ -84,7 +84,7 @@ func TestAzureMonitorBuildQueries(t *testing.T) {
},
queryInterval: duration,
expectedInterval: "PT1M",
azureMonitorQueryTarget: "%24filter=blob+eq+%27%2A%27&aggregation=Average&api-version=2018-01-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute-virtualMachines&timespan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z&top=30",
azureMonitorQueryTarget: "%24filter=blob+eq+%27%2A%27&aggregation=Average&api-version=2018-01-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute%2FvirtualMachines&timespan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z&top=30",
},
{
name: "legacy query without resourceURI and has a dimension filter and none Dimension",
@@ -96,7 +96,7 @@ func TestAzureMonitorBuildQueries(t *testing.T) {
},
queryInterval: duration,
expectedInterval: "PT1M",
azureMonitorQueryTarget: "aggregation=Average&api-version=2018-01-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute-virtualMachines&timespan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z",
azureMonitorQueryTarget: "aggregation=Average&api-version=2018-01-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute%2FvirtualMachines&timespan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z",
},
{
name: "legacy query without resourceURI and has dimensionFilter*s* property with one dimension",
@@ -107,7 +107,7 @@ func TestAzureMonitorBuildQueries(t *testing.T) {
},
queryInterval: duration,
expectedInterval: "PT1M",
azureMonitorQueryTarget: "%24filter=blob+eq+%27%2A%27&aggregation=Average&api-version=2018-01-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute-virtualMachines&timespan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z&top=30",
azureMonitorQueryTarget: "%24filter=blob+eq+%27%2A%27&aggregation=Average&api-version=2018-01-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute%2FvirtualMachines&timespan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z&top=30",
},
{
name: "legacy query without resourceURI and has dimensionFilter*s* property with two dimensions",
@@ -118,7 +118,7 @@ func TestAzureMonitorBuildQueries(t *testing.T) {
},
queryInterval: duration,
expectedInterval: "PT1M",
azureMonitorQueryTarget: "%24filter=blob+eq+%27%2A%27+and+tier+eq+%27%2A%27&aggregation=Average&api-version=2018-01-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute-virtualMachines&timespan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z&top=30",
azureMonitorQueryTarget: "%24filter=blob+eq+%27%2A%27+and+tier+eq+%27%2A%27&aggregation=Average&api-version=2018-01-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute%2FvirtualMachines&timespan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z&top=30",
},
{
name: "legacy query without resourceURI and has a dimension filter without specifying a top",
@@ -129,7 +129,7 @@ func TestAzureMonitorBuildQueries(t *testing.T) {
},
queryInterval: duration,
expectedInterval: "PT1M",
azureMonitorQueryTarget: "%24filter=blob+eq+%27%2A%27&aggregation=Average&api-version=2018-01-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute-virtualMachines&timespan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z",
azureMonitorQueryTarget: "%24filter=blob+eq+%27%2A%27&aggregation=Average&api-version=2018-01-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute%2FvirtualMachines&timespan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z",
},
{
name: "has dimensionFilter*s* property with not equals operator",
@@ -140,7 +140,7 @@ func TestAzureMonitorBuildQueries(t *testing.T) {
},
queryInterval: duration,
expectedInterval: "PT1M",
azureMonitorQueryTarget: "%24filter=blob+ne+%27test%27&aggregation=Average&api-version=2018-01-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute-virtualMachines&timespan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z&top=30",
azureMonitorQueryTarget: "%24filter=blob+ne+%27test%27&aggregation=Average&api-version=2018-01-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute%2FvirtualMachines&timespan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z&top=30",
},
{
name: "has dimensionFilter*s* property with startsWith operator",
@@ -151,7 +151,7 @@ func TestAzureMonitorBuildQueries(t *testing.T) {
},
queryInterval: duration,
expectedInterval: "PT1M",
azureMonitorQueryTarget: "%24filter=blob+sw+%27test%27&aggregation=Average&api-version=2018-01-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute-virtualMachines&timespan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z&top=30",
azureMonitorQueryTarget: "%24filter=blob+sw+%27test%27&aggregation=Average&api-version=2018-01-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute%2FvirtualMachines&timespan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z&top=30",
},
{
name: "correctly sets dimension operator to eq (irrespective of operator) when filter value is '*'",
@@ -162,7 +162,7 @@ func TestAzureMonitorBuildQueries(t *testing.T) {
},
queryInterval: duration,
expectedInterval: "PT1M",
azureMonitorQueryTarget: "%24filter=blob+eq+%27%2A%27+and+tier+eq+%27%2A%27&aggregation=Average&api-version=2018-01-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute-virtualMachines&timespan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z&top=30",
azureMonitorQueryTarget: "%24filter=blob+eq+%27%2A%27+and+tier+eq+%27%2A%27&aggregation=Average&api-version=2018-01-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute%2FvirtualMachines&timespan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z&top=30",
},
{
name: "correctly constructs target when multiple filter values are provided for the 'eq' operator",
@@ -173,7 +173,7 @@ func TestAzureMonitorBuildQueries(t *testing.T) {
},
queryInterval: duration,
expectedInterval: "PT1M",
azureMonitorQueryTarget: "%24filter=blob+eq+%27test%27+or+blob+eq+%27test2%27&aggregation=Average&api-version=2018-01-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute-virtualMachines&timespan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z&top=30",
azureMonitorQueryTarget: "%24filter=blob+eq+%27test%27+or+blob+eq+%27test2%27&aggregation=Average&api-version=2018-01-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute%2FvirtualMachines&timespan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z&top=30",
},
{
name: "correctly constructs target when multiple filter values are provided for ne 'eq' operator",
@@ -184,17 +184,16 @@ func TestAzureMonitorBuildQueries(t *testing.T) {
},
queryInterval: duration,
expectedInterval: "PT1M",
azureMonitorQueryTarget: "%24filter=blob+ne+%27test%27+and+blob+ne+%27test2%27&aggregation=Average&api-version=2018-01-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute-virtualMachines&timespan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z&top=30",
azureMonitorQueryTarget: "%24filter=blob+ne+%27test%27+and+blob+ne+%27test2%27&aggregation=Average&api-version=2018-01-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute%2FvirtualMachines&timespan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z&top=30",
},
}
commonAzureModelProps := map[string]interface{}{
"aggregation": "Average",
"resourceGroup": "grafanastaging",
"resourceName": "grafana",
"metricDefinition": "Microsoft.Compute/virtualMachines",
"metricNamespace": "Microsoft.Compute-virtualMachines",
"metricName": "Percentage CPU",
"aggregation": "Average",
"resourceGroup": "grafanastaging",
"resourceName": "grafana",
"metricNamespace": "Microsoft.Compute/virtualMachines",
"metricName": "Percentage CPU",
"alias": "testalias",
"queryType": "Azure Monitor",
@@ -222,17 +221,12 @@ func TestAzureMonitorBuildQueries(t *testing.T) {
}
azureMonitorQuery := &types.AzureMonitorQuery{
URL: "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana/providers/microsoft.insights/metrics",
UrlComponents: map[string]string{
"resourceURI": tt.resourceURI,
"metricDefinition": "Microsoft.Compute/virtualMachines",
"resourceGroup": "grafanastaging",
"resourceName": "grafana",
"subscription": "12345678-aaaa-bbbb-cccc-123456789abc",
},
Target: tt.azureMonitorQueryTarget,
RefID: "A",
Alias: "testalias",
ResourceName: "grafana",
ResourceURI: "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana",
URL: "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana/providers/microsoft.insights/metrics",
Target: tt.azureMonitorQueryTarget,
RefID: "A",
Alias: "testalias",
TimeRange: backend.TimeRange{
From: fromStart,
To: fromStart.Add(34 * time.Minute),
@@ -248,7 +242,7 @@ func TestAzureMonitorBuildQueries(t *testing.T) {
expected := `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%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-virtualMachines%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22Percentage%20CPU%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D`
`%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`
actual, err := getQueryUrl(queries[0], "http://ds")
require.NoError(t, err)
require.Equal(t, expected, actual)
@@ -300,10 +294,8 @@ func TestAzureMonitorParseResponse(t *testing.T) {
name: "average aggregate time series response",
responseFile: "1-azure-monitor-response-avg.json",
mockQuery: &types.AzureMonitorQuery{
UrlComponents: map[string]string{
"resourceName": "grafana",
"resourceURI": "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana",
},
ResourceName: "grafana",
ResourceURI: "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana",
Params: url.Values{
"aggregation": {"Average"},
},
@@ -322,10 +314,8 @@ func TestAzureMonitorParseResponse(t *testing.T) {
name: "total aggregate time series response",
responseFile: "2-azure-monitor-response-total.json",
mockQuery: &types.AzureMonitorQuery{
UrlComponents: map[string]string{
"resourceName": "grafana",
"resourceURI": "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana",
},
ResourceName: "grafana",
ResourceURI: "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana",
Params: url.Values{
"aggregation": {"Total"},
},
@@ -344,10 +334,8 @@ func TestAzureMonitorParseResponse(t *testing.T) {
name: "maximum aggregate time series response",
responseFile: "3-azure-monitor-response-maximum.json",
mockQuery: &types.AzureMonitorQuery{
UrlComponents: map[string]string{
"resourceName": "grafana",
"resourceURI": "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana",
},
ResourceName: "grafana",
ResourceURI: "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana",
Params: url.Values{
"aggregation": {"Maximum"},
},
@@ -366,10 +354,8 @@ func TestAzureMonitorParseResponse(t *testing.T) {
name: "minimum aggregate time series response",
responseFile: "4-azure-monitor-response-minimum.json",
mockQuery: &types.AzureMonitorQuery{
UrlComponents: map[string]string{
"resourceName": "grafana",
"resourceURI": "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana",
},
ResourceName: "grafana",
ResourceURI: "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana",
Params: url.Values{
"aggregation": {"Minimum"},
},
@@ -388,10 +374,8 @@ func TestAzureMonitorParseResponse(t *testing.T) {
name: "count aggregate time series response",
responseFile: "5-azure-monitor-response-count.json",
mockQuery: &types.AzureMonitorQuery{
UrlComponents: map[string]string{
"resourceName": "grafana",
"resourceURI": "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana",
},
ResourceName: "grafana",
ResourceURI: "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana",
Params: url.Values{
"aggregation": {"Count"},
},
@@ -410,10 +394,8 @@ func TestAzureMonitorParseResponse(t *testing.T) {
name: "single dimension time series response",
responseFile: "6-azure-monitor-response-single-dimension.json",
mockQuery: &types.AzureMonitorQuery{
UrlComponents: map[string]string{
"resourceName": "grafana",
"resourceURI": "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana",
},
ResourceName: "grafana",
ResourceURI: "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana",
Params: url.Values{
"aggregation": {"Average"},
},
@@ -445,11 +427,9 @@ func TestAzureMonitorParseResponse(t *testing.T) {
name: "with alias patterns in the query",
responseFile: "2-azure-monitor-response-total.json",
mockQuery: &types.AzureMonitorQuery{
Alias: "custom {{resourcegroup}} {{namespace}} {{resourceName}} {{metric}}",
UrlComponents: map[string]string{
"resourceName": "grafana",
"resourceURI": "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana",
},
ResourceName: "grafana",
ResourceURI: "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana",
Alias: "custom {{resourcegroup}} {{namespace}} {{resourceName}} {{metric}}",
Params: url.Values{
"aggregation": {"Total"},
},
@@ -468,11 +448,9 @@ func TestAzureMonitorParseResponse(t *testing.T) {
name: "single dimension with alias",
responseFile: "6-azure-monitor-response-single-dimension.json",
mockQuery: &types.AzureMonitorQuery{
Alias: "{{dimensionname}}={{DimensionValue}}",
UrlComponents: map[string]string{
"resourceName": "grafana",
"resourceURI": "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana",
},
ResourceName: "grafana",
ResourceURI: "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana",
Alias: "{{dimensionname}}={{DimensionValue}}",
Params: url.Values{
"aggregation": {"Average"},
},
@@ -506,11 +484,9 @@ func TestAzureMonitorParseResponse(t *testing.T) {
name: "multiple dimension time series response with label alias",
responseFile: "7-azure-monitor-response-multi-dimension.json",
mockQuery: &types.AzureMonitorQuery{
Alias: "{{resourcegroup}} {Blob Type={{blobtype}}, Tier={{Tier}}}",
UrlComponents: map[string]string{
"resourceName": "grafana",
"resourceURI": "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana",
},
ResourceName: "grafana",
ResourceURI: "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana",
Alias: "{{resourcegroup}} {Blob Type={{blobtype}}, Tier={{Tier}}}",
Params: url.Values{
"aggregation": {"Average"},
},
@@ -545,11 +521,9 @@ func TestAzureMonitorParseResponse(t *testing.T) {
name: "unspecified unit with alias should not panic",
responseFile: "8-azure-monitor-response-unspecified-unit.json",
mockQuery: &types.AzureMonitorQuery{
Alias: "custom",
UrlComponents: map[string]string{
"resourceName": "grafana",
"resourceURI": "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana",
},
ResourceName: "grafana",
ResourceURI: "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana",
Alias: "custom",
Params: url.Values{
"aggregation": {"Average"},
},
@@ -568,13 +542,9 @@ func TestAzureMonitorParseResponse(t *testing.T) {
name: "with legacy azure monitor query properties and without a resource uri",
responseFile: "2-azure-monitor-response-total.json",
mockQuery: &types.AzureMonitorQuery{
Alias: "custom {{resourcegroup}} {{namespace}} {{resourceName}} {{metric}}",
UrlComponents: map[string]string{
"subscription": "12345678-aaaa-bbbb-cccc-123456789abc",
"resourceGroup": "grafanastaging",
"metricDefinition": "Microsoft.Compute/virtualMachines",
"resourceName": "grafana",
},
ResourceName: "grafana",
ResourceURI: "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana",
Alias: "custom {{resourcegroup}} {{namespace}} {{resourceName}} {{metric}}",
Params: url.Values{
"aggregation": {"Total"},
},
@@ -593,14 +563,9 @@ func TestAzureMonitorParseResponse(t *testing.T) {
name: "with legacy azure monitor query properties and with a resource uri it should use the resource uri",
responseFile: "2-azure-monitor-response-total.json",
mockQuery: &types.AzureMonitorQuery{
Alias: "custom {{resourcegroup}} {{namespace}} {{resourceName}} {{metric}}",
UrlComponents: map[string]string{
"resourceURI": "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana",
"subscription": "12345678-aaaa-bbbb-cccc-123456789abc-nope",
"resourceGroup": "grafanastaging-nope",
"metricDefinition": "Microsoft.Compute/virtualMachines-nope",
"resourceName": "grafana",
},
ResourceName: "grafana",
ResourceURI: "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana",
Alias: "custom {{resourcegroup}} {{namespace}} {{resourceName}} {{metric}}",
Params: url.Values{
"aggregation": {"Total"},
},
+14 -11
View File
@@ -9,26 +9,29 @@ import (
type urlBuilder struct {
ResourceURI string
// Following fields will be deprecated in grafana 9 and will not included in new queries.
// For backwards compat, we recreate the ResourceURI using these fields
// Following fields will be used to generate a ResourceURI
DefaultSubscription string
Subscription string
ResourceGroup string
MetricDefinition string
MetricNamespace string
ResourceName string
}
func (params *urlBuilder) buildResourceURIFromLegacyQuery() string {
func (params *urlBuilder) buildResourceURI() string {
if params.ResourceURI != "" {
return params.ResourceURI
}
subscription := params.Subscription
if params.Subscription == "" {
subscription = params.DefaultSubscription
}
metricDefinitionArray := strings.Split(params.MetricDefinition, "/")
metricNamespaceArray := strings.Split(params.MetricNamespace, "/")
resourceNameArray := strings.Split(params.ResourceName, "/")
provider := metricDefinitionArray[0]
metricDefinitionArray = metricDefinitionArray[1:]
provider := metricNamespaceArray[0]
metricNamespaceArray = metricNamespaceArray[1:]
urlArray := []string{
"/subscriptions",
@@ -39,22 +42,22 @@ func (params *urlBuilder) buildResourceURIFromLegacyQuery() string {
provider,
}
for i, metricDefinition := range metricDefinitionArray {
urlArray = append(urlArray, metricDefinition, resourceNameArray[i])
for i, namespace := range metricNamespaceArray {
urlArray = append(urlArray, namespace, resourceNameArray[i])
}
resourceURI := strings.Join(urlArray, "/")
return resourceURI
}
// BuildMetricsURL checks the metric definition property to see which form of the url
// BuildMetricsURL checks the metric properties to see which form of the url
// should be returned
func (params *urlBuilder) BuildMetricsURL() string {
resourceURI := params.ResourceURI
// Prior to Grafana 9, we had a legacy query object rather than a resourceURI, so we manually create the resource URI
if resourceURI == "" {
resourceURI = params.buildResourceURIFromLegacyQuery()
resourceURI = params.buildResourceURI()
}
return fmt.Sprintf("%s/providers/microsoft.insights/metrics", resourceURI)
@@ -22,7 +22,7 @@ func TestURLBuilder(t *testing.T) {
ResourceURI: "/subscriptions/sub/resource/uri",
DefaultSubscription: "default-sub",
ResourceGroup: "rg",
MetricDefinition: "Microsoft.NetApp/netAppAccounts/capacityPools/volumes",
MetricNamespace: "Microsoft.NetApp/netAppAccounts/capacityPools/volumes",
ResourceName: "rn1/rn2/rn3",
}
@@ -35,7 +35,7 @@ func TestURLBuilder(t *testing.T) {
ub := &urlBuilder{
DefaultSubscription: "default-sub",
ResourceGroup: "rg",
MetricDefinition: "Microsoft.Compute/virtualMachines",
MetricNamespace: "Microsoft.Compute/virtualMachines",
ResourceName: "rn",
}
@@ -48,7 +48,7 @@ func TestURLBuilder(t *testing.T) {
DefaultSubscription: "default-sub",
Subscription: "specified-sub",
ResourceGroup: "rg",
MetricDefinition: "Microsoft.Compute/virtualMachines",
MetricNamespace: "Microsoft.Compute/virtualMachines",
ResourceName: "rn",
}
@@ -60,7 +60,7 @@ func TestURLBuilder(t *testing.T) {
ub := &urlBuilder{
DefaultSubscription: "default-sub",
ResourceGroup: "rg",
MetricDefinition: "Microsoft.Storage/storageAccounts/blobServices",
MetricNamespace: "Microsoft.Storage/storageAccounts/blobServices",
ResourceName: "rn1/default",
}
@@ -72,7 +72,7 @@ func TestURLBuilder(t *testing.T) {
ub := &urlBuilder{
DefaultSubscription: "default-sub",
ResourceGroup: "rg",
MetricDefinition: "Microsoft.Storage/storageAccounts/fileServices",
MetricNamespace: "Microsoft.Storage/storageAccounts/fileServices",
ResourceName: "rn1/default",
}
@@ -84,7 +84,7 @@ func TestURLBuilder(t *testing.T) {
ub := &urlBuilder{
DefaultSubscription: "default-sub",
ResourceGroup: "rg",
MetricDefinition: "Microsoft.NetApp/netAppAccounts/capacityPools/volumes",
MetricNamespace: "Microsoft.NetApp/netAppAccounts/capacityPools/volumes",
ResourceName: "rn1/rn2/rn3",
}
+15 -17
View File
@@ -54,13 +54,14 @@ type DatasourceInfo struct {
// AzureMonitorQuery is the query for all the services as they have similar queries
// with a url, a querystring and an alias field
type AzureMonitorQuery struct {
URL string
UrlComponents map[string]string
Target string
Params url.Values
RefID string
Alias string
TimeRange backend.TimeRange
ResourceName string
ResourceURI string
URL string
Target string
Params url.Values
RefID string
Alias string
TimeRange backend.TimeRange
}
// AzureMonitorResponse is the json response from the Azure Monitor API
@@ -111,9 +112,12 @@ type AzureResponseTable struct {
// AzureMonitorJSONQuery is the frontend JSON query model for an Azure Monitor query.
type AzureMonitorJSONQuery struct {
AzureMonitor struct {
ResourceURI string `json:"resourceUri"`
ResourceURI string `json:"resourceUri"`
// These are used to reconstruct a resource URI
MetricNamespace string `json:"metricNamespace"`
MetricName string `json:"metricName"`
ResourceGroup string `json:"resourceGroup"`
ResourceName string `json:"resourceName"`
Aggregation string `json:"aggregation"`
Alias string `json:"alias"`
@@ -121,19 +125,13 @@ type AzureMonitorJSONQuery struct {
TimeGrain string `json:"timeGrain"`
Top string `json:"top"`
// Legecy "resource" fields from before the resource picker provided just a single ResourceURI
// These are used for pre-resource picker queries to reconstruct a resource URI
// Deprecated
MetricDefinition string `json:"metricDefinition"`
// Deprecated
ResourceGroup string `json:"resourceGroup"`
// Deprecated
ResourceName string `json:"resourceName"`
AllowedTimeGrainsMs []int64 `json:"allowedTimeGrainsMs"`
Dimension string `json:"dimension"` // old model
DimensionFilter string `json:"dimensionFilter"` // old model
Format string `json:"format"`
// Deprecated, MetricNamespace should be used instead
MetricDefinition string `json:"metricDefinition"`
} `json:"azureMonitor"`
Subscription string `json:"subscription"`
}
@@ -30,7 +30,6 @@ export default function createMockDatasource(overrides?: DeepPartial<Datasource>
getSubscriptions: jest.fn().mockResolvedValue([]),
getResourceGroups: jest.fn().mockResolvedValueOnce([]),
getMetricDefinitions: jest.fn().mockResolvedValueOnce([]),
getResourceNames: jest.fn().mockResolvedValueOnce([]),
azureLogAnalyticsDatasource: {
@@ -35,7 +35,6 @@ export default function createMockQuery(overrides?: Partial<AzureMonitorQuery>):
allowedTimeGrainsMs: [60000, 300000, 900000, 1800000, 3600000, 21600000, 43200000, 86400000],
// dimensionFilter: '*',
dimensionFilters: [],
metricDefinition: 'Microsoft.Compute/virtualMachines',
metricName: 'Metric A',
metricNamespace: 'Microsoft.Compute/virtualMachines',
resourceGroup: 'grafanastaging',
@@ -34,6 +34,23 @@ describe('AzureMonitorDatasource', () => {
ctx.ds = new AzureMonitorDatasource(ctx.instanceSettings);
});
describe('applyTemplateVariables', () => {
it('should migrate metricDefinition to metricNamespace', () => {
const query = createMockQuery({
azureMonitor: {
metricNamespace: undefined,
metricDefinition: 'microsoft.insights/components',
},
});
const templatedQuery = ctx.ds.azureMonitorDatasource.applyTemplateVariables(query, {});
expect(templatedQuery).toMatchObject({
azureMonitor: {
metricNamespace: 'microsoft.insights/components',
},
});
});
});
describe('When performing getMetricNamespaces', () => {
const response = {
value: [
@@ -128,18 +145,18 @@ describe('AzureMonitorDatasource', () => {
const expected =
basePath +
'/providers/microsoft.insights/components/resource1' +
'/providers/microsoft.insights/metricdefinitions?api-version=2018-01-01&metricnamespace=default';
'/providers/microsoft.insights/metricdefinitions?api-version=2018-01-01&metricnamespace=microsoft.insights%2Fcomponents';
expect(path).toBe(expected);
return Promise.resolve(response);
});
});
it('should return list of Metric Definitions', () => {
it('should return list of Metric Names', () => {
return ctx.ds.azureMonitorDatasource
.getMetricNames({
resourceUri:
'/subscriptions/mock-subscription-id/resourceGroups/nodeapp/providers/microsoft.insights/components/resource1',
metricNamespace: 'default',
metricNamespace: 'microsoft.insights/components',
})
.then((results: Array<{ text: string; value: string }>) => {
expect(results.length).toEqual(2);
@@ -193,7 +210,7 @@ describe('AzureMonitorDatasource', () => {
const expected =
basePath +
'/providers/microsoft.insights/components/resource1' +
'/providers/microsoft.insights/metricdefinitions?api-version=2018-01-01&metricnamespace=default';
'/providers/microsoft.insights/metricdefinitions?api-version=2018-01-01&metricnamespace=microsoft.insights%2Fcomponents';
expect(path).toBe(expected);
return Promise.resolve(response);
});
@@ -204,7 +221,7 @@ describe('AzureMonitorDatasource', () => {
.getMetricMetadata({
resourceUri:
'/subscriptions/mock-subscription-id/resourceGroups/nodeapp/providers/microsoft.insights/components/resource1',
metricNamespace: 'default',
metricNamespace: 'microsoft.insights/components',
metricName: 'UsedCapacity',
})
.then((results) => {
@@ -232,7 +249,6 @@ describe('AzureMonitorDatasource', () => {
'resourceGroup',
'resourceName',
'metricNamespace',
'metricDefinition',
'timeGrain',
'aggregation',
'top',
@@ -317,74 +333,15 @@ describe('AzureMonitorDatasource', () => {
});
});
describe('When performing getMetricDefinitions', () => {
const response = {
value: [
{
name: 'test',
type: 'Microsoft.Network/networkInterfaces',
},
{
location: 'northeurope',
name: 'northeur',
type: 'Microsoft.Compute/virtualMachines',
},
{
location: 'westcentralus',
name: 'us',
type: 'Microsoft.Compute/virtualMachines',
},
{
name: 'IHaveNoMetrics',
type: 'IShouldBeFilteredOut',
},
{
name: 'storageTest',
type: 'Microsoft.Storage/storageAccounts',
},
],
};
beforeEach(() => {
ctx.ds.azureMonitorDatasource.getResource = jest.fn().mockImplementation((path: string) => {
const basePath = 'azuremonitor/subscriptions/mock-subscription-id/resourceGroups';
expect(path).toBe(basePath + '/nodesapp/resources?api-version=2021-04-01');
return Promise.resolve(response);
});
});
it('should return list of Metric Definitions with no duplicates and no unsupported namespaces', () => {
return ctx.ds
.getMetricDefinitions('mock-subscription-id', 'nodesapp')
.then((results: Array<{ text: string; value: string }>) => {
expect(results.length).toEqual(7);
expect(results[0].text).toEqual('Network interfaces');
expect(results[0].value).toEqual('Microsoft.Network/networkInterfaces');
expect(results[1].text).toEqual('Virtual machines');
expect(results[1].value).toEqual('Microsoft.Compute/virtualMachines');
expect(results[2].text).toEqual('Storage accounts');
expect(results[2].value).toEqual('Microsoft.Storage/storageAccounts');
expect(results[3].text).toEqual('Microsoft.Storage/storageAccounts/blobServices');
expect(results[3].value).toEqual('Microsoft.Storage/storageAccounts/blobServices');
expect(results[4].text).toEqual('Microsoft.Storage/storageAccounts/fileServices');
expect(results[4].value).toEqual('Microsoft.Storage/storageAccounts/fileServices');
expect(results[5].text).toEqual('Microsoft.Storage/storageAccounts/tableServices');
expect(results[5].value).toEqual('Microsoft.Storage/storageAccounts/tableServices');
expect(results[6].text).toEqual('Microsoft.Storage/storageAccounts/queueServices');
expect(results[6].value).toEqual('Microsoft.Storage/storageAccounts/queueServices');
});
});
});
describe('When performing getResourceNames', () => {
let subscription = 'mock-subscription-id';
let resourceGroup = 'nodeapp';
let metricDefinition = 'microsoft.insights/components';
let metricNamespace = 'microsoft.insights/components';
beforeEach(() => {
subscription = 'mock-subscription-id';
resourceGroup = 'nodeapp';
metricDefinition = 'microsoft.insights/components';
metricNamespace = 'microsoft.insights/components';
});
describe('and there are no special cases', () => {
@@ -396,7 +353,7 @@ describe('AzureMonitorDatasource', () => {
},
{
name: resourceGroup,
type: metricDefinition,
type: metricNamespace,
},
],
};
@@ -405,7 +362,7 @@ describe('AzureMonitorDatasource', () => {
ctx.ds.azureMonitorDatasource.getResource = jest.fn().mockImplementation((path: string) => {
const basePath = `azuremonitor/subscriptions/${subscription}/resourceGroups`;
expect(path).toBe(
`${basePath}/${resourceGroup}/resources?api-version=2021-04-01&$filter=resourceType eq '${metricDefinition}'`
`${basePath}/${resourceGroup}/resources?api-version=2021-04-01&$filter=resourceType eq '${metricNamespace}'`
);
return Promise.resolve(response);
});
@@ -413,7 +370,7 @@ describe('AzureMonitorDatasource', () => {
it('should return list of Resource Names', () => {
return ctx.ds
.getResourceNames(subscription, resourceGroup, metricDefinition)
.getResourceNames(subscription, resourceGroup, metricNamespace)
.then((results: Array<{ text: string; value: string }>) => {
expect(results.length).toEqual(1);
expect(results[0].text).toEqual('nodeapp');
@@ -422,9 +379,9 @@ describe('AzureMonitorDatasource', () => {
});
it('should return ignore letter case', () => {
metricDefinition = 'microsoft.insights/Components';
metricNamespace = 'microsoft.insights/Components';
return ctx.ds
.getResourceNames(subscription, resourceGroup, metricDefinition)
.getResourceNames(subscription, resourceGroup, metricNamespace)
.then((results: Array<{ text: string; value: string }>) => {
expect(results.length).toEqual(1);
expect(results[0].text).toEqual('nodeapp');
@@ -448,26 +405,26 @@ describe('AzureMonitorDatasource', () => {
};
it('should return list of Resource Names', () => {
metricDefinition = 'Microsoft.Storage/storageAccounts/blobServices';
const validMetricDefinition = startsWith(metricDefinition, 'Microsoft.Storage/storageAccounts/')
metricNamespace = 'Microsoft.Storage/storageAccounts/blobServices';
const validMetricNamespace = startsWith(metricNamespace, 'Microsoft.Storage/storageAccounts/')
? 'Microsoft.Storage/storageAccounts'
: metricDefinition;
: metricNamespace;
ctx.ds.azureMonitorDatasource.getResource = jest.fn().mockImplementation((path: string) => {
const basePath = `azuremonitor/subscriptions/${subscription}/resourceGroups`;
expect(path).toBe(
basePath +
`/${resourceGroup}/resources?api-version=2021-04-01&$filter=resourceType eq '${validMetricDefinition}'`
`/${resourceGroup}/resources?api-version=2021-04-01&$filter=resourceType eq '${validMetricNamespace}'`
);
return Promise.resolve(response);
});
return ctx.ds
.getResourceNames(subscription, resourceGroup, metricDefinition)
.getResourceNames(subscription, resourceGroup, metricNamespace)
.then((results: Array<{ text: string; value: string }>) => {
expect(results.length).toEqual(1);
expect(results[0].text).toEqual('storagetest/default');
expect(results[0].value).toEqual('storagetest/default');
expect(ctx.ds.azureMonitorDatasource.getResource).toHaveBeenCalledWith(
`azuremonitor/subscriptions/${subscription}/resourceGroups/${resourceGroup}/resources?api-version=2021-04-01&$filter=resourceType eq '${validMetricDefinition}'`
`azuremonitor/subscriptions/${subscription}/resourceGroups/${resourceGroup}/resources?api-version=2021-04-01&$filter=resourceType eq '${validMetricNamespace}'`
);
});
});
@@ -479,7 +436,7 @@ describe('AzureMonitorDatasource', () => {
value: [
{
name: `${resourceGroup}1`,
type: metricDefinition,
type: metricNamespace,
},
],
nextLink: `https://management.azure.com/resourceuri?$skiptoken=${skipToken}`,
@@ -488,7 +445,7 @@ describe('AzureMonitorDatasource', () => {
value: [
{
name: `${resourceGroup}2`,
type: metricDefinition,
type: metricNamespace,
},
],
};
@@ -497,7 +454,7 @@ describe('AzureMonitorDatasource', () => {
const fn = jest.fn();
ctx.ds.azureMonitorDatasource.getResource = fn;
const basePath = `azuremonitor/subscriptions/${subscription}/resourceGroups`;
const expectedPath = `${basePath}/${resourceGroup}/resources?api-version=2021-04-01&$filter=resourceType eq '${metricDefinition}'`;
const expectedPath = `${basePath}/${resourceGroup}/resources?api-version=2021-04-01&$filter=resourceType eq '${metricNamespace}'`;
// first page
fn.mockImplementationOnce((path: string) => {
expect(path).toBe(expectedPath);
@@ -512,7 +469,7 @@ describe('AzureMonitorDatasource', () => {
it('should return list of Resource Names', () => {
return ctx.ds
.getResourceNames(subscription, resourceGroup, metricDefinition)
.getResourceNames(subscription, resourceGroup, metricNamespace)
.then((results: Array<{ text: string; value: string }>) => {
expect(results.length).toEqual(2);
expect(results[0].value).toEqual(`${resourceGroup}1`);
@@ -530,7 +487,7 @@ describe('AzureMonitorDatasource', () => {
},
{
name: resourceGroup,
type: metricDefinition,
type: metricNamespace,
},
],
};
@@ -593,7 +550,7 @@ describe('AzureMonitorDatasource', () => {
const expected =
basePath +
'/providers/microsoft.insights/components/resource1' +
'/providers/microsoft.insights/metricdefinitions?api-version=2018-01-01&metricnamespace=default';
'/providers/microsoft.insights/metricdefinitions?api-version=2018-01-01&metricnamespace=microsoft.insights%2Fcomponents';
expect(path).toBe(expected);
return Promise.resolve(response);
});
@@ -604,9 +561,8 @@ describe('AzureMonitorDatasource', () => {
.getMetricNames({
subscription: 'mock-subscription-id',
resourceGroup: 'nodeapp',
metricDefinition: 'microsoft.insights/components',
metricNamespace: 'microsoft.insights/components',
resourceName: 'resource1',
metricNamespace: 'default',
})
.then((results: Array<{ text: string; value: string }>) => {
expect(results.length).toEqual(2);
@@ -660,7 +616,7 @@ describe('AzureMonitorDatasource', () => {
const expected =
basePath +
'/providers/microsoft.insights/components/resource1' +
'/providers/microsoft.insights/metricdefinitions?api-version=2018-01-01&metricnamespace=default';
'/providers/microsoft.insights/metricdefinitions?api-version=2018-01-01&metricnamespace=microsoft.insights%2Fcomponents';
expect(path).toBe(expected);
return Promise.resolve(response);
});
@@ -671,9 +627,8 @@ describe('AzureMonitorDatasource', () => {
.getMetricMetadata({
subscription: 'mock-subscription-id',
resourceGroup: 'nodeapp',
metricDefinition: 'microsoft.insights/components',
metricNamespace: 'microsoft.insights/components',
resourceName: 'resource1',
metricNamespace: 'default',
metricName: 'UsedCapacity',
})
.then((results) => {
@@ -729,7 +684,7 @@ describe('AzureMonitorDatasource', () => {
const expected =
basePath +
'/providers/microsoft.insights/components/resource1' +
'/providers/microsoft.insights/metricdefinitions?api-version=2018-01-01&metricnamespace=default';
'/providers/microsoft.insights/metricdefinitions?api-version=2018-01-01&metricnamespace=microsoft.insights%2Fcomponents';
expect(path).toBe(expected);
return Promise.resolve(response);
});
@@ -740,9 +695,8 @@ describe('AzureMonitorDatasource', () => {
.getMetricMetadata({
subscription: 'mock-subscription-id',
resourceGroup: 'nodeapp',
metricDefinition: 'microsoft.insights/components',
metricNamespace: 'microsoft.insights/components',
resourceName: 'resource1',
metricNamespace: 'default',
metricName: 'Transactions',
})
.then((results: any) => {
@@ -800,9 +754,8 @@ describe('AzureMonitorDatasource', () => {
.getMetricMetadata({
subscription: 'mock-subscription-id',
resourceGroup: 'nodeapp',
metricDefinition: 'microsoft.insights/components',
metricNamespace: 'microsoft.insights/components',
resourceName: 'resource1',
metricNamespace: 'default',
metricName: 'FreeCapacity',
})
.then((results: any) => {
@@ -4,12 +4,10 @@ import { DataSourceInstanceSettings, ScopedVars } from '@grafana/data';
import { DataSourceWithBackend, getTemplateSrv, TemplateSrv } from '@grafana/runtime';
import { getTimeSrv, TimeSrv } from 'app/features/dashboard/services/TimeSrv';
import { resourceTypeDisplayNames, supportedMetricNamespaces } from '../azureMetadata';
import { getAuthType, getAzureCloud, getAzurePortalUrl } from '../credentials';
import TimegrainConverter from '../time_grain_converter';
import {
AzureDataSourceJsonData,
AzureMonitorMetricDefinitionsResponse,
AzureMonitorMetricNamespacesResponse,
AzureMonitorMetricNamesResponse,
AzureMonitorMetricsMetadataResponse,
@@ -20,8 +18,10 @@ import {
GetMetricNamespacesQuery,
GetMetricNamesQuery,
GetMetricMetadataQuery,
AzureMetricQuery,
} from '../types';
import { routeNames } from '../utils/common';
import migrateQuery from '../utils/migrateQuery';
import ResponseParser from './response_parser';
import UrlBuilder from './url_builder';
@@ -66,7 +66,7 @@ export default class AzureMonitorDatasource extends DataSourceWithBackend<AzureM
const hasLegacyQuery =
hasValue(item?.azureMonitor?.resourceGroup) &&
hasValue(item?.azureMonitor?.resourceName) &&
hasValue(item?.azureMonitor?.metricDefinition);
hasValue(item?.azureMonitor?.metricDefinition || item?.azureMonitor?.metricNamespace);
return !!(
item.hide !== true &&
@@ -96,7 +96,6 @@ export default class AzureMonitorDatasource extends DataSourceWithBackend<AzureM
const resourceGroup = templateSrv.replace(item.resourceGroup, scopedVars);
const resourceName = templateSrv.replace(item.resourceName, scopedVars);
const metricNamespace = templateSrv.replace(item.metricNamespace, scopedVars);
const metricDefinition = templateSrv.replace(item.metricDefinition, scopedVars);
const timeGrain = templateSrv.replace((item.timeGrain || '').toString(), scopedVars);
const aggregation = templateSrv.replace(item.aggregation, scopedVars);
const top = templateSrv.replace(item.top || '', scopedVars);
@@ -112,26 +111,32 @@ export default class AzureMonitorDatasource extends DataSourceWithBackend<AzureM
};
});
return {
...target,
subscription: subscriptionId,
queryType: AzureQueryType.AzureMonitor,
azureMonitor: {
resourceUri,
resourceGroup,
resourceName,
metricDefinition,
timeGrain,
allowedTimeGrainsMs: item.allowedTimeGrainsMs,
metricName: templateSrv.replace(item.metricName, scopedVars),
metricNamespace:
metricNamespace && metricNamespace !== defaultDropdownValue ? metricNamespace : metricDefinition,
aggregation: aggregation,
dimensionFilters,
top: top || '10',
alias: item.alias,
},
const azMonitorQuery: AzureMetricQuery = {
resourceUri,
resourceGroup,
metricNamespace,
resourceName,
timeGrain,
allowedTimeGrainsMs: item.allowedTimeGrainsMs,
metricName: templateSrv.replace(item.metricName, scopedVars),
aggregation: aggregation,
dimensionFilters,
top: top || '10',
alias: item.alias,
};
if (item.metricDefinition) {
azMonitorQuery.metricDefinition = templateSrv.replace(item.metricDefinition, scopedVars);
}
return migrateQuery(
{
...target,
subscription: subscriptionId,
queryType: AzureQueryType.AzureMonitor,
azureMonitor: azMonitorQuery,
},
templateSrv
);
}
async getSubscriptions(): Promise<Array<{ text: string; value: string }>> {
@@ -152,83 +157,31 @@ export default class AzureMonitorDatasource extends DataSourceWithBackend<AzureM
});
}
getMetricDefinitions(subscriptionId: string, resourceGroup: string) {
return this.getResource(
`${this.resourcePath}/subscriptions/${subscriptionId}/resourceGroups/${resourceGroup}/resources?api-version=${this.listByResourceGroupApiVersion}`
)
.then((result: AzureMonitorMetricDefinitionsResponse) => {
return ResponseParser.parseResponseValues(result, 'type', 'type');
})
.then((result) =>
result.filter((t) => {
for (let i = 0; i < supportedMetricNamespaces.length; i++) {
if (t.value.toLowerCase() === supportedMetricNamespaces[i].toLowerCase()) {
return true;
}
}
return false;
})
)
.then((result) => {
let shouldHardcodeBlobStorage = false;
for (let i = 0; i < result.length; i++) {
if (result[i].value === 'Microsoft.Storage/storageAccounts') {
shouldHardcodeBlobStorage = true;
break;
}
}
if (shouldHardcodeBlobStorage) {
result.push({
text: 'Microsoft.Storage/storageAccounts/blobServices',
value: 'Microsoft.Storage/storageAccounts/blobServices',
});
result.push({
text: 'Microsoft.Storage/storageAccounts/fileServices',
value: 'Microsoft.Storage/storageAccounts/fileServices',
});
result.push({
text: 'Microsoft.Storage/storageAccounts/tableServices',
value: 'Microsoft.Storage/storageAccounts/tableServices',
});
result.push({
text: 'Microsoft.Storage/storageAccounts/queueServices',
value: 'Microsoft.Storage/storageAccounts/queueServices',
});
}
return result.map((v) => ({
value: v.value,
text: resourceTypeDisplayNames[v.value.toLowerCase()] || v.value,
}));
});
}
getResourceNames(subscriptionId: string, resourceGroup?: string, metricDefinition?: string, skipToken?: string) {
const validMetricDefinition = startsWith(metricDefinition, 'Microsoft.Storage/storageAccounts/')
getResourceNames(subscriptionId: string, resourceGroup?: string, metricNamespace?: string, skipToken?: string) {
const validMetricNamespace = startsWith(metricNamespace, 'Microsoft.Storage/storageAccounts/')
? 'Microsoft.Storage/storageAccounts'
: metricDefinition;
: metricNamespace;
let url = `${this.resourcePath}/subscriptions/${subscriptionId}`;
if (resourceGroup) {
url += `/resourceGroups/${resourceGroup}`;
}
url += `/resources?api-version=${this.listByResourceGroupApiVersion}`;
if (validMetricDefinition) {
url += `&$filter=resourceType eq '${validMetricDefinition}'`;
if (validMetricNamespace) {
url += `&$filter=resourceType eq '${validMetricNamespace}'`;
}
if (skipToken) {
url += `&$skiptoken=${skipToken}`;
}
return this.getResource(url).then(async (result: any) => {
let list: Array<{ text: string; value: string }> = [];
if (startsWith(metricDefinition, 'Microsoft.Storage/storageAccounts/')) {
if (startsWith(metricNamespace, 'Microsoft.Storage/storageAccounts/')) {
list = ResponseParser.parseResourceNames(result, 'Microsoft.Storage/storageAccounts');
for (let i = 0; i < list.length; i++) {
list[i].text += '/default';
list[i].value += '/default';
}
} else {
list = ResponseParser.parseResourceNames(result, metricDefinition);
list = ResponseParser.parseResourceNames(result, metricNamespace);
}
if (result.nextLink) {
@@ -238,7 +191,7 @@ export default class AzureMonitorDatasource extends DataSourceWithBackend<AzureM
if (!nextToken) {
throw Error('unable to request the next page of resources');
}
const nextPage = await this.getResourceNames(subscriptionId, resourceGroup, metricDefinition, nextToken);
const nextPage = await this.getResourceNames(subscriptionId, resourceGroup, metricNamespace, nextToken);
list = list.concat(nextPage);
}
@@ -33,7 +33,7 @@ export default class ResponseParser {
return list;
}
static parseResourceNames(result: any, metricDefinition?: string): Array<{ text: string; value: string }> {
static parseResourceNames(result: any, metricNamespace?: string): Array<{ text: string; value: string }> {
const list: Array<{ text: string; value: string }> = [];
if (!result) {
@@ -43,7 +43,7 @@ export default class ResponseParser {
for (let i = 0; i < result.value.length; i++) {
if (
typeof result.value[i].type === 'string' &&
(!metricDefinition || result.value[i].type.toLocaleLowerCase() === metricDefinition.toLocaleLowerCase())
(!metricNamespace || result.value[i].type.toLocaleLowerCase() === metricNamespace.toLocaleLowerCase())
) {
list.push({
text: result.value[i].name,
@@ -19,12 +19,12 @@ describe('AzureMonitorUrlBuilder', () => {
describe('buildResourceUri', () => {
it('builds a resource uri when the required properties are provided', () => {
expect(
UrlBuilder.buildResourceUri('sub', 'group', 'Microsoft.NetApp/netAppAccounts', 'name', templateSrv)
UrlBuilder.buildResourceUri('sub', 'group', templateSrv, 'Microsoft.NetApp/netAppAccounts', 'name')
).toEqual('/subscriptions/sub/resourceGroups/group/providers/Microsoft.NetApp/netAppAccounts/name');
});
it('builds a resource uri correctly when a template variable is used as namespace', () => {
expect(UrlBuilder.buildResourceUri('sub', 'group', '$ns', 'name', templateSrv)).toEqual(
expect(UrlBuilder.buildResourceUri('sub', 'group', templateSrv, '$ns', 'name')).toEqual(
'/subscriptions/sub/resourceGroups/group/providers/$ns/name'
);
});
@@ -34,9 +34,9 @@ describe('AzureMonitorUrlBuilder', () => {
UrlBuilder.buildResourceUri(
'sub',
'group',
templateSrv,
'Microsoft.Storage/storageAccounts/tableServices',
'name',
templateSrv
'name'
)
).toEqual(
'/subscriptions/sub/resourceGroups/group/providers/Microsoft.Storage/storageAccounts/name/tableServices/default'
@@ -56,25 +56,25 @@ describe('AzureMonitorUrlBuilder', () => {
templateSrv = getTemplateSrv();
it('builds a resource uri without specifying a subresource (default)', () => {
expect(UrlBuilder.buildResourceUri('sub', 'group', '$ns/tableServices', 'name', templateSrv)).toEqual(
expect(UrlBuilder.buildResourceUri('sub', 'group', templateSrv, '$ns/tableServices', 'name')).toEqual(
'/subscriptions/sub/resourceGroups/group/providers/$ns/name/tableServices/default'
);
});
it('builds a resource uri specifying a subresource (default)', () => {
expect(UrlBuilder.buildResourceUri('sub', 'group', '$ns/tableServices', 'name/default', templateSrv)).toEqual(
expect(UrlBuilder.buildResourceUri('sub', 'group', templateSrv, '$ns/tableServices', 'name/default')).toEqual(
'/subscriptions/sub/resourceGroups/group/providers/$ns/name/tableServices/default'
);
});
it('builds a resource uri specifying a resource template variable', () => {
expect(UrlBuilder.buildResourceUri('sub', 'group', '$ns/tableServices', '$rs/default', templateSrv)).toEqual(
expect(UrlBuilder.buildResourceUri('sub', 'group', templateSrv, '$ns/tableServices', '$rs/default')).toEqual(
'/subscriptions/sub/resourceGroups/group/providers/$ns/$rs/tableServices/default'
);
});
it('builds a resource uri specifying multiple template variables', () => {
expect(UrlBuilder.buildResourceUri('sub', 'group', '$ns/$ns2', '$rs/$rs2', templateSrv)).toEqual(
expect(UrlBuilder.buildResourceUri('sub', 'group', templateSrv, '$ns/$ns2', '$rs/$rs2')).toEqual(
'/subscriptions/sub/resourceGroups/group/providers/$ns/$rs/$ns2/$rs2'
);
});
@@ -123,7 +123,7 @@ describe('AzureMonitorUrlBuilder', () => {
{
subscription: 'sub1',
resourceGroup: 'rg',
metricDefinition: 'Microsoft.NetApp/netAppAccounts/capacityPools/volumes',
metricNamespace: 'Microsoft.NetApp/netAppAccounts/capacityPools/volumes',
resourceName: 'rn1/rn2/rn3',
},
templateSrv
@@ -143,7 +143,7 @@ describe('AzureMonitorUrlBuilder', () => {
{
subscription: 'sub1',
resourceGroup: 'rg',
metricDefinition: 'Microsoft.Sql/servers/databases',
metricNamespace: 'Microsoft.Sql/servers/databases',
resourceName: 'rn1/rn2',
},
templateSrv
@@ -163,7 +163,7 @@ describe('AzureMonitorUrlBuilder', () => {
{
subscription: 'sub1',
resourceGroup: 'rg',
metricDefinition: 'Microsoft.Sql/servers',
metricNamespace: 'Microsoft.Sql/servers',
resourceName: 'rn',
},
templateSrv
@@ -175,7 +175,7 @@ describe('AzureMonitorUrlBuilder', () => {
});
});
describe('when metric definition is Microsoft.NetApp/netAppAccounts/capacityPools/volumes and the metricNamespace is default', () => {
describe('when metric definition is Microsoft.NetApp/netAppAccounts/capacityPools/volumes and the metricNamespace', () => {
it('should build the getMetricNames url in the even longer format', () => {
const url = UrlBuilder.buildAzureMonitorGetMetricNamesUrl(
'',
@@ -183,20 +183,19 @@ describe('AzureMonitorUrlBuilder', () => {
{
subscription: 'sub1',
resourceGroup: 'rg',
metricDefinition: 'Microsoft.NetApp/netAppAccounts/capacityPools/volumes',
metricNamespace: 'Microsoft.NetApp/netAppAccounts/capacityPools/volumes',
resourceName: 'rn1/rn2/rn3',
metricNamespace: 'default',
},
templateSrv
);
expect(url).toBe(
'/subscriptions/sub1/resourceGroups/rg/providers/Microsoft.NetApp/netAppAccounts/rn1/capacityPools/rn2/volumes/rn3/' +
'providers/microsoft.insights/metricdefinitions?api-version=2017-05-01-preview&metricnamespace=default'
'providers/microsoft.insights/metricdefinitions?api-version=2017-05-01-preview&metricnamespace=Microsoft.NetApp%2FnetAppAccounts%2FcapacityPools%2Fvolumes'
);
});
});
describe('when metric definition is Microsoft.Sql/servers/databases and the metricNamespace is default', () => {
describe('when metric definition is Microsoft.Sql/servers/databases and the metricNamespace', () => {
it('should build the getMetricNames url in the longer format', () => {
const url = UrlBuilder.buildAzureMonitorGetMetricNamesUrl(
'',
@@ -204,20 +203,19 @@ describe('AzureMonitorUrlBuilder', () => {
{
subscription: 'sub1',
resourceGroup: 'rg',
metricDefinition: 'Microsoft.Sql/servers/databases',
metricNamespace: 'Microsoft.Sql/servers/databases',
resourceName: 'rn1/rn2',
metricNamespace: 'default',
},
templateSrv
);
expect(url).toBe(
'/subscriptions/sub1/resourceGroups/rg/providers/Microsoft.Sql/servers/rn1/databases/rn2/' +
'providers/microsoft.insights/metricdefinitions?api-version=2017-05-01-preview&metricnamespace=default'
'providers/microsoft.insights/metricdefinitions?api-version=2017-05-01-preview&metricnamespace=Microsoft.Sql%2Fservers%2Fdatabases'
);
});
});
describe('when metric definition is Microsoft.Sql/servers and the metricNamespace is default', () => {
describe('when metric definition is Microsoft.Sql/servers and the metricNamespace', () => {
it('should build the getMetricNames url in the shorter format', () => {
const url = UrlBuilder.buildAzureMonitorGetMetricNamesUrl(
'',
@@ -225,20 +223,19 @@ describe('AzureMonitorUrlBuilder', () => {
{
subscription: 'sub1',
resourceGroup: 'rg',
metricDefinition: 'Microsoft.Sql/servers',
metricNamespace: 'Microsoft.Sql/servers',
resourceName: 'rn',
metricNamespace: 'default',
},
templateSrv
);
expect(url).toBe(
'/subscriptions/sub1/resourceGroups/rg/providers/Microsoft.Sql/servers/rn/' +
'providers/microsoft.insights/metricdefinitions?api-version=2017-05-01-preview&metricnamespace=default'
'providers/microsoft.insights/metricdefinitions?api-version=2017-05-01-preview&metricnamespace=Microsoft.Sql%2Fservers'
);
});
});
describe('when metric definition is Microsoft.Storage/storageAccounts/blobServices and the metricNamespace is default', () => {
describe('when metric definition is Microsoft.Storage/storageAccounts/blobServices and the metricNamespace', () => {
it('should build the getMetricNames url in the longer format', () => {
const url = UrlBuilder.buildAzureMonitorGetMetricNamesUrl(
'',
@@ -246,20 +243,19 @@ describe('AzureMonitorUrlBuilder', () => {
{
subscription: 'sub1',
resourceGroup: 'rg',
metricDefinition: 'Microsoft.Storage/storageAccounts/blobServices',
metricNamespace: 'Microsoft.Storage/storageAccounts/blobServices',
resourceName: 'rn1/default',
metricNamespace: 'default',
},
templateSrv
);
expect(url).toBe(
'/subscriptions/sub1/resourceGroups/rg/providers/Microsoft.Storage/storageAccounts/rn1/blobServices/default/' +
'providers/microsoft.insights/metricdefinitions?api-version=2017-05-01-preview&metricnamespace=default'
'providers/microsoft.insights/metricdefinitions?api-version=2017-05-01-preview&metricnamespace=Microsoft.Storage%2FstorageAccounts%2FblobServices'
);
});
});
describe('when metric definition is Microsoft.Storage/storageAccounts/fileServices and the metricNamespace is default', () => {
describe('when metric definition is Microsoft.Storage/storageAccounts/fileServices and the metricNamespace', () => {
it('should build the getMetricNames url in the longer format', () => {
const url = UrlBuilder.buildAzureMonitorGetMetricNamesUrl(
'',
@@ -267,20 +263,19 @@ describe('AzureMonitorUrlBuilder', () => {
{
subscription: 'sub1',
resourceGroup: 'rg',
metricDefinition: 'Microsoft.Storage/storageAccounts/fileServices',
metricNamespace: 'Microsoft.Storage/storageAccounts/fileServices',
resourceName: 'rn1/default',
metricNamespace: 'default',
},
templateSrv
);
expect(url).toBe(
'/subscriptions/sub1/resourceGroups/rg/providers/Microsoft.Storage/storageAccounts/rn1/fileServices/default/' +
'providers/microsoft.insights/metricdefinitions?api-version=2017-05-01-preview&metricnamespace=default'
'providers/microsoft.insights/metricdefinitions?api-version=2017-05-01-preview&metricnamespace=Microsoft.Storage%2FstorageAccounts%2FfileServices'
);
});
});
describe('when metric definition is Microsoft.Storage/storageAccounts/tableServices and the metricNamespace is default', () => {
describe('when metric definition is Microsoft.Storage/storageAccounts/tableServices and the metricNamespace', () => {
it('should build the getMetricNames url in the longer format', () => {
const url = UrlBuilder.buildAzureMonitorGetMetricNamesUrl(
'',
@@ -288,20 +283,19 @@ describe('AzureMonitorUrlBuilder', () => {
{
subscription: 'sub1',
resourceGroup: 'rg',
metricDefinition: 'Microsoft.Storage/storageAccounts/tableServices',
metricNamespace: 'Microsoft.Storage/storageAccounts/tableServices',
resourceName: 'rn1/default',
metricNamespace: 'default',
},
templateSrv
);
expect(url).toBe(
'/subscriptions/sub1/resourceGroups/rg/providers/Microsoft.Storage/storageAccounts/rn1/tableServices/default/' +
'providers/microsoft.insights/metricdefinitions?api-version=2017-05-01-preview&metricnamespace=default'
'providers/microsoft.insights/metricdefinitions?api-version=2017-05-01-preview&metricnamespace=Microsoft.Storage%2FstorageAccounts%2FtableServices'
);
});
});
describe('when metric definition is Microsoft.Storage/storageAccounts/queueServices and the metricNamespace is default', () => {
describe('when metric definition is Microsoft.Storage/storageAccounts/queueServices and the metricNamespace', () => {
it('should build the getMetricNames url in the longer format', () => {
const url = UrlBuilder.buildAzureMonitorGetMetricNamesUrl(
'',
@@ -309,35 +303,14 @@ describe('AzureMonitorUrlBuilder', () => {
{
subscription: 'sub1',
resourceGroup: 'rg',
metricDefinition: 'Microsoft.Storage/storageAccounts/queueServices',
metricNamespace: 'Microsoft.Storage/storageAccounts/queueServices',
resourceName: 'rn1/default',
metricNamespace: 'default',
},
templateSrv
);
expect(url).toBe(
'/subscriptions/sub1/resourceGroups/rg/providers/Microsoft.Storage/storageAccounts/rn1/queueServices/default/' +
'providers/microsoft.insights/metricdefinitions?api-version=2017-05-01-preview&metricnamespace=default'
);
});
});
describe('when metric definition does not contain a metric namespace', () => {
it('should build the getMetricNames url in the longer format', () => {
const url = UrlBuilder.buildAzureMonitorGetMetricNamesUrl(
'',
'2017-05-01-preview',
{
subscription: 'sub1',
resourceGroup: 'rg',
metricDefinition: 'microsoft.compute/virtualmachines',
resourceName: 'rn1',
},
templateSrv
);
expect(url).toBe(
'/subscriptions/sub1/resourceGroups/rg/providers/microsoft.compute/virtualmachines/rn1/' +
'providers/microsoft.insights/metricdefinitions?api-version=2017-05-01-preview'
'providers/microsoft.insights/metricdefinitions?api-version=2017-05-01-preview&metricnamespace=Microsoft.Storage%2FstorageAccounts%2FqueueServices'
);
});
});
@@ -6,33 +6,42 @@ export default class UrlBuilder {
static buildResourceUri(
subscriptionId: string,
resourceGroup: string,
metricDefinition: string,
resourceName: string,
templateSrv: TemplateSrv
templateSrv: TemplateSrv,
metricNamespace?: string,
resourceName?: string
) {
const metricDefinitionProcessed = templateSrv.replace(metricDefinition);
const metricDefinitionArray = metricDefinition.split('/');
const resourceNameProcessed = templateSrv.replace(resourceName);
const resourceNameArray = resourceName.split('/');
const provider = metricDefinitionArray.shift();
const urlArray = ['/subscriptions', subscriptionId, 'resourceGroups', resourceGroup, 'providers', provider];
const urlArray = ['/subscriptions', subscriptionId, 'resourceGroups', resourceGroup];
if (
metricDefinitionProcessed.startsWith('Microsoft.Storage/storageAccounts/') &&
!resourceNameProcessed.endsWith('default')
) {
resourceNameArray.push('default');
if (metricNamespace && resourceName) {
const metricNamespaceProcessed = templateSrv.replace(metricNamespace);
const metricNamespaceArray = metricNamespace.split('/');
const resourceNameProcessed = templateSrv.replace(resourceName);
const resourceNameArray = resourceName.split('/');
const provider = metricNamespaceArray.shift();
if (provider) {
urlArray.push('providers', provider);
}
if (
metricNamespaceProcessed.startsWith('Microsoft.Storage/storageAccounts/') &&
!resourceNameProcessed.endsWith('default')
) {
resourceNameArray.push('default');
}
if (resourceNameArray.length > metricNamespaceArray.length) {
const parentResource = resourceNameArray.shift();
if (parentResource) {
urlArray.push(parentResource);
}
}
for (const i in metricNamespaceArray) {
urlArray.push(metricNamespaceArray[i]);
urlArray.push(resourceNameArray[i]);
}
}
if (resourceNameArray.length > metricDefinitionArray.length) {
const parentResource = resourceNameArray.shift();
urlArray.push(parentResource);
}
for (const i in metricDefinitionArray) {
urlArray.push(metricDefinitionArray[i]);
urlArray.push(resourceNameArray[i]);
}
return urlArray.join('/');
}
@@ -47,13 +56,13 @@ export default class UrlBuilder {
if ('resourceUri' in query) {
resourceUri = query.resourceUri;
} else {
const { subscription, resourceGroup, metricDefinition, resourceName } = query;
const { subscription, resourceGroup, metricNamespace, resourceName } = query;
resourceUri = UrlBuilder.buildResourceUri(
subscription,
resourceGroup,
metricDefinition,
resourceName,
templateSrv
templateSrv,
metricNamespace,
resourceName
);
}
@@ -72,13 +81,13 @@ export default class UrlBuilder {
if ('resourceUri' in query) {
resourceUri = query.resourceUri;
} else {
const { subscription, resourceGroup, metricDefinition, resourceName } = query;
const { subscription, resourceGroup, metricNamespace, resourceName } = query;
resourceUri = UrlBuilder.buildResourceUri(
subscription,
resourceGroup,
metricDefinition,
resourceName,
templateSrv
templateSrv,
metricNamespace,
resourceName
);
}
@@ -128,10 +128,6 @@ describe('AzureMonitor: metrics dataHooks', () => {
opt('Web App - Development', 'web-app-development'),
]);
datasource.getMetricDefinitions = jest
.fn()
.mockResolvedValue([opt('Virtual Machine', 'azure/vm'), opt('Database', 'azure/db')]);
datasource.getResourceNames = jest
.fn()
.mockResolvedValue([opt('Web server', 'web-server'), opt('Job server', 'job-server')]);
@@ -12,10 +12,7 @@ describe('setResource', () => {
const q = createMockQuery();
expect(q.azureMonitor?.metricNamespace).not.toEqual(undefined);
expect(q.azureMonitor?.metricName).not.toEqual(undefined);
expect(q.azureMonitor?.metricDefinition).not.toEqual(undefined);
expect(q.azureMonitor?.aggregation).not.toEqual(undefined);
expect(q.azureMonitor?.metricDefinition).not.toEqual(undefined);
expect(q.azureMonitor?.metricDefinition).not.toEqual(undefined);
expect(q.azureMonitor?.timeGrain).not.toEqual('');
expect(q.azureMonitor?.timeGrain).not.toEqual([]);
const newQ = setResource(createMockQuery(), '/new-uri');
@@ -23,7 +20,6 @@ describe('setResource', () => {
metricNamespace: undefined,
metricName: undefined,
aggregation: undefined,
metricDefinition: undefined,
timeGrain: '',
dimensionFilters: [],
});
@@ -9,7 +9,6 @@ export function setResource(query: AzureMonitorQuery, resourceURI: string | unde
metricNamespace: undefined,
metricName: undefined,
aggregation: undefined,
metricDefinition: undefined,
timeGrain: '',
dimensionFilters: [],
},
@@ -36,7 +36,6 @@ const SubscriptionField: React.FC<SubscriptionFieldProps> = ({
newQuery.azureMonitor = {
...newQuery.azureMonitor,
resourceGroup: undefined,
metricDefinition: undefined,
metricNamespace: undefined,
resourceName: undefined,
metricName: undefined,
@@ -147,13 +147,6 @@ export default class Datasource extends DataSourceWithBackend<AzureMonitorQuery,
return this.azureMonitorDatasource.getResourceGroups(this.templateSrv.replace(subscriptionId));
}
getMetricDefinitions(subscriptionId: string, resourceGroup: string) {
return this.azureMonitorDatasource.getMetricDefinitions(
this.templateSrv.replace(subscriptionId),
this.templateSrv.replace(resourceGroup)
);
}
getMetricNamespaces(subscriptionId: string, resourceGroup?: string) {
let url = `/subscriptions/${subscriptionId}`;
if (resourceGroup) {
@@ -162,19 +155,19 @@ export default class Datasource extends DataSourceWithBackend<AzureMonitorQuery,
return this.azureMonitorDatasource.getMetricNamespaces({ resourceUri: url });
}
getResourceNames(subscriptionId: string, resourceGroup?: string, metricDefinition?: string) {
getResourceNames(subscriptionId: string, resourceGroup?: string, metricNamespace?: string) {
return this.azureMonitorDatasource.getResourceNames(
this.templateSrv.replace(subscriptionId),
this.templateSrv.replace(resourceGroup),
this.templateSrv.replace(metricDefinition)
this.templateSrv.replace(metricNamespace)
);
}
getMetricNames(subscriptionId: string, resourceGroup: string, metricDefinition: string, resourceName: string) {
getMetricNames(subscriptionId: string, resourceGroup: string, metricNamespace: string, resourceName: string) {
return this.azureMonitorDatasource.getMetricNames({
subscription: subscriptionId,
resourceGroup,
metricDefinition,
metricNamespace,
resourceName,
});
}
@@ -7,7 +7,6 @@ import {
AppInsightsGroupByQuery,
AppInsightsMetricNameQuery,
GrafanaTemplateVariableQuery,
MetricDefinitionsQuery,
MetricNamespaceQuery,
MetricNamesQuery,
ResourceGroupsQuery,
@@ -30,8 +29,8 @@ export const grafanaTemplateVariableFnMatches = (query: string) => {
subscriptions: query.match(/^Subscriptions\(\)/i),
resourceGroups: query.match(/^ResourceGroups\(\)/i),
resourceGroupsWithSub: query.match(/^ResourceGroups\(([^\)]+?)(,\s?([^,]+?))?\)/i),
metricDefinitions: query.match(/^Namespaces\(([^\)]+?)(,\s?([^,]+?))?\)/i),
metricDefinitionsWithSub: query.match(/^Namespaces\(([^,]+?),\s?([^,]+?)\)/i),
namespaces: query.match(/^Namespaces\(([^\)]+?)(,\s?([^,]+?))?\)/i),
namespacesWithSub: query.match(/^Namespaces\(([^,]+?),\s?([^,]+?)\)/i),
resourceNames: query.match(/^ResourceNames\(([^,]+?),\s?([^,]+?)\)/i),
resourceNamesWithSub: query.match(/^ResourceNames\(([^,]+?),\s?([^,]+?),\s?(.+?)\)/i),
metricNamespace: query.match(/^MetricNamespace\(([^,]+?),\s?([^,]+?),\s?([^,]+?)\)/i),
@@ -95,22 +94,22 @@ const createGrafanaTemplateVariableQuery = (rawQuery: string, datasource: DataSo
return queryDetails;
}
if (matchesForQuery.metricDefinitionsWithSub) {
const queryDetails: MetricDefinitionsQuery = {
kind: 'MetricDefinitionsQuery',
if (matchesForQuery.namespacesWithSub) {
const queryDetails: MetricNamespaceQuery = {
kind: 'MetricNamespaceQuery',
rawQuery,
subscription: matchesForQuery.metricDefinitionsWithSub[1],
resourceGroup: matchesForQuery.metricDefinitionsWithSub[2],
subscription: matchesForQuery.namespacesWithSub[1],
resourceGroup: matchesForQuery.namespacesWithSub[2],
};
return queryDetails;
}
if (matchesForQuery.metricDefinitions && defaultSubscriptionId) {
const queryDetails: MetricDefinitionsQuery = {
kind: 'MetricDefinitionsQuery',
if (matchesForQuery.namespaces && defaultSubscriptionId) {
const queryDetails: MetricNamespaceQuery = {
kind: 'MetricNamespaceQuery',
rawQuery,
subscription: defaultSubscriptionId,
resourceGroup: matchesForQuery.metricDefinitions[1],
resourceGroup: matchesForQuery.namespaces[1],
};
return queryDetails;
}
@@ -121,7 +120,7 @@ const createGrafanaTemplateVariableQuery = (rawQuery: string, datasource: DataSo
rawQuery,
subscription: matchesForQuery.resourceNamesWithSub[1],
resourceGroup: matchesForQuery.resourceNamesWithSub[2],
metricDefinition: matchesForQuery.resourceNamesWithSub[3],
metricNamespace: matchesForQuery.resourceNamesWithSub[3],
};
return queryDetails;
}
@@ -132,7 +131,7 @@ const createGrafanaTemplateVariableQuery = (rawQuery: string, datasource: DataSo
rawQuery,
subscription: defaultSubscriptionId,
resourceGroup: matchesForQuery.resourceNames[1],
metricDefinition: matchesForQuery.resourceNames[2],
metricNamespace: matchesForQuery.resourceNames[2],
};
return queryDetails;
}
@@ -143,7 +142,7 @@ const createGrafanaTemplateVariableQuery = (rawQuery: string, datasource: DataSo
rawQuery,
subscription: matchesForQuery.metricNamespaceWithSub[1],
resourceGroup: matchesForQuery.metricNamespaceWithSub[2],
metricDefinition: matchesForQuery.metricNamespaceWithSub[3],
metricNamespace: matchesForQuery.metricNamespaceWithSub[3],
resourceName: matchesForQuery.metricNamespaceWithSub[4],
};
return queryDetails;
@@ -155,7 +154,7 @@ const createGrafanaTemplateVariableQuery = (rawQuery: string, datasource: DataSo
rawQuery,
subscription: defaultSubscriptionId,
resourceGroup: matchesForQuery.metricNamespace[1],
metricDefinition: matchesForQuery.metricNamespace[2],
metricNamespace: matchesForQuery.metricNamespace[2],
resourceName: matchesForQuery.metricNamespace[3],
};
return queryDetails;
@@ -168,9 +167,8 @@ const createGrafanaTemplateVariableQuery = (rawQuery: string, datasource: DataSo
rawQuery,
subscription: defaultSubscriptionId,
resourceGroup: matchesForQuery.metricNames[1],
metricDefinition: matchesForQuery.metricNames[2],
metricNamespace: matchesForQuery.metricNames[2],
resourceName: matchesForQuery.metricNames[3],
metricNamespace: matchesForQuery.metricNames[4],
};
return queryDetails;
}
@@ -182,9 +180,8 @@ const createGrafanaTemplateVariableQuery = (rawQuery: string, datasource: DataSo
rawQuery,
subscription: matchesForQuery.metricNamesWithSub[1],
resourceGroup: matchesForQuery.metricNamesWithSub[2],
metricDefinition: matchesForQuery.metricNamesWithSub[3],
metricNamespace: matchesForQuery.metricNamesWithSub[3],
resourceName: matchesForQuery.metricNamesWithSub[4],
metricNamespace: matchesForQuery.metricNamesWithSub[5],
};
return queryDetails;
}
@@ -270,9 +267,6 @@ const migrateGrafanaTemplateVariableFn = (query: AzureMonitorQuery) => {
if ('resourceGroup' in grafanaTemplateVariableFn) {
migratedQuery.resourceGroup = grafanaTemplateVariableFn.resourceGroup;
}
if ('metricDefinition' in grafanaTemplateVariableFn) {
migratedQuery.namespace = grafanaTemplateVariableFn.metricDefinition;
}
if ('metricNamespace' in grafanaTemplateVariableFn) {
migratedQuery.namespace = grafanaTemplateVariableFn.metricNamespace;
}
@@ -287,9 +281,6 @@ const migrateGrafanaTemplateVariableFn = (query: AzureMonitorQuery) => {
case 'ResourceGroupsQuery':
migratedQuery.queryType = AzureQueryType.ResourceGroupsQuery;
break;
case 'MetricDefinitionsQuery':
migratedQuery.queryType = AzureQueryType.NamespacesQuery;
break;
case 'ResourceNamesQuery':
migratedQuery.queryType = AzureQueryType.ResourceNamesQuery;
break;
@@ -45,7 +45,7 @@ describe('migrateStringQueriesToObjectQueries', () => {
refId: 'A',
queryType: AzureQueryType.GrafanaTemplateVariableFn,
grafanaTemplateVariableFn: {
kind: 'MetricDefinitionsQuery',
kind: 'MetricNamespaceQuery',
rawQuery: 'Namespaces(rg)',
subscription: 'defaultSubscriptionId',
resourceGroup: 'rg',
@@ -59,7 +59,7 @@ describe('migrateStringQueriesToObjectQueries', () => {
refId: 'A',
queryType: AzureQueryType.GrafanaTemplateVariableFn,
grafanaTemplateVariableFn: {
kind: 'MetricDefinitionsQuery',
kind: 'MetricNamespaceQuery',
rawQuery: 'Namespaces(subId, rg)',
subscription: 'subId',
resourceGroup: 'rg',
@@ -77,7 +77,7 @@ describe('migrateStringQueriesToObjectQueries', () => {
rawQuery: 'ResourceNames(rg, md)',
subscription: 'defaultSubscriptionId',
resourceGroup: 'rg',
metricDefinition: 'md',
metricNamespace: 'md',
},
subscription: 'defaultSubscriptionId',
},
@@ -92,7 +92,7 @@ describe('migrateStringQueriesToObjectQueries', () => {
rawQuery: 'ResourceNames(subId, rg, md)',
subscription: 'subId',
resourceGroup: 'rg',
metricDefinition: 'md',
metricNamespace: 'md',
},
subscription: 'defaultSubscriptionId',
},
@@ -107,7 +107,7 @@ describe('migrateStringQueriesToObjectQueries', () => {
rawQuery: 'MetricNamespace(rg, md, rn)',
subscription: 'defaultSubscriptionId',
resourceGroup: 'rg',
metricDefinition: 'md',
metricNamespace: 'md',
resourceName: 'rn',
},
subscription: 'defaultSubscriptionId',
@@ -123,7 +123,7 @@ describe('migrateStringQueriesToObjectQueries', () => {
rawQuery: 'MetricNamespace(subId, rg, md, rn)',
subscription: 'subId',
resourceGroup: 'rg',
metricDefinition: 'md',
metricNamespace: 'md',
resourceName: 'rn',
},
subscription: 'defaultSubscriptionId',
@@ -139,9 +139,8 @@ describe('migrateStringQueriesToObjectQueries', () => {
rawQuery: 'MetricNames(rg, md, rn, mn)',
subscription: 'defaultSubscriptionId',
resourceGroup: 'rg',
metricDefinition: 'md',
metricNamespace: 'md',
resourceName: 'rn',
metricNamespace: 'mn',
},
subscription: 'defaultSubscriptionId',
},
@@ -156,9 +155,8 @@ describe('migrateStringQueriesToObjectQueries', () => {
rawQuery: 'MetricNames(subId, rg, md, rn, mn)',
subscription: 'subId',
resourceGroup: 'rg',
metricDefinition: 'md',
metricNamespace: 'md',
resourceName: 'rn',
metricNamespace: 'mn',
},
subscription: 'defaultSubscriptionId',
},
@@ -293,7 +291,7 @@ describe('migrateStringQueriesToObjectQueries', () => {
refId: 'A',
queryType: AzureQueryType.GrafanaTemplateVariableFn,
grafanaTemplateVariableFn: {
kind: 'MetricDefinitionsQuery',
kind: 'MetricNamespaceQuery',
rawQuery: 'Namespaces(rg)',
subscription: 'defaultSubscriptionId',
resourceGroup: 'rg',
@@ -312,7 +310,7 @@ describe('migrateStringQueriesToObjectQueries', () => {
refId: 'A',
queryType: AzureQueryType.GrafanaTemplateVariableFn,
grafanaTemplateVariableFn: {
kind: 'MetricDefinitionsQuery',
kind: 'MetricNamespaceQuery',
rawQuery: 'Namespaces(subId, rg)',
subscription: 'subId',
resourceGroup: 'rg',
@@ -335,7 +333,7 @@ describe('migrateStringQueriesToObjectQueries', () => {
rawQuery: 'ResourceNames(rg, md)',
subscription: 'defaultSubscriptionId',
resourceGroup: 'rg',
metricDefinition: 'md',
metricNamespace: 'md',
},
subscription: 'defaultSubscriptionId',
},
@@ -356,7 +354,7 @@ describe('migrateStringQueriesToObjectQueries', () => {
rawQuery: 'ResourceNames(subId, rg, md)',
subscription: 'subId',
resourceGroup: 'rg',
metricDefinition: 'md',
metricNamespace: 'md',
},
subscription: 'defaultSubscriptionId',
},
@@ -377,7 +375,7 @@ describe('migrateStringQueriesToObjectQueries', () => {
rawQuery: 'MetricNamespace(rg, md, rn)',
subscription: 'defaultSubscriptionId',
resourceGroup: 'rg',
metricDefinition: 'md',
metricNamespace: 'md',
resourceName: 'rn',
},
subscription: 'defaultSubscriptionId',
@@ -400,7 +398,7 @@ describe('migrateStringQueriesToObjectQueries', () => {
rawQuery: 'MetricNamespace(subId, rg, md, rn)',
subscription: 'subId',
resourceGroup: 'rg',
metricDefinition: 'md',
metricNamespace: 'md',
resourceName: 'rn',
},
subscription: 'defaultSubscriptionId',
@@ -423,9 +421,8 @@ describe('migrateStringQueriesToObjectQueries', () => {
rawQuery: 'MetricNames(rg, md, rn, mn)',
subscription: 'defaultSubscriptionId',
resourceGroup: 'rg',
metricDefinition: 'md',
metricNamespace: 'md',
resourceName: 'rn',
metricNamespace: 'mn',
},
subscription: 'defaultSubscriptionId',
},
@@ -434,7 +431,7 @@ describe('migrateStringQueriesToObjectQueries', () => {
queryType: AzureQueryType.MetricNamesQuery,
subscription: 'defaultSubscriptionId',
resourceGroup: 'rg',
namespace: 'mn',
namespace: 'md',
resource: 'rn',
},
},
@@ -447,9 +444,8 @@ describe('migrateStringQueriesToObjectQueries', () => {
rawQuery: 'MetricNames(subId, rg, md, rn, mn)',
subscription: 'subId',
resourceGroup: 'rg',
metricDefinition: 'md',
metricNamespace: 'md',
resourceName: 'rn',
metricNamespace: 'mn',
},
subscription: 'defaultSubscriptionId',
},
@@ -458,7 +454,7 @@ describe('migrateStringQueriesToObjectQueries', () => {
queryType: AzureQueryType.MetricNamesQuery,
subscription: 'subId',
resourceGroup: 'rg',
namespace: 'mn',
namespace: 'md',
resource: 'rn',
},
},
@@ -46,10 +46,8 @@ export interface AzureMetricQuery {
resourceUri?: string;
resourceGroup?: string;
/** Resource type */
metricDefinition?: string;
resourceName?: string;
/** Resource type */
metricNamespace?: string;
metricName?: string;
timeGrain?: string;
@@ -67,6 +65,9 @@ export interface AzureMetricQuery {
/** @deprecated This property was migrated to dimensionFilters and should only be accessed in the migration */
dimensionFilter?: string;
/** @deprecated Use metricNamespace instead */
metricDefinition?: string;
}
/**
@@ -3,7 +3,6 @@ export type GrafanaTemplateVariableQueryType =
| 'AppInsightsGroupByQuery'
| 'SubscriptionsQuery'
| 'ResourceGroupsQuery'
| 'MetricDefinitionsQuery'
| 'ResourceNamesQuery'
| 'MetricNamespaceQuery'
| 'MetricNamesQuery'
@@ -31,29 +30,23 @@ export interface ResourceGroupsQuery extends BaseGrafanaTemplateVariableQuery {
kind: 'ResourceGroupsQuery';
subscription: string;
}
export interface MetricDefinitionsQuery extends BaseGrafanaTemplateVariableQuery {
kind: 'MetricDefinitionsQuery';
subscription: string;
resourceGroup: string;
}
export interface ResourceNamesQuery extends BaseGrafanaTemplateVariableQuery {
kind: 'ResourceNamesQuery';
subscription: string;
resourceGroup: string;
metricDefinition: string;
metricNamespace: string;
}
export interface MetricNamespaceQuery extends BaseGrafanaTemplateVariableQuery {
kind: 'MetricNamespaceQuery';
subscription: string;
resourceGroup: string;
metricDefinition: string;
resourceName: string;
metricNamespace?: string;
resourceName?: string;
}
export interface MetricNamesQuery extends BaseGrafanaTemplateVariableQuery {
kind: 'MetricNamesQuery';
subscription: string;
resourceGroup: string;
metricDefinition: string;
resourceName: string;
metricNamespace: string;
}
@@ -67,7 +60,6 @@ export type GrafanaTemplateVariableQuery =
| AppInsightsGroupByQuery
| SubscriptionsQuery
| ResourceGroupsQuery
| MetricDefinitionsQuery
| ResourceNamesQuery
| MetricNamespaceQuery
| MetricNamesQuery
@@ -129,14 +129,6 @@ export interface AzureMonitorLocalizedValue {
localizedValue: string;
}
export interface AzureMonitorMetricDefinitionsResponse {
data: {
value: Array<{ name: string; type: string; location?: string }>;
};
status: number;
statusText: string;
}
export interface AzureMonitorResourceGroupsResponse {
data: {
value: Array<{ name: string }>;
@@ -233,8 +225,8 @@ export interface AzureGetMetricNamespacesQuery {
export interface LegacyAzureGetMetricNamespacesQuery {
subscription: string;
resourceGroup: string;
metricDefinition: string;
resourceName: string;
metricNamespace?: string;
resourceName?: string;
}
export interface AzureGetMetricNamesQuery {
@@ -245,9 +237,8 @@ export interface AzureGetMetricNamesQuery {
export interface LegacyAzureGetMetricNamesQuery {
subscription: string;
resourceGroup: string;
metricDefinition: string;
resourceName: string;
metricNamespace?: string;
metricNamespace: string;
}
export interface AzureGetMetricMetadataQuery {
@@ -259,7 +250,6 @@ export interface AzureGetMetricMetadataQuery {
export interface LegacyAzureGetMetricMetadataQuery {
subscription: string;
resourceGroup: string;
metricDefinition: string;
resourceName: string;
metricNamespace: string;
metricName: string;
@@ -33,7 +33,6 @@ const azureMonitorQueryV7 = {
aggregation: 'Average',
allowedTimeGrainsMs: [60000, 300000, 900000, 1800000, 3600000, 21600000, 43200000, 86400000],
dimensionFilters: [{ dimension: 'dependency/success', filter: '', operator: 'eq' }],
metricDefinition: 'microsoft.insights/components',
metricName: 'dependencies/duration',
metricNamespace: 'microsoft.insights/components',
resourceGroup: 'cloud-datasources',
@@ -54,7 +53,6 @@ const azureMonitorQueryV8 = {
azureMonitor: {
aggregation: 'Average',
dimensionFilters: [],
metricDefinition: 'microsoft.insights/components',
metricName: 'dependencies/duration',
metricNamespace: 'microsoft.insights/components',
resourceGroup: 'cloud-datasources',
@@ -82,7 +80,6 @@ const modernMetricsQuery: AzureMonitorQuery = {
alias: '{{ dimensionvalue }}',
allowedTimeGrainsMs: [60000, 300000, 900000, 1800000, 3600000, 21600000, 43200000, 86400000],
dimensionFilters: [{ dimension: 'dependency/success', filters: ['*'], operator: 'eq' }],
metricDefinition: 'microsoft.insights/components',
metricName: 'dependencies/duration',
metricNamespace: 'microsoft.insights/components',
resourceGroup: 'cloud-datasources',
@@ -158,7 +155,7 @@ describe('AzureMonitor: migrateQuery', () => {
...azureMonitorQueryV8,
azureMonitor: {
...azureMonitorQueryV8.azureMonitor,
metricDefinition: '$ns',
metricNamespace: '$ns',
},
};
const result = migrateQuery(query, templateSrv, setErrorMock);
@@ -295,5 +292,20 @@ describe('AzureMonitor: migrateQuery', () => {
})
);
});
it('correctly migrates a metric definition', () => {
const result = migrateQuery(
{ ...azureMonitorQueryV8, azureMonitor: { metricDefinition: 'ms.ns/mn' } },
templateSrv
);
expect(result).toMatchObject(
expect.objectContaining({
azureMonitor: expect.objectContaining({
metricNamespace: 'ms.ns/mn',
metricDefinition: undefined,
}),
})
);
});
});
});
@@ -16,7 +16,7 @@ const OLD_DEFAULT_DROPDOWN_VALUE = 'select';
export default function migrateQuery(
query: AzureMonitorQuery,
templateSrv: TemplateSrv,
setError: (errorSource: string, error: AzureMonitorErrorish) => void
setError?: (errorSource: string, error: AzureMonitorErrorish) => void
): AzureMonitorQuery {
let workingQuery = query;
@@ -81,6 +81,7 @@ function migrateToDefaultNamespace(query: AzureMonitorQuery): AzureMonitorQuery
azureMonitor: {
...query.azureMonitor,
metricNamespace: query.azureMonitor.metricDefinition,
metricDefinition: undefined,
},
};
}
@@ -116,13 +117,13 @@ function migrateResourceUri(
}
const { subscription } = query;
const { resourceGroup, metricDefinition, resourceName } = azureMonitorQuery;
if (!(subscription && resourceGroup && metricDefinition && resourceName)) {
const { resourceGroup, metricNamespace, resourceName } = azureMonitorQuery;
if (!(subscription && resourceGroup && metricNamespace && resourceName)) {
return query;
}
const metricDefinitionArray = metricDefinition.split('/');
if (metricDefinitionArray.some((p) => templateSrv.replace(p).split('/').length > 2)) {
const metricNamespaceArray = metricNamespace.split('/');
if (metricNamespaceArray.some((p) => templateSrv.replace(p).split('/').length > 2)) {
// If a metric definition includes template variable with a subresource e.g.
// Microsoft.Storage/storageAccounts/libraries, it's not possible to generate a valid
// resource URI
@@ -173,9 +174,9 @@ function migrateResourceUri(
const resourceUri = UrlBuilder.buildResourceUri(
subscription,
resourceGroup,
metricDefinition,
resourceName,
templateSrv
templateSrv,
metricNamespace,
resourceName
);
return {
@@ -98,14 +98,16 @@ describe('VariableSupport', () => {
});
});
it('can fetch metricDefinitions with a default subscriptionId', (done) => {
it('can fetch metricNamespaces with a default subscriptionId', (done) => {
const expectedResults = ['test'];
const variableSupport = new VariableSupport(
createMockDatasource({
azureLogAnalyticsDatasource: {
defaultSubscriptionId: 'defaultSubscriptionId',
},
getMetricDefinitions: jest.fn().mockResolvedValueOnce(expectedResults),
azureMonitorDatasource: {
getMetricNamespaces: jest.fn().mockResolvedValue(expectedResults),
},
})
);
const mockRequest = {
@@ -114,7 +116,7 @@ describe('VariableSupport', () => {
refId: 'A',
queryType: AzureQueryType.GrafanaTemplateVariableFn,
grafanaTemplateVariableFn: {
kind: 'MetricDefinitionsQuery',
kind: 'MetricNamespaceQuery',
rawQuery: 'Namespaces(resourceGroup)',
},
} as AzureMonitorQuery,
@@ -127,11 +129,13 @@ describe('VariableSupport', () => {
});
});
it('can fetch metricDefinitions with a subscriptionId', (done) => {
it('can fetch metricNamespaces with a subscriptionId', (done) => {
const expectedResults = ['test'];
const variableSupport = new VariableSupport(
createMockDatasource({
getMetricDefinitions: jest.fn().mockResolvedValueOnce(expectedResults),
azureMonitorDatasource: {
getMetricNamespaces: jest.fn().mockResolvedValue(expectedResults),
},
})
);
const mockRequest = {
@@ -140,7 +144,7 @@ describe('VariableSupport', () => {
refId: 'A',
queryType: AzureQueryType.GrafanaTemplateVariableFn,
grafanaTemplateVariableFn: {
kind: 'MetricDefinitionsQuery',
kind: 'MetricNamespaceQuery',
rawQuery: 'Namespaces(resourceGroup, subscriptionId)',
},
} as AzureMonitorQuery,
@@ -170,7 +174,7 @@ describe('VariableSupport', () => {
queryType: AzureQueryType.GrafanaTemplateVariableFn,
grafanaTemplateVariableFn: {
kind: 'ResourceNamesQuery',
rawQuery: 'ResourceNames(resourceGroup, metricDefinition)',
rawQuery: 'ResourceNames(resourceGroup, metricNamespace)',
},
} as AzureMonitorQuery,
],
@@ -196,7 +200,7 @@ describe('VariableSupport', () => {
queryType: AzureQueryType.GrafanaTemplateVariableFn,
grafanaTemplateVariableFn: {
kind: 'ResourceNamesQuery',
rawQuery: 'ResourceNames(subscriptionId, resourceGroup, metricDefinition)',
rawQuery: 'ResourceNames(subscriptionId, resourceGroup, metricNamespace)',
},
} as AzureMonitorQuery,
],
@@ -227,7 +231,7 @@ describe('VariableSupport', () => {
queryType: AzureQueryType.GrafanaTemplateVariableFn,
grafanaTemplateVariableFn: {
kind: 'MetricNamespaceQuery',
rawQuery: 'metricNamespace(resourceGroup, metricDefinition, resourceName)',
rawQuery: 'metricNamespace(resourceGroup, metricNamespace, resourceName)',
},
} as AzureMonitorQuery,
],
@@ -255,7 +259,7 @@ describe('VariableSupport', () => {
queryType: AzureQueryType.GrafanaTemplateVariableFn,
grafanaTemplateVariableFn: {
kind: 'MetricNamespaceQuery',
rawQuery: 'metricNamespace(subscriptionId, resourceGroup, metricDefinition, resourceName)',
rawQuery: 'metricNamespace(subscriptionId, resourceGroup, metricNamespace, resourceName)',
},
} as AzureMonitorQuery,
],
@@ -286,7 +290,7 @@ describe('VariableSupport', () => {
queryType: AzureQueryType.GrafanaTemplateVariableFn,
grafanaTemplateVariableFn: {
kind: 'MetricNamesQuery',
rawQuery: 'metricNames(resourceGroup, metricDefinition, resourceName, metricNamespace)',
rawQuery: 'metricNames(resourceGroup, metricNamespace, resourceName, metricNamespace)',
},
} as AzureMonitorQuery,
],
@@ -314,7 +318,7 @@ describe('VariableSupport', () => {
queryType: AzureQueryType.GrafanaTemplateVariableFn,
grafanaTemplateVariableFn: {
kind: 'MetricNamesQuery',
rawQuery: 'metricNames(subscription, resourceGroup, metricDefinition, resourceName, metricNamespace)',
rawQuery: 'metricNames(subscription, resourceGroup, metricNamespace, resourceName, metricNamespace)',
},
} as AzureMonitorQuery,
],
@@ -393,7 +397,7 @@ describe('VariableSupport', () => {
if (sub === 'subscriptionId' && rg === 'resourceGroup') {
return Promise.resolve(expectedResults);
}
return Promise.resolve([`getMetricDefinitions unexpected input: ${sub}, ${rg}`]);
return Promise.resolve([`getmetricNamespaces unexpected input: ${sub}, ${rg}`]);
}),
})
);
@@ -443,7 +447,7 @@ describe('VariableSupport', () => {
queryType: AzureQueryType.GrafanaTemplateVariableFn,
grafanaTemplateVariableFn: {
kind: 'MetricNamesQuery',
rawQuery: 'metricNames(resourceGroup, metricDefinition, resourceName, metricNamespace)',
rawQuery: 'metricNames(resourceGroup, metricNamespace, resourceName, metricNamespace)',
},
} as AzureMonitorQuery,
],
@@ -111,18 +111,11 @@ export class VariableSupport extends CustomVariableSupport<DataSource, AzureMoni
return this.datasource.getResourceGroups(this.replaceVariable(query.subscription));
}
if (query.kind === 'MetricDefinitionsQuery') {
return this.datasource.getMetricDefinitions(
this.replaceVariable(query.subscription),
this.replaceVariable(query.resourceGroup)
);
}
if (query.kind === 'ResourceNamesQuery') {
return this.datasource.getResourceNames(
this.replaceVariable(query.subscription),
this.replaceVariable(query.resourceGroup),
this.replaceVariable(query.metricDefinition)
this.replaceVariable(query.metricNamespace)
);
}