mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
AzureMonitor: Support multi-resource aliases and subscription aliases (#68648)
Update legend aliases - Add subscription response type - Update AzureMonitorQuery type - Update docs - Update tests - Add function to retrieve subscription display name if not present
This commit is contained in:
@@ -83,6 +83,8 @@ For example:
|
|||||||
|
|
||||||
| Alias pattern | Description |
|
| Alias pattern | Description |
|
||||||
| ----------------------------- | ------------------------------------------------------------------------------------------------------ |
|
| ----------------------------- | ------------------------------------------------------------------------------------------------------ |
|
||||||
|
| `{{ subscriptionid }}` | Replaced with the subscription ID. |
|
||||||
|
| `{{ subscription }}` | Replaced with the subscription name. |
|
||||||
| `{{ resourcegroup }}` | Replaced with the the resource group. |
|
| `{{ resourcegroup }}` | Replaced with the the resource group. |
|
||||||
| `{{ namespace }}` | Replaced with the resource type or namespace, such as `Microsoft.Compute/virtualMachines`. |
|
| `{{ namespace }}` | Replaced with the resource type or namespace, such as `Microsoft.Compute/virtualMachines`. |
|
||||||
| `{{ resourcename }}` | Replaced with the resource name. |
|
| `{{ resourcename }}` | Replaced with the resource name. |
|
||||||
|
|||||||
@@ -42,6 +42,8 @@ func (e *AzureMonitorDatasource) ResourceRequest(rw http.ResponseWriter, req *ht
|
|||||||
e.Proxy.Do(rw, req, cli)
|
e.Proxy.Do(rw, req, cli)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var subscriptions = map[string]string{}
|
||||||
|
|
||||||
// executeTimeSeriesQuery does the following:
|
// executeTimeSeriesQuery does the following:
|
||||||
// 1. build the AzureMonitor url and querystring for each query
|
// 1. build the AzureMonitor url and querystring for each query
|
||||||
// 2. executes each query by calling the Azure Monitor API
|
// 2. executes each query by calling the Azure Monitor API
|
||||||
@@ -112,6 +114,7 @@ func (e *AzureMonitorDatasource) buildQueries(logger log.Logger, queries []backe
|
|||||||
params.Add("region", azJSONModel.Region)
|
params.Add("region", azJSONModel.Region)
|
||||||
}
|
}
|
||||||
resourceIDs := []string{}
|
resourceIDs := []string{}
|
||||||
|
resourceMap := map[string]types.AzureMonitorResource{}
|
||||||
if hasOne, resourceGroup, resourceName := hasOneResource(queryJSONModel); hasOne {
|
if hasOne, resourceGroup, resourceName := hasOneResource(queryJSONModel); hasOne {
|
||||||
ub := urlBuilder{
|
ub := urlBuilder{
|
||||||
ResourceURI: azJSONModel.ResourceURI,
|
ResourceURI: azJSONModel.ResourceURI,
|
||||||
@@ -125,6 +128,7 @@ func (e *AzureMonitorDatasource) buildQueries(logger log.Logger, queries []backe
|
|||||||
azureURL = ub.BuildMetricsURL()
|
azureURL = ub.BuildMetricsURL()
|
||||||
// POST requests are only supported at the subscription level
|
// POST requests are only supported at the subscription level
|
||||||
filterInBody = false
|
filterInBody = false
|
||||||
|
resourceMap[ub.buildResourceURI()] = types.AzureMonitorResource{ResourceGroup: resourceGroup, ResourceName: resourceName}
|
||||||
} else {
|
} else {
|
||||||
for _, r := range azJSONModel.Resources {
|
for _, r := range azJSONModel.Resources {
|
||||||
ub := urlBuilder{
|
ub := urlBuilder{
|
||||||
@@ -134,7 +138,9 @@ func (e *AzureMonitorDatasource) buildQueries(logger log.Logger, queries []backe
|
|||||||
MetricNamespace: azJSONModel.MetricNamespace,
|
MetricNamespace: azJSONModel.MetricNamespace,
|
||||||
ResourceName: r.ResourceName,
|
ResourceName: r.ResourceName,
|
||||||
}
|
}
|
||||||
resourceIDs = append(resourceIDs, fmt.Sprintf("Microsoft.ResourceId eq '%s'", ub.buildResourceURI()))
|
resourceUri := ub.buildResourceURI()
|
||||||
|
resourceMap[resourceUri] = r
|
||||||
|
resourceIDs = append(resourceIDs, fmt.Sprintf("Microsoft.ResourceId eq '%s'", resourceUri))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,13 +186,15 @@ func (e *AzureMonitorDatasource) buildQueries(logger log.Logger, queries []backe
|
|||||||
}
|
}
|
||||||
|
|
||||||
query := &types.AzureMonitorQuery{
|
query := &types.AzureMonitorQuery{
|
||||||
URL: azureURL,
|
URL: azureURL,
|
||||||
Target: target,
|
Target: target,
|
||||||
Params: params,
|
Params: params,
|
||||||
RefID: query.RefID,
|
RefID: query.RefID,
|
||||||
Alias: alias,
|
Alias: alias,
|
||||||
TimeRange: query.TimeRange,
|
TimeRange: query.TimeRange,
|
||||||
Dimensions: azJSONModel.DimensionFilters,
|
Dimensions: azJSONModel.DimensionFilters,
|
||||||
|
Resources: resourceMap,
|
||||||
|
Subscription: queryJSONModel.Subscription,
|
||||||
}
|
}
|
||||||
if filterString != "" {
|
if filterString != "" {
|
||||||
if filterInBody {
|
if filterInBody {
|
||||||
@@ -201,6 +209,51 @@ func (e *AzureMonitorDatasource) buildQueries(logger log.Logger, queries []backe
|
|||||||
return azureMonitorQueries, nil
|
return azureMonitorQueries, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func retrieveSubscriptionDetails(e *AzureMonitorDatasource, cli *http.Client, ctx context.Context, logger log.Logger, tracer tracing.Tracer, subscriptionId string, baseUrl string, dsId int64, orgId int64) {
|
||||||
|
req, err := e.createRequest(ctx, logger, fmt.Sprintf("%s/subscriptions/%s", baseUrl, subscriptionId))
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("failed to retrieve subscription details for subscription %s: %s", subscriptionId, err)
|
||||||
|
}
|
||||||
|
values := req.URL.Query()
|
||||||
|
values.Add("api-version", "2022-12-01")
|
||||||
|
req.URL.RawQuery = values.Encode()
|
||||||
|
|
||||||
|
ctx, span := tracer.Start(ctx, "azuremonitor query")
|
||||||
|
span.SetAttributes("subscription", subscriptionId, attribute.Key("subscription").String(subscriptionId))
|
||||||
|
span.SetAttributes("datasource_id", dsId, attribute.Key("datasource_id").Int64(dsId))
|
||||||
|
span.SetAttributes("org_id", orgId, attribute.Key("org_id").Int64(orgId))
|
||||||
|
|
||||||
|
defer span.End()
|
||||||
|
tracer.Inject(ctx, req.Header, span)
|
||||||
|
logger.Debug("AzureMonitor", "Subscription Details Req")
|
||||||
|
res, err := cli.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
logger.Warn("failed to request subscription details: %s", err)
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if err := res.Body.Close(); err != nil {
|
||||||
|
logger.Warn("Failed to close response body", "err", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
body, err := io.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
logger.Warn("failed to read response body: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if res.StatusCode/100 != 2 {
|
||||||
|
logger.Warn("request failed, status: %s, error: %s", res.Status, string(body))
|
||||||
|
}
|
||||||
|
|
||||||
|
var data types.SubscriptionsResponse
|
||||||
|
err = json.Unmarshal(body, &data)
|
||||||
|
if err != nil {
|
||||||
|
logger.Warn("Failed to unmarshal subscription detail response", "error", err, "status", res.Status, "body", string(body))
|
||||||
|
}
|
||||||
|
|
||||||
|
subscriptions[data.SubscriptionID] = data.DisplayName
|
||||||
|
}
|
||||||
|
|
||||||
func (e *AzureMonitorDatasource) executeQuery(ctx context.Context, logger log.Logger, query *types.AzureMonitorQuery, dsInfo types.DatasourceInfo, cli *http.Client,
|
func (e *AzureMonitorDatasource) executeQuery(ctx context.Context, logger log.Logger, query *types.AzureMonitorQuery, dsInfo types.DatasourceInfo, cli *http.Client,
|
||||||
url string, tracer tracing.Tracer) backend.DataResponse {
|
url string, tracer tracing.Tracer) backend.DataResponse {
|
||||||
dataResponse := backend.DataResponse{}
|
dataResponse := backend.DataResponse{}
|
||||||
@@ -253,6 +306,10 @@ func (e *AzureMonitorDatasource) executeQuery(ctx context.Context, logger log.Lo
|
|||||||
return dataResponse
|
return dataResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if _, ok := subscriptions[query.Subscription]; !ok {
|
||||||
|
retrieveSubscriptionDetails(e, cli, ctx, logger, tracer, query.Subscription, dsInfo.Routes["Azure Monitor"].URL, dsInfo.DatasourceID, dsInfo.OrgID)
|
||||||
|
}
|
||||||
|
|
||||||
dataResponse.Frames, err = e.parseResponse(data, query, azurePortalUrl)
|
dataResponse.Frames, err = e.parseResponse(data, query, azurePortalUrl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
dataResponse.Error = err
|
dataResponse.Error = err
|
||||||
@@ -340,8 +397,9 @@ func (e *AzureMonitorDatasource) parseResponse(amr types.AzureMonitorResponse, q
|
|||||||
labels["resourceName"] = resourceName
|
labels["resourceName"] = resourceName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
currentResource := query.Resources[resourceID]
|
||||||
if query.Alias != "" {
|
if query.Alias != "" {
|
||||||
displayName := formatAzureMonitorLegendKey(query.Alias, resourceName,
|
displayName := formatAzureMonitorLegendKey(query.Alias, query.Subscription, currentResource,
|
||||||
amr.Value[0].Name.LocalizedValue, "", "", amr.Namespace, amr.Value[0].ID, labels)
|
amr.Value[0].Name.LocalizedValue, "", "", amr.Namespace, amr.Value[0].ID, labels)
|
||||||
|
|
||||||
if dataField.Config != nil {
|
if dataField.Config != nil {
|
||||||
@@ -379,7 +437,6 @@ func (e *AzureMonitorDatasource) parseResponse(amr types.AzureMonitorResponse, q
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
frameWithLink := loganalytics.AddConfigLinks(*frame, queryUrl, nil)
|
frameWithLink := loganalytics.AddConfigLinks(*frame, queryUrl, nil)
|
||||||
frames = append(frames, &frameWithLink)
|
frames = append(frames, &frameWithLink)
|
||||||
}
|
}
|
||||||
@@ -495,12 +552,8 @@ func getQueryUrl(query *types.AzureMonitorQuery, azurePortalUrl, resourceID, res
|
|||||||
|
|
||||||
// formatAzureMonitorLegendKey builds the legend key or timeseries name
|
// formatAzureMonitorLegendKey builds the legend key or timeseries name
|
||||||
// Alias patterns like {{resourcename}} are replaced with the appropriate data values.
|
// Alias patterns like {{resourcename}} are replaced with the appropriate data values.
|
||||||
func formatAzureMonitorLegendKey(alias string, resourceName string, metricName string, metadataName string,
|
func formatAzureMonitorLegendKey(alias string, subscriptionId string, resource types.AzureMonitorResource, metricName string, metadataName string,
|
||||||
metadataValue string, namespace string, seriesID string, labels data.Labels) string {
|
metadataValue string, namespace string, seriesID string, labels data.Labels) string {
|
||||||
startIndex := strings.Index(seriesID, "/resourceGroups/") + 16
|
|
||||||
endIndex := strings.Index(seriesID, "/providers")
|
|
||||||
resourceGroup := seriesID[startIndex:endIndex]
|
|
||||||
|
|
||||||
// Could be a collision problem if there were two keys that varied only in case, but I don't think that would happen in azure.
|
// Could be a collision problem if there were two keys that varied only in case, but I don't think that would happen in azure.
|
||||||
lowerLabels := data.Labels{}
|
lowerLabels := data.Labels{}
|
||||||
for k, v := range labels {
|
for k, v := range labels {
|
||||||
@@ -517,8 +570,20 @@ func formatAzureMonitorLegendKey(alias string, resourceName string, metricName s
|
|||||||
metaPartName = strings.Replace(metaPartName, "}}", "", 1)
|
metaPartName = strings.Replace(metaPartName, "}}", "", 1)
|
||||||
metaPartName = strings.ToLower(strings.TrimSpace(metaPartName))
|
metaPartName = strings.ToLower(strings.TrimSpace(metaPartName))
|
||||||
|
|
||||||
|
if metaPartName == "subscriptionid" {
|
||||||
|
return []byte(subscriptionId)
|
||||||
|
}
|
||||||
|
|
||||||
|
if metaPartName == "subscription" {
|
||||||
|
if subscription, ok := subscriptions[subscriptionId]; ok {
|
||||||
|
return []byte(subscription)
|
||||||
|
} else {
|
||||||
|
return []byte{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if metaPartName == "resourcegroup" {
|
if metaPartName == "resourcegroup" {
|
||||||
return []byte(resourceGroup)
|
return []byte(resource.ResourceGroup)
|
||||||
}
|
}
|
||||||
|
|
||||||
if metaPartName == "namespace" {
|
if metaPartName == "namespace" {
|
||||||
@@ -526,7 +591,7 @@ func formatAzureMonitorLegendKey(alias string, resourceName string, metricName s
|
|||||||
}
|
}
|
||||||
|
|
||||||
if metaPartName == "resourcename" {
|
if metaPartName == "resourcename" {
|
||||||
return []byte(resourceName)
|
return []byte(resource.ResourceName)
|
||||||
}
|
}
|
||||||
|
|
||||||
if metaPartName == "metric" {
|
if metaPartName == "metric" {
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ func TestAzureMonitorBuildQueries(t *testing.T) {
|
|||||||
expectedBodyFilter string
|
expectedBodyFilter string
|
||||||
expectedParamFilter string
|
expectedParamFilter string
|
||||||
expectedPortalURL *string
|
expectedPortalURL *string
|
||||||
|
resources map[string]types.AzureMonitorResource
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "Parse queries from frontend and build AzureMonitor API queries",
|
name: "Parse queries from frontend and build AzureMonitor API queries",
|
||||||
@@ -296,6 +297,16 @@ func TestAzureMonitorBuildQueries(t *testing.T) {
|
|||||||
queries, err := datasource.buildQueries(log.New("test"), tsdbQuery, dsInfo)
|
queries, err := datasource.buildQueries(log.New("test"), tsdbQuery, dsInfo)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
resources := map[string]types.AzureMonitorResource{}
|
||||||
|
if tt.azureMonitorVariedProperties["resources"] != nil {
|
||||||
|
resourceSlice := tt.azureMonitorVariedProperties["resources"].([]types.AzureMonitorResource)
|
||||||
|
for _, resource := range resourceSlice {
|
||||||
|
resources[fmt.Sprintf("/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/%s/providers/Microsoft.Compute/virtualMachines/%s", resource.ResourceGroup, resource.ResourceName)] = resource
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
resources["/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana"] = types.AzureMonitorResource{ResourceGroup: "grafanastaging", ResourceName: "grafana"}
|
||||||
|
}
|
||||||
|
|
||||||
azureMonitorQuery := &types.AzureMonitorQuery{
|
azureMonitorQuery := &types.AzureMonitorQuery{
|
||||||
URL: tt.expectedURL,
|
URL: tt.expectedURL,
|
||||||
Target: tt.azureMonitorQueryTarget,
|
Target: tt.azureMonitorQueryTarget,
|
||||||
@@ -305,7 +316,9 @@ func TestAzureMonitorBuildQueries(t *testing.T) {
|
|||||||
From: fromStart,
|
From: fromStart,
|
||||||
To: fromStart.Add(34 * time.Minute),
|
To: fromStart.Add(34 * time.Minute),
|
||||||
},
|
},
|
||||||
BodyFilter: tt.expectedBodyFilter,
|
BodyFilter: tt.expectedBodyFilter,
|
||||||
|
Subscription: "12345678-aaaa-bbbb-cccc-123456789abc",
|
||||||
|
Resources: resources,
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.Equal(t, tt.expectedParamFilter, queries[0].Params.Get("$filter"))
|
assert.Equal(t, tt.expectedParamFilter, queries[0].Params.Get("$filter"))
|
||||||
@@ -354,6 +367,10 @@ func TestCustomNamespace(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestAzureMonitorParseResponse(t *testing.T) {
|
func TestAzureMonitorParseResponse(t *testing.T) {
|
||||||
|
resources := map[string]types.AzureMonitorResource{}
|
||||||
|
resources["/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana"] = types.AzureMonitorResource{ResourceGroup: "grafanastaging", ResourceName: "grafana"}
|
||||||
|
subscription := "12345678-aaaa-bbbb-cccc-123456789abc"
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
responseFile string
|
responseFile string
|
||||||
@@ -369,6 +386,8 @@ func TestAzureMonitorParseResponse(t *testing.T) {
|
|||||||
Params: url.Values{
|
Params: url.Values{
|
||||||
"aggregation": {"Average"},
|
"aggregation": {"Average"},
|
||||||
},
|
},
|
||||||
|
Resources: resources,
|
||||||
|
Subscription: subscription,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -379,6 +398,8 @@ func TestAzureMonitorParseResponse(t *testing.T) {
|
|||||||
Params: url.Values{
|
Params: url.Values{
|
||||||
"aggregation": {"Total"},
|
"aggregation": {"Total"},
|
||||||
},
|
},
|
||||||
|
Resources: resources,
|
||||||
|
Subscription: subscription,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -389,6 +410,8 @@ func TestAzureMonitorParseResponse(t *testing.T) {
|
|||||||
Params: url.Values{
|
Params: url.Values{
|
||||||
"aggregation": {"Maximum"},
|
"aggregation": {"Maximum"},
|
||||||
},
|
},
|
||||||
|
Resources: resources,
|
||||||
|
Subscription: subscription,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -399,6 +422,8 @@ func TestAzureMonitorParseResponse(t *testing.T) {
|
|||||||
Params: url.Values{
|
Params: url.Values{
|
||||||
"aggregation": {"Minimum"},
|
"aggregation": {"Minimum"},
|
||||||
},
|
},
|
||||||
|
Resources: resources,
|
||||||
|
Subscription: subscription,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -409,6 +434,8 @@ func TestAzureMonitorParseResponse(t *testing.T) {
|
|||||||
Params: url.Values{
|
Params: url.Values{
|
||||||
"aggregation": {"Count"},
|
"aggregation": {"Count"},
|
||||||
},
|
},
|
||||||
|
Resources: resources,
|
||||||
|
Subscription: subscription,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -419,6 +446,8 @@ func TestAzureMonitorParseResponse(t *testing.T) {
|
|||||||
Params: url.Values{
|
Params: url.Values{
|
||||||
"aggregation": {"Average"},
|
"aggregation": {"Average"},
|
||||||
},
|
},
|
||||||
|
Resources: resources,
|
||||||
|
Subscription: subscription,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -430,6 +459,8 @@ func TestAzureMonitorParseResponse(t *testing.T) {
|
|||||||
Params: url.Values{
|
Params: url.Values{
|
||||||
"aggregation": {"Total"},
|
"aggregation": {"Total"},
|
||||||
},
|
},
|
||||||
|
Resources: resources,
|
||||||
|
Subscription: subscription,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -441,17 +472,21 @@ func TestAzureMonitorParseResponse(t *testing.T) {
|
|||||||
Params: url.Values{
|
Params: url.Values{
|
||||||
"aggregation": {"Average"},
|
"aggregation": {"Average"},
|
||||||
},
|
},
|
||||||
|
Resources: resources,
|
||||||
|
Subscription: subscription,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "multiple dimension time series response with label alias",
|
name: "multiple dimension time series response with label alias",
|
||||||
responseFile: "azuremonitor/7-azure-monitor-response-multi-dimension.json",
|
responseFile: "azuremonitor/7-azure-monitor-response-multi-dimension.json",
|
||||||
mockQuery: &types.AzureMonitorQuery{
|
mockQuery: &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/grafanatest/providers/Microsoft.Storage/storageAccounts/testblobaccount/blobServices/default/providers/Microsoft.Insights/metrics",
|
||||||
Alias: "{{resourcegroup}} {Blob Type={{blobtype}}, Tier={{Tier}}}",
|
Alias: "{{resourcegroup}} {Blob Type={{blobtype}}, Tier={{Tier}}}",
|
||||||
Params: url.Values{
|
Params: url.Values{
|
||||||
"aggregation": {"Average"},
|
"aggregation": {"Average"},
|
||||||
},
|
},
|
||||||
|
Resources: map[string]types.AzureMonitorResource{"/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanatest/providers/Microsoft.Storage/storageAccounts/testblobaccount/blobServices/default/providers/Microsoft.Insights/metrics": {ResourceGroup: "grafanatest", ResourceName: "testblobaccount"}},
|
||||||
|
Subscription: subscription,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -463,6 +498,8 @@ func TestAzureMonitorParseResponse(t *testing.T) {
|
|||||||
Params: url.Values{
|
Params: url.Values{
|
||||||
"aggregation": {"Average"},
|
"aggregation": {"Average"},
|
||||||
},
|
},
|
||||||
|
Resources: resources,
|
||||||
|
Subscription: subscription,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -474,6 +511,8 @@ func TestAzureMonitorParseResponse(t *testing.T) {
|
|||||||
Params: url.Values{
|
Params: url.Values{
|
||||||
"aggregation": {"Total"},
|
"aggregation": {"Total"},
|
||||||
},
|
},
|
||||||
|
Resources: resources,
|
||||||
|
Subscription: subscription,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -485,6 +524,8 @@ func TestAzureMonitorParseResponse(t *testing.T) {
|
|||||||
Params: url.Values{
|
Params: url.Values{
|
||||||
"aggregation": {"Total"},
|
"aggregation": {"Total"},
|
||||||
},
|
},
|
||||||
|
Resources: resources,
|
||||||
|
Subscription: subscription,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -495,6 +536,8 @@ func TestAzureMonitorParseResponse(t *testing.T) {
|
|||||||
Params: url.Values{
|
Params: url.Values{
|
||||||
"aggregation": {"Average"},
|
"aggregation": {"Average"},
|
||||||
},
|
},
|
||||||
|
Resources: resources,
|
||||||
|
Subscription: subscription,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -505,6 +548,8 @@ func TestAzureMonitorParseResponse(t *testing.T) {
|
|||||||
Params: url.Values{
|
Params: url.Values{
|
||||||
"aggregation": {"Average"},
|
"aggregation": {"Average"},
|
||||||
},
|
},
|
||||||
|
Resources: resources,
|
||||||
|
Subscription: subscription,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"interval": "PT1H",
|
"interval": "PT1H",
|
||||||
"value": [
|
"value": [
|
||||||
{
|
{
|
||||||
"id": "/subscriptions/44693801-6ee6-49de-9b2d-9106972f9572/resourceGroups/danieltest/providers/Microsoft.Storage/storageAccounts/danieltestdiag187/blobServices/default/providers/Microsoft.Insights/metrics/BlobCapacity",
|
"id": "/subscriptions/12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanatest/providers/Microsoft.Storage/storageAccounts/testblobaccount/blobServices/default/providers/Microsoft.Insights/metrics/BlobCapacity",
|
||||||
"type": "Microsoft.Insights/metrics",
|
"type": "Microsoft.Insights/metrics",
|
||||||
"name": {
|
"name": {
|
||||||
"value": "BlobCapacity",
|
"value": "BlobCapacity",
|
||||||
|
|||||||
@@ -62,7 +62,7 @@
|
|||||||
{
|
{
|
||||||
"title": "View in Azure Portal",
|
"title": "View in Azure Portal",
|
||||||
"targetBlank": true,
|
"targetBlank": true,
|
||||||
"url": "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%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"
|
"url": "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%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanatest%2Fproviders%2FMicrosoft.Storage%2FstorageAccounts%2Ftestblobaccount%2FblobServices%2Fdefault%2Fproviders%2FMicrosoft.Insights%2Fmetrics%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%22default%22%7D%7D%5D%7D%5D%7D"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -79,13 +79,13 @@
|
|||||||
"tier": "Standard"
|
"tier": "Standard"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"displayName": "danieltest {Blob Type=PageBlob, Tier=Standard}",
|
"displayName": "grafanatest {Blob Type=PageBlob, Tier=Standard}",
|
||||||
"unit": "decbytes",
|
"unit": "decbytes",
|
||||||
"links": [
|
"links": [
|
||||||
{
|
{
|
||||||
"title": "View in Azure Portal",
|
"title": "View in Azure Portal",
|
||||||
"targetBlank": true,
|
"targetBlank": true,
|
||||||
"url": "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%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"
|
"url": "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%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanatest%2Fproviders%2FMicrosoft.Storage%2FstorageAccounts%2Ftestblobaccount%2FblobServices%2Fdefault%2Fproviders%2FMicrosoft.Insights%2Fmetrics%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%22default%22%7D%7D%5D%7D%5D%7D"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -121,7 +121,7 @@
|
|||||||
{
|
{
|
||||||
"title": "View in Azure Portal",
|
"title": "View in Azure Portal",
|
||||||
"targetBlank": true,
|
"targetBlank": true,
|
||||||
"url": "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%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"
|
"url": "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%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanatest%2Fproviders%2FMicrosoft.Storage%2FstorageAccounts%2Ftestblobaccount%2FblobServices%2Fdefault%2Fproviders%2FMicrosoft.Insights%2Fmetrics%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%22default%22%7D%7D%5D%7D%5D%7D"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -138,13 +138,13 @@
|
|||||||
"tier": "Hot"
|
"tier": "Hot"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"displayName": "danieltest {Blob Type=BlockBlob, Tier=Hot}",
|
"displayName": "grafanatest {Blob Type=BlockBlob, Tier=Hot}",
|
||||||
"unit": "decbytes",
|
"unit": "decbytes",
|
||||||
"links": [
|
"links": [
|
||||||
{
|
{
|
||||||
"title": "View in Azure Portal",
|
"title": "View in Azure Portal",
|
||||||
"targetBlank": true,
|
"targetBlank": true,
|
||||||
"url": "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%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"
|
"url": "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%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanatest%2Fproviders%2FMicrosoft.Storage%2FstorageAccounts%2Ftestblobaccount%2FblobServices%2Fdefault%2Fproviders%2FMicrosoft.Insights%2Fmetrics%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%22default%22%7D%7D%5D%7D%5D%7D"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -180,7 +180,7 @@
|
|||||||
{
|
{
|
||||||
"title": "View in Azure Portal",
|
"title": "View in Azure Portal",
|
||||||
"targetBlank": true,
|
"targetBlank": true,
|
||||||
"url": "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%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"
|
"url": "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%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanatest%2Fproviders%2FMicrosoft.Storage%2FstorageAccounts%2Ftestblobaccount%2FblobServices%2Fdefault%2Fproviders%2FMicrosoft.Insights%2Fmetrics%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%22default%22%7D%7D%5D%7D%5D%7D"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -197,13 +197,13 @@
|
|||||||
"tier": "Cool"
|
"tier": "Cool"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"displayName": "danieltest {Blob Type=Azure Data Lake Storage, Tier=Cool}",
|
"displayName": "grafanatest {Blob Type=Azure Data Lake Storage, Tier=Cool}",
|
||||||
"unit": "decbytes",
|
"unit": "decbytes",
|
||||||
"links": [
|
"links": [
|
||||||
{
|
{
|
||||||
"title": "View in Azure Portal",
|
"title": "View in Azure Portal",
|
||||||
"targetBlank": true,
|
"targetBlank": true,
|
||||||
"url": "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%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"
|
"url": "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%2F12345678-aaaa-bbbb-cccc-123456789abc%2FresourceGroups%2Fgrafanatest%2Fproviders%2FMicrosoft.Storage%2FstorageAccounts%2Ftestblobaccount%2FblobServices%2Fdefault%2Fproviders%2FMicrosoft.Insights%2Fmetrics%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%22default%22%7D%7D%5D%7D%5D%7D"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,14 +65,16 @@ type DatasourceInfo struct {
|
|||||||
// AzureMonitorQuery is the query for all the services as they have similar queries
|
// AzureMonitorQuery is the query for all the services as they have similar queries
|
||||||
// with a url, a querystring and an alias field
|
// with a url, a querystring and an alias field
|
||||||
type AzureMonitorQuery struct {
|
type AzureMonitorQuery struct {
|
||||||
URL string
|
URL string
|
||||||
Target string
|
Target string
|
||||||
Params url.Values
|
Params url.Values
|
||||||
RefID string
|
RefID string
|
||||||
Alias string
|
Alias string
|
||||||
TimeRange backend.TimeRange
|
TimeRange backend.TimeRange
|
||||||
BodyFilter string
|
BodyFilter string
|
||||||
Dimensions []AzureMonitorDimensionFilter
|
Dimensions []AzureMonitorDimensionFilter
|
||||||
|
Resources map[string]AzureMonitorResource
|
||||||
|
Subscription string
|
||||||
}
|
}
|
||||||
|
|
||||||
// AzureMonitorResponse is the json response from the Azure Monitor API
|
// AzureMonitorResponse is the json response from the Azure Monitor API
|
||||||
@@ -274,4 +276,11 @@ type LogAnalyticsWorkspaceResponse struct {
|
|||||||
RetentionInDays int `json:"retentionInDays"`
|
RetentionInDays int `json:"retentionInDays"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SubscriptionsResponse struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
SubscriptionID string `json:"subscriptionId"`
|
||||||
|
TenantID string `json:"tenantId"`
|
||||||
|
DisplayName string `json:"displayName"`
|
||||||
|
}
|
||||||
|
|
||||||
var ErrorAzureHealthCheck = errors.New("health check failed")
|
var ErrorAzureHealthCheck = errors.New("health check failed")
|
||||||
|
|||||||
Reference in New Issue
Block a user