Commit fa9ffe38 by Daniel Lee Committed by GitHub

Azuremonitor: multiple subscription support for alerting (#17195)

* fix: azuremonitor adds multi-sub support to alerting

* fix: AzureMonitor missing parameter in metadata func

getMetricMetadata function when called in the query ctrl
was missing a parameter for Subscription Id.

Also, made some tweaks to what happens when a chained
dropdown is changed to not reset all the fields that
are dependent on it.
parent 744682e6
...@@ -85,14 +85,17 @@ func (e *AzureMonitorDatasource) buildQueries(queries []*tsdb.Query, timeRange * ...@@ -85,14 +85,17 @@ func (e *AzureMonitorDatasource) buildQueries(queries []*tsdb.Query, timeRange *
azlog.Debug("AzureMonitor", "target", azureMonitorTarget) azlog.Debug("AzureMonitor", "target", azureMonitorTarget)
urlComponents := map[string]string{} urlComponents := map[string]string{}
urlComponents["subscription"] = fmt.Sprintf("%v", query.Model.Get("subscription").MustString())
urlComponents["resourceGroup"] = fmt.Sprintf("%v", azureMonitorTarget["resourceGroup"]) urlComponents["resourceGroup"] = fmt.Sprintf("%v", azureMonitorTarget["resourceGroup"])
urlComponents["metricDefinition"] = fmt.Sprintf("%v", azureMonitorTarget["metricDefinition"]) urlComponents["metricDefinition"] = fmt.Sprintf("%v", azureMonitorTarget["metricDefinition"])
urlComponents["resourceName"] = fmt.Sprintf("%v", azureMonitorTarget["resourceName"]) urlComponents["resourceName"] = fmt.Sprintf("%v", azureMonitorTarget["resourceName"])
ub := urlBuilder{ ub := urlBuilder{
ResourceGroup: urlComponents["resourceGroup"], DefaultSubscription: query.DataSource.JsonData.Get("subscriptionId").MustString(),
MetricDefinition: urlComponents["metricDefinition"], Subscription: urlComponents["subscription"],
ResourceName: urlComponents["resourceName"], ResourceGroup: urlComponents["resourceGroup"],
MetricDefinition: urlComponents["metricDefinition"],
ResourceName: urlComponents["resourceName"],
} }
azureURL := ub.Build() azureURL := ub.Build()
...@@ -199,8 +202,7 @@ func (e *AzureMonitorDatasource) createRequest(ctx context.Context, dsInfo *mode ...@@ -199,8 +202,7 @@ func (e *AzureMonitorDatasource) createRequest(ctx context.Context, dsInfo *mode
} }
cloudName := dsInfo.JsonData.Get("cloudName").MustString("azuremonitor") cloudName := dsInfo.JsonData.Get("cloudName").MustString("azuremonitor")
subscriptionID := dsInfo.JsonData.Get("subscriptionId").MustString() proxyPass := fmt.Sprintf("%s/subscriptions", cloudName)
proxyPass := fmt.Sprintf("%s/subscriptions/%s", cloudName, subscriptionID)
u, _ := url.Parse(dsInfo.Url) u, _ := url.Parse(dsInfo.Url)
u.Path = path.Join(u.Path, "render") u.Path = path.Join(u.Path, "render")
......
...@@ -9,6 +9,7 @@ import ( ...@@ -9,6 +9,7 @@ import (
"time" "time"
"github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/tsdb" "github.com/grafana/grafana/pkg/tsdb"
. "github.com/smartystreets/goconvey/convey" . "github.com/smartystreets/goconvey/convey"
...@@ -27,7 +28,13 @@ func TestAzureMonitorDatasource(t *testing.T) { ...@@ -27,7 +28,13 @@ func TestAzureMonitorDatasource(t *testing.T) {
}, },
Queries: []*tsdb.Query{ Queries: []*tsdb.Query{
{ {
DataSource: &models.DataSource{
JsonData: simplejson.NewFromAny(map[string]interface{}{
"subscriptionId": "default-subscription",
}),
},
Model: simplejson.NewFromAny(map[string]interface{}{ Model: simplejson.NewFromAny(map[string]interface{}{
"subscription": "12345678-aaaa-bbbb-cccc-123456789abc",
"azureMonitor": map[string]interface{}{ "azureMonitor": map[string]interface{}{
"timeGrain": "PT1M", "timeGrain": "PT1M",
"aggregation": "Average", "aggregation": "Average",
...@@ -49,7 +56,7 @@ func TestAzureMonitorDatasource(t *testing.T) { ...@@ -49,7 +56,7 @@ func TestAzureMonitorDatasource(t *testing.T) {
So(len(queries), ShouldEqual, 1) So(len(queries), ShouldEqual, 1)
So(queries[0].RefID, ShouldEqual, "A") So(queries[0].RefID, ShouldEqual, "A")
So(queries[0].URL, ShouldEqual, "resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana/providers/microsoft.insights/metrics") So(queries[0].URL, ShouldEqual, "12345678-aaaa-bbbb-cccc-123456789abc/resourceGroups/grafanastaging/providers/Microsoft.Compute/virtualMachines/grafana/providers/microsoft.insights/metrics")
So(queries[0].Target, ShouldEqual, "aggregation=Average&api-version=2018-01-01&interval=PT1M&metricnames=Percentage+CPU&timespan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z") So(queries[0].Target, ShouldEqual, "aggregation=Average&api-version=2018-01-01&interval=PT1M&metricnames=Percentage+CPU&timespan=2018-03-15T13%3A00%3A00Z%2F2018-03-15T13%3A34%3A00Z")
So(len(queries[0].Params), ShouldEqual, 5) So(len(queries[0].Params), ShouldEqual, 5)
So(queries[0].Params["timespan"][0], ShouldEqual, "2018-03-15T13:00:00Z/2018-03-15T13:34:00Z") So(queries[0].Params["timespan"][0], ShouldEqual, "2018-03-15T13:00:00Z/2018-03-15T13:34:00Z")
......
...@@ -7,22 +7,30 @@ import ( ...@@ -7,22 +7,30 @@ import (
// urlBuilder builds the URL for calling the Azure Monitor API // urlBuilder builds the URL for calling the Azure Monitor API
type urlBuilder struct { type urlBuilder struct {
ResourceGroup string DefaultSubscription string
MetricDefinition string Subscription string
ResourceName string ResourceGroup string
MetricDefinition string
ResourceName string
} }
// Build checks the metric definition property to see which form of the url // Build checks the metric definition property to see which form of the url
// should be returned // should be returned
func (ub *urlBuilder) Build() string { func (ub *urlBuilder) Build() string {
subscription := ub.Subscription
if ub.Subscription == "" {
subscription = ub.DefaultSubscription
}
if strings.Count(ub.MetricDefinition, "/") > 1 { if strings.Count(ub.MetricDefinition, "/") > 1 {
rn := strings.Split(ub.ResourceName, "/") rn := strings.Split(ub.ResourceName, "/")
lastIndex := strings.LastIndex(ub.MetricDefinition, "/") lastIndex := strings.LastIndex(ub.MetricDefinition, "/")
service := ub.MetricDefinition[lastIndex+1:] service := ub.MetricDefinition[lastIndex+1:]
md := ub.MetricDefinition[0:lastIndex] md := ub.MetricDefinition[0:lastIndex]
return fmt.Sprintf("resourceGroups/%s/providers/%s/%s/%s/%s/providers/microsoft.insights/metrics", ub.ResourceGroup, md, rn[0], service, rn[1]) return fmt.Sprintf("%s/resourceGroups/%s/providers/%s/%s/%s/%s/providers/microsoft.insights/metrics", subscription, ub.ResourceGroup, md, rn[0], service, rn[1])
} }
return fmt.Sprintf("resourceGroups/%s/providers/%s/%s/providers/microsoft.insights/metrics", ub.ResourceGroup, ub.MetricDefinition, ub.ResourceName) return fmt.Sprintf("%s/resourceGroups/%s/providers/%s/%s/providers/microsoft.insights/metrics", subscription, ub.ResourceGroup, ub.MetricDefinition, ub.ResourceName)
} }
...@@ -11,35 +11,51 @@ func TestURLBuilder(t *testing.T) { ...@@ -11,35 +11,51 @@ func TestURLBuilder(t *testing.T) {
Convey("when metric definition is in the short form", func() { Convey("when metric definition is in the short form", func() {
ub := &urlBuilder{ ub := &urlBuilder{
ResourceGroup: "rg", DefaultSubscription: "default-sub",
MetricDefinition: "Microsoft.Compute/virtualMachines", ResourceGroup: "rg",
ResourceName: "rn", MetricDefinition: "Microsoft.Compute/virtualMachines",
ResourceName: "rn",
} }
url := ub.Build() url := ub.Build()
So(url, ShouldEqual, "resourceGroups/rg/providers/Microsoft.Compute/virtualMachines/rn/providers/microsoft.insights/metrics") So(url, ShouldEqual, "default-sub/resourceGroups/rg/providers/Microsoft.Compute/virtualMachines/rn/providers/microsoft.insights/metrics")
})
Convey("when metric definition is in the short form and a subscription is defined", func() {
ub := &urlBuilder{
DefaultSubscription: "default-sub",
Subscription: "specified-sub",
ResourceGroup: "rg",
MetricDefinition: "Microsoft.Compute/virtualMachines",
ResourceName: "rn",
}
url := ub.Build()
So(url, ShouldEqual, "specified-sub/resourceGroups/rg/providers/Microsoft.Compute/virtualMachines/rn/providers/microsoft.insights/metrics")
}) })
Convey("when metric definition is Microsoft.Storage/storageAccounts/blobServices", func() { Convey("when metric definition is Microsoft.Storage/storageAccounts/blobServices", func() {
ub := &urlBuilder{ ub := &urlBuilder{
ResourceGroup: "rg", DefaultSubscription: "default-sub",
MetricDefinition: "Microsoft.Storage/storageAccounts/blobServices", ResourceGroup: "rg",
ResourceName: "rn1/default", MetricDefinition: "Microsoft.Storage/storageAccounts/blobServices",
ResourceName: "rn1/default",
} }
url := ub.Build() url := ub.Build()
So(url, ShouldEqual, "resourceGroups/rg/providers/Microsoft.Storage/storageAccounts/rn1/blobServices/default/providers/microsoft.insights/metrics") So(url, ShouldEqual, "default-sub/resourceGroups/rg/providers/Microsoft.Storage/storageAccounts/rn1/blobServices/default/providers/microsoft.insights/metrics")
}) })
Convey("when metric definition is Microsoft.Storage/storageAccounts/fileServices", func() { Convey("when metric definition is Microsoft.Storage/storageAccounts/fileServices", func() {
ub := &urlBuilder{ ub := &urlBuilder{
ResourceGroup: "rg", DefaultSubscription: "default-sub",
MetricDefinition: "Microsoft.Storage/storageAccounts/fileServices", ResourceGroup: "rg",
ResourceName: "rn1/default", MetricDefinition: "Microsoft.Storage/storageAccounts/fileServices",
ResourceName: "rn1/default",
} }
url := ub.Build() url := ub.Build()
So(url, ShouldEqual, "resourceGroups/rg/providers/Microsoft.Storage/storageAccounts/rn1/fileServices/default/providers/microsoft.insights/metrics") So(url, ShouldEqual, "default-sub/resourceGroups/rg/providers/Microsoft.Storage/storageAccounts/rn1/fileServices/default/providers/microsoft.insights/metrics")
}) })
}) })
} }
...@@ -189,11 +189,19 @@ describe('AzureMonitorQueryCtrl', () => { ...@@ -189,11 +189,19 @@ describe('AzureMonitorQueryCtrl', () => {
}; };
beforeEach(() => { beforeEach(() => {
queryCtrl.target.subscription = 'sub1';
queryCtrl.target.azureMonitor.resourceGroup = 'test'; queryCtrl.target.azureMonitor.resourceGroup = 'test';
queryCtrl.target.azureMonitor.metricDefinition = 'Microsoft.Compute/virtualMachines'; queryCtrl.target.azureMonitor.metricDefinition = 'Microsoft.Compute/virtualMachines';
queryCtrl.target.azureMonitor.resourceName = 'test'; queryCtrl.target.azureMonitor.resourceName = 'test';
queryCtrl.target.azureMonitor.metricName = 'Percentage CPU'; queryCtrl.target.azureMonitor.metricName = 'Percentage CPU';
queryCtrl.datasource.getMetricMetadata = function(resourceGroup, metricDefinition, resourceName, metricName) { queryCtrl.datasource.getMetricMetadata = function(
subscription,
resourceGroup,
metricDefinition,
resourceName,
metricName
) {
expect(subscription).toBe('sub1');
expect(resourceGroup).toBe('test'); expect(resourceGroup).toBe('test');
expect(metricDefinition).toBe('Microsoft.Compute/virtualMachines'); expect(metricDefinition).toBe('Microsoft.Compute/virtualMachines');
expect(resourceName).toBe('test'); expect(resourceName).toBe('test');
......
...@@ -279,9 +279,6 @@ export class AzureMonitorQueryCtrl extends QueryCtrl { ...@@ -279,9 +279,6 @@ export class AzureMonitorQueryCtrl extends QueryCtrl {
} }
onResourceGroupChange() { onResourceGroupChange() {
this.target.azureMonitor.metricDefinition = this.defaultDropdownValue;
this.target.azureMonitor.resourceName = this.defaultDropdownValue;
this.target.azureMonitor.metricName = this.defaultDropdownValue;
this.target.azureMonitor.dimensions = []; this.target.azureMonitor.dimensions = [];
this.target.azureMonitor.dimension = ''; this.target.azureMonitor.dimension = '';
} }
...@@ -294,7 +291,6 @@ export class AzureMonitorQueryCtrl extends QueryCtrl { ...@@ -294,7 +291,6 @@ export class AzureMonitorQueryCtrl extends QueryCtrl {
} }
onResourceNameChange() { onResourceNameChange() {
this.target.azureMonitor.metricName = this.defaultDropdownValue;
this.target.azureMonitor.dimensions = []; this.target.azureMonitor.dimensions = [];
this.target.azureMonitor.dimension = ''; this.target.azureMonitor.dimension = '';
} }
...@@ -306,6 +302,7 @@ export class AzureMonitorQueryCtrl extends QueryCtrl { ...@@ -306,6 +302,7 @@ export class AzureMonitorQueryCtrl extends QueryCtrl {
return this.datasource return this.datasource
.getMetricMetadata( .getMetricMetadata(
this.replace(this.target.subscription),
this.replace(this.target.azureMonitor.resourceGroup), this.replace(this.target.azureMonitor.resourceGroup),
this.replace(this.target.azureMonitor.metricDefinition), this.replace(this.target.azureMonitor.metricDefinition),
this.replace(this.target.azureMonitor.resourceName), this.replace(this.target.azureMonitor.resourceName),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment