AzureMonitor: move metric deep link code to backend (#39524)

This commit is contained in:
Isabella Siu
2021-09-28 09:24:18 -04:00
committed by GitHub
parent 73936fc63c
commit bf9be975ac
6 changed files with 190 additions and 162 deletions
@@ -186,7 +186,7 @@ func (e *AzureResourceGraphDatasource) executeQuery(ctx context.Context, query *
}
url := azurePortalUrl + "/#blade/HubsExtension/ArgQueryBlade/query/" + url.PathEscape(query.InterpolatedQuery)
frameWithLink := addConfigData(*frame, url)
frameWithLink := addConfigLinks(*frame, url)
if frameWithLink.Meta == nil {
frameWithLink.Meta = &data.FrameMeta{}
}
@@ -196,7 +196,7 @@ func (e *AzureResourceGraphDatasource) executeQuery(ctx context.Context, query *
return dataResponse
}
func addConfigData(frame data.Frame, dl string) data.Frame {
func addConfigLinks(frame data.Frame, dl string) data.Frame {
for i := range frame.Fields {
if frame.Fields[i].Config == nil {
frame.Fields[i].Config = &data.FieldConfig{}
@@ -120,7 +120,7 @@ func TestAddConfigData(t *testing.T) {
frame := data.Frame{
Fields: []*data.Field{&field},
}
frameWithLink := addConfigData(frame, "http://ds")
frameWithLink := addConfigLinks(frame, "http://ds")
expectedFrameWithLink := data.Frame{
Fields: []*data.Field{
{
@@ -28,6 +28,9 @@ type AzureMonitorDatasource struct {
var (
// 1m, 5m, 15m, 30m, 1h, 6h, 12h, 1d in milliseconds
defaultAllowedIntervalsMS = []int64{60000, 300000, 900000, 1800000, 3600000, 21600000, 43200000, 86400000}
// 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}
)
const azureMonitorAPIVersion = "2018-01-01"
@@ -49,18 +52,7 @@ func (e *AzureMonitorDatasource) executeTimeSeriesQuery(ctx context.Context, ori
}
for _, query := range queries {
queryRes, resp, err := e.executeQuery(ctx, query, dsInfo, client, url)
if err != nil {
return nil, err
}
frames, err := e.parseResponse(resp, query)
if err != nil {
queryRes.Error = err
} else {
queryRes.Frames = frames
}
result.Responses[query.RefID] = queryRes
result.Responses[query.RefID] = e.executeQuery(ctx, query, dsInfo, client, url)
}
return result, nil
@@ -155,13 +147,13 @@ func (e *AzureMonitorDatasource) buildQueries(queries []backend.DataQuery, dsInf
return azureMonitorQueries, nil
}
func (e *AzureMonitorDatasource) executeQuery(ctx context.Context, query *AzureMonitorQuery, dsInfo datasourceInfo, cli *http.Client, url string) (backend.DataResponse, AzureMonitorResponse, error) {
func (e *AzureMonitorDatasource) executeQuery(ctx context.Context, query *AzureMonitorQuery, dsInfo datasourceInfo, cli *http.Client, url string) backend.DataResponse {
dataResponse := backend.DataResponse{}
req, err := e.createRequest(ctx, dsInfo, url)
if err != nil {
dataResponse.Error = err
return dataResponse, AzureMonitorResponse{}, nil
return dataResponse
}
req.URL.Path = path.Join(req.URL.Path, query.URL)
@@ -181,7 +173,7 @@ func (e *AzureMonitorDatasource) executeQuery(ctx context.Context, query *AzureM
opentracing.HTTPHeaders,
opentracing.HTTPHeadersCarrier(req.Header)); err != nil {
dataResponse.Error = err
return dataResponse, AzureMonitorResponse{}, nil
return dataResponse
}
azlog.Debug("AzureMonitor", "Request ApiURL", req.URL.String())
@@ -189,7 +181,7 @@ func (e *AzureMonitorDatasource) executeQuery(ctx context.Context, query *AzureM
res, err := ctxhttp.Do(ctx, cli, req)
if err != nil {
dataResponse.Error = err
return dataResponse, AzureMonitorResponse{}, nil
return dataResponse
}
defer func() {
if err := res.Body.Close(); err != nil {
@@ -200,10 +192,22 @@ func (e *AzureMonitorDatasource) executeQuery(ctx context.Context, query *AzureM
data, err := e.unmarshalResponse(res)
if err != nil {
dataResponse.Error = err
return dataResponse, AzureMonitorResponse{}, nil
return dataResponse
}
return dataResponse, data, nil
azurePortalUrl, err := getAzurePortalUrl(dsInfo.Cloud)
if err != nil {
dataResponse.Error = err
return dataResponse
}
dataResponse.Frames, err = e.parseResponse(data, query, azurePortalUrl)
if err != nil {
dataResponse.Error = err
return dataResponse
}
return dataResponse
}
func (e *AzureMonitorDatasource) createRequest(ctx context.Context, dsInfo datasourceInfo, url string) (*http.Request, error) {
@@ -239,12 +243,16 @@ func (e *AzureMonitorDatasource) unmarshalResponse(res *http.Response) (AzureMon
return data, nil
}
func (e *AzureMonitorDatasource) parseResponse(amr AzureMonitorResponse, query *AzureMonitorQuery) (
data.Frames, error) {
func (e *AzureMonitorDatasource) parseResponse(amr AzureMonitorResponse, query *AzureMonitorQuery, azurePortalUrl string) (data.Frames, error) {
if len(amr.Value) == 0 {
return nil, nil
}
queryUrl, err := getQueryUrl(query, azurePortalUrl)
if err != nil {
return nil, err
}
frames := data.Frames{}
for _, series := range amr.Value[0].Timeseries {
labels := data.Labels{}
@@ -299,12 +307,71 @@ func (e *AzureMonitorDatasource) parseResponse(amr AzureMonitorResponse, query *
frame.SetRow(i, point.TimeStamp, value)
}
frames = append(frames, frame)
frameWithLink := addConfigLinks(*frame, queryUrl)
frames = append(frames, &frameWithLink)
}
return frames, nil
}
// Gets the deep link for the given query
func getQueryUrl(query *AzureMonitorQuery, azurePortalUrl string) (string, error) {
aggregationType := aggregationTypeMap["Average"]
aggregation := query.Params.Get("aggregation")
if aggregation != "" {
if aggType, ok := aggregationTypeMap[aggregation]; ok {
aggregationType = aggType
}
}
timespan, err := json.Marshal(map[string]interface{}{
"absolute": struct {
Start string `json:"startTime"`
End string `json:"endTime"`
}{
Start: query.TimeRange.From.UTC().Format(time.RFC3339Nano),
End: query.TimeRange.To.UTC().Format(time.RFC3339Nano),
},
})
if err != nil {
return "", err
}
escapedTime := url.QueryEscape(string(timespan))
id := fmt.Sprintf("/subscriptions/%v/resourceGroups/%v/providers/%v/%v",
query.UrlComponents["subscription"],
query.UrlComponents["resourceGroup"],
query.UrlComponents["metricDefinition"],
query.UrlComponents["resourceName"],
)
chartDef, err := json.Marshal(map[string]interface{}{
"v2charts": []interface{}{
map[string]interface{}{
"metrics": []metricChartDefinition{
{
ResourceMetadata: map[string]string{
"id": id,
},
Name: query.Params.Get("metricnames"),
AggregationType: aggregationType,
Namespace: query.Params.Get("metricnamespace"),
MetricVisualization: metricVisualization{
DisplayName: query.Params.Get("metricnames"),
ResourceDisplayName: query.UrlComponents["resourceName"],
},
},
},
},
},
})
if err != nil {
return "", err
}
escapedChart := url.QueryEscape(string(chartDef))
return fmt.Sprintf("%s/#blade/Microsoft_Azure_MonitoringMetrics/Metrics.ReactView/Referer/MetricsExplorer/TimeContext/%s/ChartDefinition/%s", azurePortalUrl, escapedTime, escapedChart), nil
}
// formatAzureMonitorLegendKey builds the legend key or timeseries name
// Alias patterns like {{resourcename}} are replaced with the appropriate data values.
func formatAzureMonitorLegendKey(alias string, resourceName string, metricName string, metadataName string,
@@ -171,6 +171,14 @@ func TestAzureMonitorBuildQueries(t *testing.T) {
if diff := cmp.Diff(azureMonitorQuery, queries[0], cmpopts.IgnoreUnexported(simplejson.Json{}), cmpopts.IgnoreFields(AzureMonitorQuery{}, "Params")); diff != "" {
t.Errorf("Result mismatch (-want +got):\n%s", diff)
}
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+CPU%22%2C%22aggregationType%22%3A4%2C%22namespace%22%3A%22Microsoft.Compute-virtualMachines%22%2C%22metricVisualization%22%3A%7B%22displayName%22%3A%22Percentage+CPU%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)
})
}
}
@@ -182,7 +190,32 @@ func makeDates(startDate time.Time, count int, interval time.Duration) (times []
return
}
func makeTestDataLink(url string) data.DataLink {
return data.DataLink{
Title: "View in Azure Portal",
TargetBlank: true,
URL: url,
}
}
func TestAzureMonitorParseResponse(t *testing.T) {
// 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/` +
`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` +
`%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/` +
`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` +
`%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/` +
`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` +
`%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/` +
`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` +
`%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/` +
`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` +
`%22metricVisualization%22%3A%7B%22displayName%22%3A%22%22%2C%22resourceDisplayName%22%3A%22grafana%22%7D%7D%5D%7D%5D%7D`)
tests := []struct {
name string
responseFile string
@@ -204,10 +237,11 @@ func TestAzureMonitorParseResponse(t *testing.T) {
expectedFrames: data.Frames{
data.NewFrame("",
data.NewField("Time", nil,
makeDates(time.Date(2019, 2, 8, 10, 13, 0, 0, time.UTC), 5, time.Minute)),
makeDates(time.Date(2019, 2, 8, 10, 13, 0, 0, time.UTC), 5, time.Minute),
).SetConfig(&data.FieldConfig{Links: []data.DataLink{averageLink}}),
data.NewField("Percentage CPU", nil, []*float64{
ptr.Float64(2.0875), ptr.Float64(2.1525), ptr.Float64(2.155), ptr.Float64(3.6925), ptr.Float64(2.44),
}).SetConfig(&data.FieldConfig{Unit: "percent"})),
}).SetConfig(&data.FieldConfig{Unit: "percent", Links: []data.DataLink{averageLink}})),
},
},
{
@@ -224,10 +258,11 @@ func TestAzureMonitorParseResponse(t *testing.T) {
expectedFrames: data.Frames{
data.NewFrame("",
data.NewField("Time", nil,
makeDates(time.Date(2019, 2, 9, 13, 29, 0, 0, time.UTC), 5, time.Minute)),
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"})),
}).SetConfig(&data.FieldConfig{Unit: "percent", Links: []data.DataLink{totalLink}})),
},
},
{
@@ -244,10 +279,11 @@ func TestAzureMonitorParseResponse(t *testing.T) {
expectedFrames: data.Frames{
data.NewFrame("",
data.NewField("Time", nil,
makeDates(time.Date(2019, 2, 9, 14, 26, 0, 0, time.UTC), 5, time.Minute)),
makeDates(time.Date(2019, 2, 9, 14, 26, 0, 0, time.UTC), 5, time.Minute),
).SetConfig(&data.FieldConfig{Links: []data.DataLink{maxLink}}),
data.NewField("Percentage CPU", nil, []*float64{
ptr.Float64(3.07), ptr.Float64(2.92), ptr.Float64(2.87), ptr.Float64(2.27), ptr.Float64(2.52),
}).SetConfig(&data.FieldConfig{Unit: "percent"})),
}).SetConfig(&data.FieldConfig{Unit: "percent", Links: []data.DataLink{maxLink}})),
},
},
{
@@ -264,10 +300,11 @@ func TestAzureMonitorParseResponse(t *testing.T) {
expectedFrames: data.Frames{
data.NewFrame("",
data.NewField("Time", nil,
makeDates(time.Date(2019, 2, 9, 14, 43, 0, 0, time.UTC), 5, time.Minute)),
makeDates(time.Date(2019, 2, 9, 14, 43, 0, 0, time.UTC), 5, time.Minute),
).SetConfig(&data.FieldConfig{Links: []data.DataLink{minLink}}),
data.NewField("Percentage CPU", nil, []*float64{
ptr.Float64(1.51), ptr.Float64(2.38), ptr.Float64(1.69), ptr.Float64(2.27), ptr.Float64(1.96),
}).SetConfig(&data.FieldConfig{Unit: "percent"})),
}).SetConfig(&data.FieldConfig{Unit: "percent", Links: []data.DataLink{minLink}})),
},
},
{
@@ -284,10 +321,11 @@ func TestAzureMonitorParseResponse(t *testing.T) {
expectedFrames: data.Frames{
data.NewFrame("",
data.NewField("Time", nil,
makeDates(time.Date(2019, 2, 9, 14, 44, 0, 0, time.UTC), 5, time.Minute)),
makeDates(time.Date(2019, 2, 9, 14, 44, 0, 0, time.UTC), 5, time.Minute),
).SetConfig(&data.FieldConfig{Links: []data.DataLink{countLink}}),
data.NewField("Percentage CPU", nil, []*float64{
ptr.Float64(4), ptr.Float64(4), ptr.Float64(4), ptr.Float64(4), ptr.Float64(4),
}).SetConfig(&data.FieldConfig{Unit: "percent"})),
}).SetConfig(&data.FieldConfig{Unit: "percent", Links: []data.DataLink{countLink}})),
},
},
{
@@ -304,21 +342,24 @@ func TestAzureMonitorParseResponse(t *testing.T) {
expectedFrames: data.Frames{
data.NewFrame("",
data.NewField("Time", nil,
makeDates(time.Date(2019, 2, 9, 15, 21, 0, 0, time.UTC), 6, time.Hour)),
makeDates(time.Date(2019, 2, 9, 15, 21, 0, 0, time.UTC), 6, time.Hour),
).SetConfig(&data.FieldConfig{Links: []data.DataLink{averageLink}}),
data.NewField("Blob Count", data.Labels{"blobtype": "PageBlob"},
[]*float64{ptr.Float64(3), ptr.Float64(3), ptr.Float64(3), ptr.Float64(3), ptr.Float64(3), nil}).SetConfig(&data.FieldConfig{Unit: "short"})),
[]*float64{ptr.Float64(3), ptr.Float64(3), ptr.Float64(3), ptr.Float64(3), ptr.Float64(3), nil}).SetConfig(&data.FieldConfig{Unit: "short", Links: []data.DataLink{averageLink}})),
data.NewFrame("",
data.NewField("Time", nil,
makeDates(time.Date(2019, 2, 9, 15, 21, 0, 0, time.UTC), 6, time.Hour)),
makeDates(time.Date(2019, 2, 9, 15, 21, 0, 0, time.UTC), 6, time.Hour),
).SetConfig(&data.FieldConfig{Links: []data.DataLink{averageLink}}),
data.NewField("Blob Count", data.Labels{"blobtype": "BlockBlob"},
[]*float64{ptr.Float64(1), ptr.Float64(1), ptr.Float64(1), ptr.Float64(1), ptr.Float64(1), nil}).SetConfig(&data.FieldConfig{Unit: "short"})),
[]*float64{ptr.Float64(1), ptr.Float64(1), ptr.Float64(1), ptr.Float64(1), ptr.Float64(1), nil}).SetConfig(&data.FieldConfig{Unit: "short", Links: []data.DataLink{averageLink}})),
data.NewFrame("",
data.NewField("Time", nil,
makeDates(time.Date(2019, 2, 9, 15, 21, 0, 0, time.UTC), 6, time.Hour)),
makeDates(time.Date(2019, 2, 9, 15, 21, 0, 0, time.UTC), 6, time.Hour),
).SetConfig(&data.FieldConfig{Links: []data.DataLink{averageLink}}),
data.NewField("Blob Count", data.Labels{"blobtype": "Azure Data Lake Storage"},
[]*float64{ptr.Float64(0), ptr.Float64(0), ptr.Float64(0), ptr.Float64(0), ptr.Float64(0), nil}).SetConfig(&data.FieldConfig{Unit: "short"})),
[]*float64{ptr.Float64(0), ptr.Float64(0), ptr.Float64(0), ptr.Float64(0), ptr.Float64(0), nil}).SetConfig(&data.FieldConfig{Unit: "short", Links: []data.DataLink{averageLink}})),
},
},
{
@@ -336,10 +377,11 @@ func TestAzureMonitorParseResponse(t *testing.T) {
expectedFrames: data.Frames{
data.NewFrame("",
data.NewField("Time", nil,
makeDates(time.Date(2019, 2, 9, 13, 29, 0, 0, time.UTC), 5, time.Minute)),
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"})),
}).SetConfig(&data.FieldConfig{Unit: "percent", DisplayName: "custom grafanastaging Microsoft.Compute/virtualMachines grafana Percentage CPU", Links: []data.DataLink{totalLink}})),
},
},
{
@@ -357,23 +399,26 @@ func TestAzureMonitorParseResponse(t *testing.T) {
expectedFrames: data.Frames{
data.NewFrame("",
data.NewField("Time", nil,
makeDates(time.Date(2019, 2, 9, 15, 21, 0, 0, time.UTC), 6, time.Hour)),
makeDates(time.Date(2019, 2, 9, 15, 21, 0, 0, time.UTC), 6, time.Hour),
).SetConfig(&data.FieldConfig{Links: []data.DataLink{averageLink}}),
data.NewField("Blob Count", data.Labels{"blobtype": "PageBlob"},
[]*float64{ptr.Float64(3), ptr.Float64(3), ptr.Float64(3), ptr.Float64(3), ptr.Float64(3), nil}).SetConfig(&data.FieldConfig{Unit: "short", DisplayName: "blobtype=PageBlob"})),
[]*float64{ptr.Float64(3), ptr.Float64(3), ptr.Float64(3), ptr.Float64(3), ptr.Float64(3), nil}).SetConfig(&data.FieldConfig{Unit: "short", DisplayName: "blobtype=PageBlob", Links: []data.DataLink{averageLink}})),
data.NewFrame("",
data.NewField("Time", nil,
makeDates(time.Date(2019, 2, 9, 15, 21, 0, 0, time.UTC), 6, time.Hour)),
makeDates(time.Date(2019, 2, 9, 15, 21, 0, 0, time.UTC), 6, time.Hour),
).SetConfig(&data.FieldConfig{Links: []data.DataLink{averageLink}}),
data.NewField("Blob Count", data.Labels{"blobtype": "BlockBlob"}, []*float64{
ptr.Float64(1), ptr.Float64(1), ptr.Float64(1), ptr.Float64(1), ptr.Float64(1), nil,
}).SetConfig(&data.FieldConfig{Unit: "short", DisplayName: "blobtype=BlockBlob"})),
}).SetConfig(&data.FieldConfig{Unit: "short", DisplayName: "blobtype=BlockBlob", Links: []data.DataLink{averageLink}})),
data.NewFrame("",
data.NewField("Time", nil,
makeDates(time.Date(2019, 2, 9, 15, 21, 0, 0, time.UTC), 6, time.Hour)),
makeDates(time.Date(2019, 2, 9, 15, 21, 0, 0, time.UTC), 6, time.Hour),
).SetConfig(&data.FieldConfig{Links: []data.DataLink{averageLink}}),
data.NewField("Blob Count", data.Labels{"blobtype": "Azure Data Lake Storage"}, []*float64{
ptr.Float64(0), ptr.Float64(0), ptr.Float64(0), ptr.Float64(0), ptr.Float64(0), nil,
}).SetConfig(&data.FieldConfig{Unit: "short", DisplayName: "blobtype=Azure Data Lake Storage"})),
}).SetConfig(&data.FieldConfig{Unit: "short", DisplayName: "blobtype=Azure Data Lake Storage", Links: []data.DataLink{averageLink}})),
},
},
{
@@ -391,24 +436,27 @@ func TestAzureMonitorParseResponse(t *testing.T) {
expectedFrames: data.Frames{
data.NewFrame("",
data.NewField("Time", nil,
makeDates(time.Date(2020, 06, 30, 9, 58, 0, 0, time.UTC), 3, time.Hour)),
makeDates(time.Date(2020, 06, 30, 9, 58, 0, 0, time.UTC), 3, time.Hour),
).SetConfig(&data.FieldConfig{Links: []data.DataLink{averageLink}}),
data.NewField("Blob Capacity", data.Labels{"blobtype": "PageBlob", "tier": "Standard"},
[]*float64{ptr.Float64(675530), ptr.Float64(675530), ptr.Float64(675530)}).SetConfig(
&data.FieldConfig{Unit: "decbytes", DisplayName: "danieltest {Blob Type=PageBlob, Tier=Standard}"})),
&data.FieldConfig{Unit: "decbytes", DisplayName: "danieltest {Blob Type=PageBlob, Tier=Standard}", Links: []data.DataLink{averageLink}})),
data.NewFrame("",
data.NewField("Time", nil,
makeDates(time.Date(2020, 06, 30, 9, 58, 0, 0, time.UTC), 3, time.Hour)),
makeDates(time.Date(2020, 06, 30, 9, 58, 0, 0, time.UTC), 3, time.Hour),
).SetConfig(&data.FieldConfig{Links: []data.DataLink{averageLink}}),
data.NewField("Blob Capacity", data.Labels{"blobtype": "BlockBlob", "tier": "Hot"},
[]*float64{ptr.Float64(0), ptr.Float64(0), ptr.Float64(0)}).SetConfig(
&data.FieldConfig{Unit: "decbytes", DisplayName: "danieltest {Blob Type=BlockBlob, Tier=Hot}"})),
&data.FieldConfig{Unit: "decbytes", DisplayName: "danieltest {Blob Type=BlockBlob, Tier=Hot}", Links: []data.DataLink{averageLink}})),
data.NewFrame("",
data.NewField("Time", nil,
makeDates(time.Date(2020, 06, 30, 9, 58, 0, 0, time.UTC), 3, time.Hour)),
makeDates(time.Date(2020, 06, 30, 9, 58, 0, 0, time.UTC), 3, time.Hour),
).SetConfig(&data.FieldConfig{Links: []data.DataLink{averageLink}}),
data.NewField("Blob Capacity", data.Labels{"blobtype": "Azure Data Lake Storage", "tier": "Cool"},
[]*float64{ptr.Float64(0), ptr.Float64(0), ptr.Float64(0)}).SetConfig(
&data.FieldConfig{Unit: "decbytes", DisplayName: "danieltest {Blob Type=Azure Data Lake Storage, Tier=Cool}"})),
&data.FieldConfig{Unit: "decbytes", DisplayName: "danieltest {Blob Type=Azure Data Lake Storage, Tier=Cool}", Links: []data.DataLink{averageLink}})),
},
},
{
@@ -426,10 +474,11 @@ func TestAzureMonitorParseResponse(t *testing.T) {
expectedFrames: data.Frames{
data.NewFrame("",
data.NewField("Time", nil,
[]time.Time{time.Date(2019, 2, 8, 10, 13, 0, 0, time.UTC)}),
[]time.Time{time.Date(2019, 2, 8, 10, 13, 0, 0, time.UTC)},
).SetConfig(&data.FieldConfig{Links: []data.DataLink{averageLink}}),
data.NewField("Percentage CPU", nil, []*float64{
ptr.Float64(2.0875),
}).SetConfig(&data.FieldConfig{DisplayName: "custom"})),
}).SetConfig(&data.FieldConfig{DisplayName: "custom", Links: []data.DataLink{averageLink}})),
},
},
}
@@ -438,7 +487,7 @@ func TestAzureMonitorParseResponse(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
azData := loadTestFile(t, "azuremonitor/"+tt.responseFile)
dframes, err := datasource.parseResponse(azData, tt.mockQuery)
dframes, err := datasource.parseResponse(azData, tt.mockQuery, "http://ds")
require.NoError(t, err)
require.NotNil(t, dframes)
+16
View File
@@ -155,6 +155,22 @@ type argJSONQuery struct {
} `json:"azureResourceGraph"`
}
// metricChartDefinition is the JSON model for a metrics chart definition
type metricChartDefinition struct {
ResourceMetadata map[string]string `json:"resourceMetadata"`
Name string `json:"name"`
AggregationType int `json:"aggregationType"`
Namespace string `json:"namespace"`
MetricVisualization metricVisualization `json:"metricVisualization"`
}
// metricVisualization is the JSON model for the visualization field of a
// metricChartDefinition
type metricVisualization struct {
DisplayName string `json:"displayName"`
ResourceDisplayName string `json:"resourceDisplayName"`
}
// InsightsDimensions will unmarshal from a JSON string, or an array of strings,
// into a string array. This exists to support an older query format which is updated
// when a user saves the query or it is sent from the front end, but may not be when