mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
AzureMonitor: build azure portal deep link with resource uri (#47947)
* AzureMonitor: build azure portal deep link with resource uri * extract resource name from the metrics api query * extract func for getting resource name from metrics url * add additional valid characters to regex
This commit is contained in:
parent
e0aeb83786
commit
eef22c05e1
@ -8,6 +8,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"path"
|
"path"
|
||||||
|
"regexp"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -33,6 +34,7 @@ type AzureMonitorDatasource struct {
|
|||||||
var (
|
var (
|
||||||
// Used to convert the aggregation value to the Azure enum for deep linking
|
// Used to convert the aggregation value to the Azure enum for deep linking
|
||||||
aggregationTypeMap = map[string]int{"None": 0, "Total": 1, "Minimum": 2, "Maximum": 3, "Average": 4, "Count": 7}
|
aggregationTypeMap = map[string]int{"None": 0, "Total": 1, "Minimum": 2, "Maximum": 3, "Average": 4, "Count": 7}
|
||||||
|
resourceNameLandmark = regexp.MustCompile(`(?i)(/(?P<resourceName>[\w-\.]+)/providers/Microsoft\.Insights/metrics)`)
|
||||||
)
|
)
|
||||||
|
|
||||||
const azureMonitorAPIVersion = "2018-01-01"
|
const azureMonitorAPIVersion = "2018-01-01"
|
||||||
@ -74,12 +76,6 @@ func (e *AzureMonitorDatasource) buildQueries(queries []backend.DataQuery, dsInf
|
|||||||
|
|
||||||
azJSONModel := queryJSONModel.AzureMonitor
|
azJSONModel := queryJSONModel.AzureMonitor
|
||||||
|
|
||||||
urlComponents := map[string]string{}
|
|
||||||
urlComponents["subscription"] = queryJSONModel.Subscription
|
|
||||||
urlComponents["resourceGroup"] = azJSONModel.ResourceGroup
|
|
||||||
urlComponents["metricDefinition"] = azJSONModel.MetricDefinition
|
|
||||||
urlComponents["resourceName"] = azJSONModel.ResourceName
|
|
||||||
|
|
||||||
ub := urlBuilder{
|
ub := urlBuilder{
|
||||||
ResourceURI: azJSONModel.ResourceURI,
|
ResourceURI: azJSONModel.ResourceURI,
|
||||||
// Legacy, used to reconstruct resource URI if it's not present
|
// Legacy, used to reconstruct resource URI if it's not present
|
||||||
@ -91,6 +87,19 @@ func (e *AzureMonitorDatasource) buildQueries(queries []backend.DataQuery, dsInf
|
|||||||
}
|
}
|
||||||
azureURL := ub.BuildMetricsURL()
|
azureURL := ub.BuildMetricsURL()
|
||||||
|
|
||||||
|
resourceName := azJSONModel.ResourceName
|
||||||
|
if resourceName == "" {
|
||||||
|
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
|
alias := azJSONModel.Alias
|
||||||
|
|
||||||
timeGrain := azJSONModel.TimeGrain
|
timeGrain := azJSONModel.TimeGrain
|
||||||
@ -338,12 +347,18 @@ func getQueryUrl(query *types.AzureMonitorQuery, azurePortalUrl string) (string,
|
|||||||
}
|
}
|
||||||
escapedTime := url.QueryEscape(string(timespan))
|
escapedTime := url.QueryEscape(string(timespan))
|
||||||
|
|
||||||
id := fmt.Sprintf("/subscriptions/%v/resourceGroups/%v/providers/%v/%v",
|
id := query.UrlComponents["resourceURI"]
|
||||||
query.UrlComponents["subscription"],
|
|
||||||
query.UrlComponents["resourceGroup"],
|
if id == "" {
|
||||||
query.UrlComponents["metricDefinition"],
|
ub := urlBuilder{
|
||||||
query.UrlComponents["resourceName"],
|
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{}{
|
chartDef, err := json.Marshal(map[string]interface{}{
|
||||||
"v2charts": []interface{}{
|
"v2charts": []interface{}{
|
||||||
map[string]interface{}{
|
map[string]interface{}{
|
||||||
@ -467,3 +482,20 @@ func toGrafanaUnit(unit string) string {
|
|||||||
// 1. Do not have a corresponding unit in Grafana's current list.
|
// 1. Do not have a corresponding unit in Grafana's current list.
|
||||||
// 2. Do not have the unit listed in any of Azure Monitor's supported metrics anyways.
|
// 2. Do not have the unit listed in any of Azure Monitor's supported metrics anyways.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func extractResourceNameFromMetricsURL(url string) string {
|
||||||
|
matches := resourceNameLandmark.FindStringSubmatch(url)
|
||||||
|
resourceName := ""
|
||||||
|
|
||||||
|
if matches == nil {
|
||||||
|
return resourceName
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, name := range resourceNameLandmark.SubexpNames() {
|
||||||
|
if name == "resourceName" {
|
||||||
|
resourceName = matches[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resourceName
|
||||||
|
}
|
||||||
|
@ -38,19 +38,22 @@ func TestAzureMonitorBuildQueries(t *testing.T) {
|
|||||||
azureMonitorVariedProperties map[string]interface{}
|
azureMonitorVariedProperties map[string]interface{}
|
||||||
azureMonitorQueryTarget string
|
azureMonitorQueryTarget string
|
||||||
expectedInterval string
|
expectedInterval string
|
||||||
|
resourceURI string
|
||||||
queryInterval time.Duration
|
queryInterval time.Duration
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "Parse queries from frontend and build AzureMonitor API queries",
|
name: "Parse queries from frontend and build AzureMonitor API queries",
|
||||||
azureMonitorVariedProperties: map[string]interface{}{
|
azureMonitorVariedProperties: map[string]interface{}{
|
||||||
|
"resourceURI": "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana",
|
||||||
"timeGrain": "PT1M",
|
"timeGrain": "PT1M",
|
||||||
"top": "10",
|
"top": "10",
|
||||||
},
|
},
|
||||||
|
resourceURI: "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana",
|
||||||
expectedInterval: "PT1M",
|
expectedInterval: "PT1M",
|
||||||
azureMonitorQueryTarget: "aggregation=Average&api-version=2018-01-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute-virtualMachines×pan=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-virtualMachines×pan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "time grain set to auto",
|
name: "legacy query without resourceURI and time grain set to auto",
|
||||||
azureMonitorVariedProperties: map[string]interface{}{
|
azureMonitorVariedProperties: map[string]interface{}{
|
||||||
"timeGrain": "auto",
|
"timeGrain": "auto",
|
||||||
"top": "10",
|
"top": "10",
|
||||||
@ -60,7 +63,7 @@ func TestAzureMonitorBuildQueries(t *testing.T) {
|
|||||||
azureMonitorQueryTarget: "aggregation=Average&api-version=2018-01-01&interval=PT15M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute-virtualMachines×pan=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-virtualMachines×pan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "time grain set to auto",
|
name: "legacy query without resourceURI and time grain set to auto",
|
||||||
azureMonitorVariedProperties: map[string]interface{}{
|
azureMonitorVariedProperties: map[string]interface{}{
|
||||||
"timeGrain": "auto",
|
"timeGrain": "auto",
|
||||||
"allowedTimeGrainsMs": []int64{60000, 300000},
|
"allowedTimeGrainsMs": []int64{60000, 300000},
|
||||||
@ -71,7 +74,7 @@ func TestAzureMonitorBuildQueries(t *testing.T) {
|
|||||||
azureMonitorQueryTarget: "aggregation=Average&api-version=2018-01-01&interval=PT5M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute-virtualMachines×pan=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-virtualMachines×pan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "has a dimension filter",
|
name: "legacy query without resourceURI and has a dimension filter",
|
||||||
azureMonitorVariedProperties: map[string]interface{}{
|
azureMonitorVariedProperties: map[string]interface{}{
|
||||||
"timeGrain": "PT1M",
|
"timeGrain": "PT1M",
|
||||||
"dimension": "blob",
|
"dimension": "blob",
|
||||||
@ -83,7 +86,7 @@ func TestAzureMonitorBuildQueries(t *testing.T) {
|
|||||||
azureMonitorQueryTarget: "%24filter=blob+eq+%27%2A%27&aggregation=Average&api-version=2018-01-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute-virtualMachines×pan=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-virtualMachines×pan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z&top=30",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "has a dimension filter and none Dimension",
|
name: "legacy query without resourceURI and has a dimension filter and none Dimension",
|
||||||
azureMonitorVariedProperties: map[string]interface{}{
|
azureMonitorVariedProperties: map[string]interface{}{
|
||||||
"timeGrain": "PT1M",
|
"timeGrain": "PT1M",
|
||||||
"dimension": "None",
|
"dimension": "None",
|
||||||
@ -95,7 +98,7 @@ func TestAzureMonitorBuildQueries(t *testing.T) {
|
|||||||
azureMonitorQueryTarget: "aggregation=Average&api-version=2018-01-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute-virtualMachines×pan=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-virtualMachines×pan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "has dimensionFilter*s* property with one dimension",
|
name: "legacy query without resourceURI and has dimensionFilter*s* property with one dimension",
|
||||||
azureMonitorVariedProperties: map[string]interface{}{
|
azureMonitorVariedProperties: map[string]interface{}{
|
||||||
"timeGrain": "PT1M",
|
"timeGrain": "PT1M",
|
||||||
"dimensionFilters": []types.AzureMonitorDimensionFilter{{Dimension: "blob", Operator: "eq", Filter: "*"}},
|
"dimensionFilters": []types.AzureMonitorDimensionFilter{{Dimension: "blob", Operator: "eq", Filter: "*"}},
|
||||||
@ -106,7 +109,7 @@ func TestAzureMonitorBuildQueries(t *testing.T) {
|
|||||||
azureMonitorQueryTarget: "%24filter=blob+eq+%27%2A%27&aggregation=Average&api-version=2018-01-01&interval=PT1M&metricnames=Percentage+CPU&metricnamespace=Microsoft.Compute-virtualMachines×pan=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-virtualMachines×pan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z&top=30",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "has dimensionFilter*s* property with two dimensions",
|
name: "legacy query without resourceURI and has dimensionFilter*s* property with two dimensions",
|
||||||
azureMonitorVariedProperties: map[string]interface{}{
|
azureMonitorVariedProperties: map[string]interface{}{
|
||||||
"timeGrain": "PT1M",
|
"timeGrain": "PT1M",
|
||||||
"dimensionFilters": []types.AzureMonitorDimensionFilter{{Dimension: "blob", Operator: "eq", Filter: "*"}, {Dimension: "tier", Operator: "eq", Filter: "*"}},
|
"dimensionFilters": []types.AzureMonitorDimensionFilter{{Dimension: "blob", Operator: "eq", Filter: "*"}, {Dimension: "tier", Operator: "eq", Filter: "*"}},
|
||||||
@ -117,7 +120,7 @@ func TestAzureMonitorBuildQueries(t *testing.T) {
|
|||||||
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×pan=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-virtualMachines×pan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z&top=30",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "has a dimension filter without specifying a top",
|
name: "legacy query without resourceURI and has a dimension filter without specifying a top",
|
||||||
azureMonitorVariedProperties: map[string]interface{}{
|
azureMonitorVariedProperties: map[string]interface{}{
|
||||||
"timeGrain": "PT1M",
|
"timeGrain": "PT1M",
|
||||||
"dimension": "blob",
|
"dimension": "blob",
|
||||||
@ -165,6 +168,7 @@ func TestAzureMonitorBuildQueries(t *testing.T) {
|
|||||||
azureMonitorQuery := &types.AzureMonitorQuery{
|
azureMonitorQuery := &types.AzureMonitorQuery{
|
||||||
URL: "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana/providers/microsoft.insights/metrics",
|
URL: "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana/providers/microsoft.insights/metrics",
|
||||||
UrlComponents: map[string]string{
|
UrlComponents: map[string]string{
|
||||||
|
"resourceURI": tt.resourceURI,
|
||||||
"metricDefinition": "Microsoft.Compute/virtualMachines",
|
"metricDefinition": "Microsoft.Compute/virtualMachines",
|
||||||
"resourceGroup": "grafanastaging",
|
"resourceGroup": "grafanastaging",
|
||||||
"resourceName": "grafana",
|
"resourceName": "grafana",
|
||||||
@ -214,19 +218,19 @@ func makeTestDataLink(url string) data.DataLink {
|
|||||||
func TestAzureMonitorParseResponse(t *testing.T) {
|
func TestAzureMonitorParseResponse(t *testing.T) {
|
||||||
// datalinks for the test frames
|
// datalinks for the test frames
|
||||||
averageLink := makeTestDataLink(`http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/` +
|
averageLink := makeTestDataLink(`http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%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%2F%2FresourceGroups%2F%2Fproviders%2F%2Fgrafana%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22%22%2C` +
|
`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%22%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22%22%2C` +
|
||||||
`%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D`)
|
`%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D`)
|
||||||
totalLink := makeTestDataLink(`http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/` +
|
totalLink := makeTestDataLink(`http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%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%2F%2FresourceGroups%2F%2Fproviders%2F%2Fgrafana%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A1%2C%22namespace%22%3A%22%22%2C` +
|
`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%22%22%2C%22aggregationType%22%3A1%2C%22namespace%22%3A%22%22%2C` +
|
||||||
`%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D`)
|
`%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D`)
|
||||||
maxLink := makeTestDataLink(`http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/` +
|
maxLink := makeTestDataLink(`http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%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%2F%2FresourceGroups%2F%2Fproviders%2F%2Fgrafana%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A3%2C%22namespace%22%3A%22%22%2C` +
|
`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%22%22%2C%22aggregationType%22%3A3%2C%22namespace%22%3A%22%22%2C` +
|
||||||
`%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D`)
|
`%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D`)
|
||||||
minLink := makeTestDataLink(`http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/` +
|
minLink := makeTestDataLink(`http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%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%2F%2FresourceGroups%2F%2Fproviders%2F%2Fgrafana%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A2%2C%22namespace%22%3A%22%22%2C` +
|
`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%22%22%2C%22aggregationType%22%3A2%2C%22namespace%22%3A%22%22%2C` +
|
||||||
`%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D`)
|
`%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D`)
|
||||||
countLink := makeTestDataLink(`http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%3A00Z%22%7D%7D/` +
|
countLink := makeTestDataLink(`http://ds/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%7B%22absolute%22%3A%7B%22startTime%22%3A%220001-01-01T00%3A00%3A00Z%22%2C%22endTime%22%3A%220001-01-01T00%3A00%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%2F%2FresourceGroups%2F%2Fproviders%2F%2Fgrafana%22%7D%2C%22name%22%3A%22%22%2C%22aggregationType%22%3A7%2C%22namespace%22%3A%22%22%2C` +
|
`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%22%22%2C%22aggregationType%22%3A7%2C%22namespace%22%3A%22%22%2C` +
|
||||||
`%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D`)
|
`%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D`)
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
@ -242,6 +246,7 @@ func TestAzureMonitorParseResponse(t *testing.T) {
|
|||||||
mockQuery: &types.AzureMonitorQuery{
|
mockQuery: &types.AzureMonitorQuery{
|
||||||
UrlComponents: map[string]string{
|
UrlComponents: map[string]string{
|
||||||
"resourceName": "grafana",
|
"resourceName": "grafana",
|
||||||
|
"resourceURI": "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana",
|
||||||
},
|
},
|
||||||
Params: url.Values{
|
Params: url.Values{
|
||||||
"aggregation": {"Average"},
|
"aggregation": {"Average"},
|
||||||
@ -263,6 +268,7 @@ func TestAzureMonitorParseResponse(t *testing.T) {
|
|||||||
mockQuery: &types.AzureMonitorQuery{
|
mockQuery: &types.AzureMonitorQuery{
|
||||||
UrlComponents: map[string]string{
|
UrlComponents: map[string]string{
|
||||||
"resourceName": "grafana",
|
"resourceName": "grafana",
|
||||||
|
"resourceURI": "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana",
|
||||||
},
|
},
|
||||||
Params: url.Values{
|
Params: url.Values{
|
||||||
"aggregation": {"Total"},
|
"aggregation": {"Total"},
|
||||||
@ -284,6 +290,7 @@ func TestAzureMonitorParseResponse(t *testing.T) {
|
|||||||
mockQuery: &types.AzureMonitorQuery{
|
mockQuery: &types.AzureMonitorQuery{
|
||||||
UrlComponents: map[string]string{
|
UrlComponents: map[string]string{
|
||||||
"resourceName": "grafana",
|
"resourceName": "grafana",
|
||||||
|
"resourceURI": "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana",
|
||||||
},
|
},
|
||||||
Params: url.Values{
|
Params: url.Values{
|
||||||
"aggregation": {"Maximum"},
|
"aggregation": {"Maximum"},
|
||||||
@ -305,6 +312,7 @@ func TestAzureMonitorParseResponse(t *testing.T) {
|
|||||||
mockQuery: &types.AzureMonitorQuery{
|
mockQuery: &types.AzureMonitorQuery{
|
||||||
UrlComponents: map[string]string{
|
UrlComponents: map[string]string{
|
||||||
"resourceName": "grafana",
|
"resourceName": "grafana",
|
||||||
|
"resourceURI": "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana",
|
||||||
},
|
},
|
||||||
Params: url.Values{
|
Params: url.Values{
|
||||||
"aggregation": {"Minimum"},
|
"aggregation": {"Minimum"},
|
||||||
@ -326,6 +334,7 @@ func TestAzureMonitorParseResponse(t *testing.T) {
|
|||||||
mockQuery: &types.AzureMonitorQuery{
|
mockQuery: &types.AzureMonitorQuery{
|
||||||
UrlComponents: map[string]string{
|
UrlComponents: map[string]string{
|
||||||
"resourceName": "grafana",
|
"resourceName": "grafana",
|
||||||
|
"resourceURI": "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana",
|
||||||
},
|
},
|
||||||
Params: url.Values{
|
Params: url.Values{
|
||||||
"aggregation": {"Count"},
|
"aggregation": {"Count"},
|
||||||
@ -347,6 +356,7 @@ func TestAzureMonitorParseResponse(t *testing.T) {
|
|||||||
mockQuery: &types.AzureMonitorQuery{
|
mockQuery: &types.AzureMonitorQuery{
|
||||||
UrlComponents: map[string]string{
|
UrlComponents: map[string]string{
|
||||||
"resourceName": "grafana",
|
"resourceName": "grafana",
|
||||||
|
"resourceURI": "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana",
|
||||||
},
|
},
|
||||||
Params: url.Values{
|
Params: url.Values{
|
||||||
"aggregation": {"Average"},
|
"aggregation": {"Average"},
|
||||||
@ -382,6 +392,7 @@ func TestAzureMonitorParseResponse(t *testing.T) {
|
|||||||
Alias: "custom {{resourcegroup}} {{namespace}} {{resourceName}} {{metric}}",
|
Alias: "custom {{resourcegroup}} {{namespace}} {{resourceName}} {{metric}}",
|
||||||
UrlComponents: map[string]string{
|
UrlComponents: map[string]string{
|
||||||
"resourceName": "grafana",
|
"resourceName": "grafana",
|
||||||
|
"resourceURI": "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana",
|
||||||
},
|
},
|
||||||
Params: url.Values{
|
Params: url.Values{
|
||||||
"aggregation": {"Total"},
|
"aggregation": {"Total"},
|
||||||
@ -404,6 +415,7 @@ func TestAzureMonitorParseResponse(t *testing.T) {
|
|||||||
Alias: "{{dimensionname}}={{DimensionValue}}",
|
Alias: "{{dimensionname}}={{DimensionValue}}",
|
||||||
UrlComponents: map[string]string{
|
UrlComponents: map[string]string{
|
||||||
"resourceName": "grafana",
|
"resourceName": "grafana",
|
||||||
|
"resourceURI": "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana",
|
||||||
},
|
},
|
||||||
Params: url.Values{
|
Params: url.Values{
|
||||||
"aggregation": {"Average"},
|
"aggregation": {"Average"},
|
||||||
@ -441,6 +453,7 @@ func TestAzureMonitorParseResponse(t *testing.T) {
|
|||||||
Alias: "{{resourcegroup}} {Blob Type={{blobtype}}, Tier={{Tier}}}",
|
Alias: "{{resourcegroup}} {Blob Type={{blobtype}}, Tier={{Tier}}}",
|
||||||
UrlComponents: map[string]string{
|
UrlComponents: map[string]string{
|
||||||
"resourceName": "grafana",
|
"resourceName": "grafana",
|
||||||
|
"resourceURI": "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana",
|
||||||
},
|
},
|
||||||
Params: url.Values{
|
Params: url.Values{
|
||||||
"aggregation": {"Average"},
|
"aggregation": {"Average"},
|
||||||
@ -479,6 +492,7 @@ func TestAzureMonitorParseResponse(t *testing.T) {
|
|||||||
Alias: "custom",
|
Alias: "custom",
|
||||||
UrlComponents: map[string]string{
|
UrlComponents: map[string]string{
|
||||||
"resourceName": "grafana",
|
"resourceName": "grafana",
|
||||||
|
"resourceURI": "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana",
|
||||||
},
|
},
|
||||||
Params: url.Values{
|
Params: url.Values{
|
||||||
"aggregation": {"Average"},
|
"aggregation": {"Average"},
|
||||||
@ -494,6 +508,57 @@ func TestAzureMonitorParseResponse(t *testing.T) {
|
|||||||
}).SetConfig(&data.FieldConfig{DisplayName: "custom", Links: []data.DataLink{averageLink}})),
|
}).SetConfig(&data.FieldConfig{DisplayName: "custom", Links: []data.DataLink{averageLink}})),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
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",
|
||||||
|
},
|
||||||
|
Params: url.Values{
|
||||||
|
"aggregation": {"Total"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedFrames: data.Frames{
|
||||||
|
data.NewFrame("",
|
||||||
|
data.NewField("Time", nil,
|
||||||
|
makeDates(time.Date(2019, 2, 9, 13, 29, 0, 0, time.UTC), 5, time.Minute),
|
||||||
|
).SetConfig(&data.FieldConfig{Links: []data.DataLink{totalLink}}),
|
||||||
|
data.NewField("Percentage CPU", nil, []*float64{
|
||||||
|
ptr.Float64(8.26), ptr.Float64(8.7), ptr.Float64(14.82), ptr.Float64(10.07), ptr.Float64(8.52),
|
||||||
|
}).SetConfig(&data.FieldConfig{Unit: "percent", DisplayName: "custom grafanastaging Microsoft.Compute/virtualMachines grafana Percentage CPU", Links: []data.DataLink{totalLink}})),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
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",
|
||||||
|
},
|
||||||
|
Params: url.Values{
|
||||||
|
"aggregation": {"Total"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedFrames: data.Frames{
|
||||||
|
data.NewFrame("",
|
||||||
|
data.NewField("Time", nil,
|
||||||
|
makeDates(time.Date(2019, 2, 9, 13, 29, 0, 0, time.UTC), 5, time.Minute),
|
||||||
|
).SetConfig(&data.FieldConfig{Links: []data.DataLink{totalLink}}),
|
||||||
|
data.NewField("Percentage CPU", nil, []*float64{
|
||||||
|
ptr.Float64(8.26), ptr.Float64(8.7), ptr.Float64(14.82), ptr.Float64(10.07), ptr.Float64(8.52),
|
||||||
|
}).SetConfig(&data.FieldConfig{Unit: "percent", DisplayName: "custom grafanastaging Microsoft.Compute/virtualMachines grafana Percentage CPU", Links: []data.DataLink{totalLink}})),
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
datasource := &AzureMonitorDatasource{}
|
datasource := &AzureMonitorDatasource{}
|
||||||
@ -609,3 +674,21 @@ func TestAzureMonitorCreateRequest(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestExtractResourceNameFromMetricsURL(t *testing.T) {
|
||||||
|
t.Run("it should extract the resourceName from a well-formed Metrics URL", func(t *testing.T) {
|
||||||
|
url := "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/Grafana-Test.VM/providers/microsoft.insights/metrics"
|
||||||
|
expected := "Grafana-Test.VM"
|
||||||
|
require.Equal(t, expected, extractResourceNameFromMetricsURL((url)))
|
||||||
|
})
|
||||||
|
t.Run("it should extract the resourceName from a well-formed Metrics URL in a case insensitive manner", func(t *testing.T) {
|
||||||
|
url := "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/Grafana-Test.VM/pRoViDeRs/MiCrOsOfT.iNsIgHtS/mEtRiCs"
|
||||||
|
expected := "Grafana-Test.VM"
|
||||||
|
require.Equal(t, expected, extractResourceNameFromMetricsURL((url)))
|
||||||
|
})
|
||||||
|
t.Run("it should return an empty string if no match is found", func(t *testing.T) {
|
||||||
|
url := "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/Grafana-Test.VM/providers/microsoft.insights/nope-this-part-does-not-match"
|
||||||
|
expected := ""
|
||||||
|
require.Equal(t, expected, extractResourceNameFromMetricsURL((url)))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -18,7 +18,7 @@ type urlBuilder struct {
|
|||||||
ResourceName string
|
ResourceName string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (params *urlBuilder) buildMetricsURLFromLegacyQuery() string {
|
func (params *urlBuilder) buildResourceURIFromLegacyQuery() string {
|
||||||
subscription := params.Subscription
|
subscription := params.Subscription
|
||||||
|
|
||||||
if params.Subscription == "" {
|
if params.Subscription == "" {
|
||||||
@ -54,7 +54,7 @@ func (params *urlBuilder) BuildMetricsURL() string {
|
|||||||
|
|
||||||
// Prior to Grafana 9, we had a legacy query object rather than a resourceURI, so we manually create the resource URI
|
// Prior to Grafana 9, we had a legacy query object rather than a resourceURI, so we manually create the resource URI
|
||||||
if resourceURI == "" {
|
if resourceURI == "" {
|
||||||
resourceURI = params.buildMetricsURLFromLegacyQuery()
|
resourceURI = params.buildResourceURIFromLegacyQuery()
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Sprintf("%s/providers/microsoft.insights/metrics", resourceURI)
|
return fmt.Sprintf("%s/providers/microsoft.insights/metrics", resourceURI)
|
||||||
|
Loading…
Reference in New Issue
Block a user