Browse Source

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.
Daniel Lee 6 years ago
parent
commit
fa9ffe38d2

+ 7 - 5
pkg/tsdb/azuremonitor/azuremonitor-datasource.go

@@ -85,14 +85,17 @@ func (e *AzureMonitorDatasource) buildQueries(queries []*tsdb.Query, timeRange *
 		azlog.Debug("AzureMonitor", "target", azureMonitorTarget)
 
 		urlComponents := map[string]string{}
+		urlComponents["subscription"] = fmt.Sprintf("%v", query.Model.Get("subscription").MustString())
 		urlComponents["resourceGroup"] = fmt.Sprintf("%v", azureMonitorTarget["resourceGroup"])
 		urlComponents["metricDefinition"] = fmt.Sprintf("%v", azureMonitorTarget["metricDefinition"])
 		urlComponents["resourceName"] = fmt.Sprintf("%v", azureMonitorTarget["resourceName"])
 
 		ub := urlBuilder{
-			ResourceGroup:    urlComponents["resourceGroup"],
-			MetricDefinition: urlComponents["metricDefinition"],
-			ResourceName:     urlComponents["resourceName"],
+			DefaultSubscription: query.DataSource.JsonData.Get("subscriptionId").MustString(),
+			Subscription:        urlComponents["subscription"],
+			ResourceGroup:       urlComponents["resourceGroup"],
+			MetricDefinition:    urlComponents["metricDefinition"],
+			ResourceName:        urlComponents["resourceName"],
 		}
 		azureURL := ub.Build()
 
@@ -199,8 +202,7 @@ func (e *AzureMonitorDatasource) createRequest(ctx context.Context, dsInfo *mode
 	}
 
 	cloudName := dsInfo.JsonData.Get("cloudName").MustString("azuremonitor")
-	subscriptionID := dsInfo.JsonData.Get("subscriptionId").MustString()
-	proxyPass := fmt.Sprintf("%s/subscriptions/%s", cloudName, subscriptionID)
+	proxyPass := fmt.Sprintf("%s/subscriptions", cloudName)
 
 	u, _ := url.Parse(dsInfo.Url)
 	u.Path = path.Join(u.Path, "render")

+ 8 - 1
pkg/tsdb/azuremonitor/azuremonitor-datasource_test.go

@@ -9,6 +9,7 @@ import (
 	"time"
 
 	"github.com/grafana/grafana/pkg/components/simplejson"
+	"github.com/grafana/grafana/pkg/models"
 	"github.com/grafana/grafana/pkg/tsdb"
 
 	. "github.com/smartystreets/goconvey/convey"
@@ -27,7 +28,13 @@ func TestAzureMonitorDatasource(t *testing.T) {
 				},
 				Queries: []*tsdb.Query{
 					{
+						DataSource: &models.DataSource{
+							JsonData: simplejson.NewFromAny(map[string]interface{}{
+								"subscriptionId": "default-subscription",
+							}),
+						},
 						Model: simplejson.NewFromAny(map[string]interface{}{
+							"subscription": "12345678-aaaa-bbbb-cccc-123456789abc",
 							"azureMonitor": map[string]interface{}{
 								"timeGrain":        "PT1M",
 								"aggregation":      "Average",
@@ -49,7 +56,7 @@ func TestAzureMonitorDatasource(t *testing.T) {
 
 				So(len(queries), ShouldEqual, 1)
 				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(len(queries[0].Params), ShouldEqual, 5)
 				So(queries[0].Params["timespan"][0], ShouldEqual, "2018-03-15T13:00:00Z/2018-03-15T13:34:00Z")

+ 13 - 5
pkg/tsdb/azuremonitor/url-builder.go

@@ -7,22 +7,30 @@ import (
 
 // urlBuilder builds the URL for calling the Azure Monitor API
 type urlBuilder struct {
-	ResourceGroup    string
-	MetricDefinition string
-	ResourceName     string
+	DefaultSubscription string
+	Subscription        string
+	ResourceGroup       string
+	MetricDefinition    string
+	ResourceName        string
 }
 
 // Build checks the metric definition property to see which form of the url
 // should be returned
 func (ub *urlBuilder) Build() string {
 
+	subscription := ub.Subscription
+
+	if ub.Subscription == "" {
+		subscription = ub.DefaultSubscription
+	}
+
 	if strings.Count(ub.MetricDefinition, "/") > 1 {
 		rn := strings.Split(ub.ResourceName, "/")
 		lastIndex := strings.LastIndex(ub.MetricDefinition, "/")
 		service := ub.MetricDefinition[lastIndex+1:]
 		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)
 }

+ 28 - 12
pkg/tsdb/azuremonitor/url-builder_test.go

@@ -11,35 +11,51 @@ func TestURLBuilder(t *testing.T) {
 
 		Convey("when metric definition is in the short form", func() {
 			ub := &urlBuilder{
-				ResourceGroup:    "rg",
-				MetricDefinition: "Microsoft.Compute/virtualMachines",
-				ResourceName:     "rn",
+				DefaultSubscription: "default-sub",
+				ResourceGroup:       "rg",
+				MetricDefinition:    "Microsoft.Compute/virtualMachines",
+				ResourceName:        "rn",
 			}
 
 			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() {
 			ub := &urlBuilder{
-				ResourceGroup:    "rg",
-				MetricDefinition: "Microsoft.Storage/storageAccounts/blobServices",
-				ResourceName:     "rn1/default",
+				DefaultSubscription: "default-sub",
+				ResourceGroup:       "rg",
+				MetricDefinition:    "Microsoft.Storage/storageAccounts/blobServices",
+				ResourceName:        "rn1/default",
 			}
 
 			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() {
 			ub := &urlBuilder{
-				ResourceGroup:    "rg",
-				MetricDefinition: "Microsoft.Storage/storageAccounts/fileServices",
-				ResourceName:     "rn1/default",
+				DefaultSubscription: "default-sub",
+				ResourceGroup:       "rg",
+				MetricDefinition:    "Microsoft.Storage/storageAccounts/fileServices",
+				ResourceName:        "rn1/default",
 			}
 
 			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")
 		})
 	})
 }

+ 9 - 1
public/app/plugins/datasource/grafana-azure-monitor-datasource/query_ctrl.test.ts

@@ -189,11 +189,19 @@ describe('AzureMonitorQueryCtrl', () => {
       };
 
       beforeEach(() => {
+        queryCtrl.target.subscription = 'sub1';
         queryCtrl.target.azureMonitor.resourceGroup = 'test';
         queryCtrl.target.azureMonitor.metricDefinition = 'Microsoft.Compute/virtualMachines';
         queryCtrl.target.azureMonitor.resourceName = 'test';
         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(metricDefinition).toBe('Microsoft.Compute/virtualMachines');
           expect(resourceName).toBe('test');

+ 1 - 4
public/app/plugins/datasource/grafana-azure-monitor-datasource/query_ctrl.ts

@@ -279,9 +279,6 @@ export class AzureMonitorQueryCtrl extends QueryCtrl {
   }
 
   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.dimension = '';
   }
@@ -294,7 +291,6 @@ export class AzureMonitorQueryCtrl extends QueryCtrl {
   }
 
   onResourceNameChange() {
-    this.target.azureMonitor.metricName = this.defaultDropdownValue;
     this.target.azureMonitor.dimensions = [];
     this.target.azureMonitor.dimension = '';
   }
@@ -306,6 +302,7 @@ export class AzureMonitorQueryCtrl extends QueryCtrl {
 
     return this.datasource
       .getMetricMetadata(
+        this.replace(this.target.subscription),
         this.replace(this.target.azureMonitor.resourceGroup),
         this.replace(this.target.azureMonitor.metricDefinition),
         this.replace(this.target.azureMonitor.resourceName),