From 14c6043702644447afb0fbf8e10b7201c39d11df Mon Sep 17 00:00:00 2001 From: Vighnesh Shenoy Date: Fri, 25 Mar 2022 18:52:10 +0530 Subject: [PATCH] Enable support for non-public clouds in Application Insights scaler. (#2818) --- CHANGELOG.md | 3 +- pkg/scalers/azure/azure_app_insights.go | 33 +++++++----- pkg/scalers/azure_app_insights_scaler.go | 26 ++++++++++ pkg/scalers/azure_app_insights_scaler_test.go | 50 +++++++++++++++++++ 4 files changed, 99 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e9740242dd6..ed82b08b367 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,7 +40,8 @@ ### Improvements - **General:** Synchronize HPA annotations from ScaledObject ([#2659](https://github.com/kedacore/keda/pull/2659)) -- **Azure Event Hub Scaler:** Improve logging when blob container not found ([#2363]https://github.com/kedacore/keda/issues/2363) +- **Azure Application Insights Scaler:** Provide support for non-public clouds ([#2735](https://github.com/kedacore/keda/issues/2735)) +- **Azure Event Hub Scaler:** Improve logging when blob container not found ([#2363](https://github.com/kedacore/keda/issues/2363) - **Azure Event Hub Scaler:** Provide support for non-public clouds ([#1915](https://github.com/kedacore/keda/issues/1915)) - **Azure Queue:** Don't call Azure queue GetProperties API unnecessarily ([#2613](https://github.com/kedacore/keda/pull/2613)) - **Datadog Scaler:** Validate query to contain `{` to prevent panic on invalid query ([#2625](https://github.com/kedacore/keda/issues/2625)) diff --git a/pkg/scalers/azure/azure_app_insights.go b/pkg/scalers/azure/azure_app_insights.go index b6353a9bd0f..5a8de634013 100644 --- a/pkg/scalers/azure/azure_app_insights.go +++ b/pkg/scalers/azure/azure_app_insights.go @@ -16,18 +16,26 @@ import ( ) const ( - appInsightsResource = "https://api.applicationinsights.io" + DefaultAppInsightsResourceURL = "https://api.applicationinsights.io" ) +var AppInsightsResourceURLInCloud = map[string]string{ + "AZUREPUBLICCLOUD": "https://api.applicationinsights.io", + "AZUREUSGOVERNMENTCLOUD": "https://api.applicationinsights.us", + "AZURECHINACLOUD": "https://api.applicationinsights.azure.cn", +} + type AppInsightsInfo struct { - ApplicationInsightsID string - TenantID string - MetricID string - AggregationTimespan string - AggregationType string - Filter string - ClientID string - ClientPassword string + ApplicationInsightsID string + TenantID string + MetricID string + AggregationTimespan string + AggregationType string + Filter string + ClientID string + ClientPassword string + AppInsightsResourceURL string + ActiveDirectoryEndpoint string } type ApplicationInsightsMetric struct { @@ -55,12 +63,13 @@ func toISO8601(time string) (string, error) { func getAuthConfig(info AppInsightsInfo, podIdentity kedav1alpha1.PodIdentityProvider) auth.AuthorizerConfig { if podIdentity == "" || podIdentity == kedav1alpha1.PodIdentityProviderNone { config := auth.NewClientCredentialsConfig(info.ClientID, info.ClientPassword, info.TenantID) - config.Resource = appInsightsResource + config.Resource = info.AppInsightsResourceURL + config.AADEndpoint = info.ActiveDirectoryEndpoint return config } config := auth.NewMSIConfig() - config.Resource = appInsightsResource + config.Resource = info.AppInsightsResourceURL return config } @@ -115,7 +124,7 @@ func GetAzureAppInsightsMetricValue(ctx context.Context, info AppInsightsInfo, p } req, err := autorest.Prepare(&http.Request{}, - autorest.WithBaseURL(appInsightsResource), + autorest.WithBaseURL(info.AppInsightsResourceURL), autorest.WithPath("v1/apps"), autorest.WithPath(info.ApplicationInsightsID), autorest.WithPath("metrics"), diff --git a/pkg/scalers/azure_app_insights_scaler.go b/pkg/scalers/azure_app_insights_scaler.go index 636eff3d856..8a1e7159fa3 100644 --- a/pkg/scalers/azure_app_insights_scaler.go +++ b/pkg/scalers/azure_app_insights_scaler.go @@ -6,6 +6,7 @@ import ( "strconv" "strings" + az "github.com/Azure/go-autorest/autorest/azure" v2beta2 "k8s.io/api/autoscaling/v2beta2" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -97,6 +98,31 @@ func parseAzureAppInsightsMetadata(config *ScalerConfig) (*azureAppInsightsMetad meta.azureAppInsightsInfo.Filter = "" } + meta.azureAppInsightsInfo.AppInsightsResourceURL = azure.DefaultAppInsightsResourceURL + + if cloud, ok := config.TriggerMetadata["cloud"]; ok { + if strings.EqualFold(cloud, azure.PrivateCloud) { + if resource, ok := config.TriggerMetadata["appInsightsResourceURL"]; ok && resource != "" { + meta.azureAppInsightsInfo.AppInsightsResourceURL = resource + } else { + return nil, fmt.Errorf("appInsightsResourceURL must be provided for %s cloud type", azure.PrivateCloud) + } + } else if resource, ok := azure.AppInsightsResourceURLInCloud[strings.ToUpper(cloud)]; ok { + meta.azureAppInsightsInfo.AppInsightsResourceURL = resource + } else { + return nil, fmt.Errorf("there is no cloud environment matching the name %s", cloud) + } + } + + activeDirectoryEndpointProvider := func(env az.Environment) (string, error) { + return env.ActiveDirectoryEndpoint, nil + } + activeDirectoryEndpoint, err := azure.ParseEnvironmentProperty(config.TriggerMetadata, "activeDirectoryEndpoint", activeDirectoryEndpointProvider) + if err != nil { + return nil, err + } + meta.azureAppInsightsInfo.ActiveDirectoryEndpoint = activeDirectoryEndpoint + // Required authentication parameters below val, err = getParameterFromConfig(config, azureAppInsightsAppIDName, true) diff --git a/pkg/scalers/azure_app_insights_scaler_test.go b/pkg/scalers/azure_app_insights_scaler_test.go index 80918e97201..345b01b8b9c 100644 --- a/pkg/scalers/azure_app_insights_scaler_test.go +++ b/pkg/scalers/azure_app_insights_scaler_test.go @@ -140,6 +140,56 @@ var azureAppInsightsScalerData = []azureAppInsightsScalerTestData{ "AD_CLIENT_ID": "5678", "AD_CLIENT_PASSWORD": "pw", "APP_INSIGHTS_ID": "1234", "TENANT_ID": "1234", }, }}, + {name: "known Azure Cloud", isError: false, config: ScalerConfig{ + TriggerMetadata: map[string]string{ + "metricAggregationTimespan": "00:01", "metricAggregationType": "count", "metricId": "unittest/test", "targetValue": "10", + "applicationInsightsId": "appinsightid", "tenantId": "tenantid", + "cloud": "azureChinaCloud", + }, + AuthParams: map[string]string{ + "tenantId": "tenantId", "activeDirectoryClientId": "adClientId", "activeDirectoryClientPassword": "adClientPassword", + }, + }}, + {name: "private cloud", isError: false, config: ScalerConfig{ + TriggerMetadata: map[string]string{ + "metricAggregationTimespan": "00:01", "metricAggregationType": "count", "metricId": "unittest/test", "targetValue": "10", + "applicationInsightsId": "appinsightid", "tenantId": "tenantid", + "cloud": "private", "appInsightsResourceURL": "appInsightsResourceURL", "activeDirectoryEndpoint": "adEndpoint", + }, + AuthParams: map[string]string{ + "tenantId": "tenantId", "activeDirectoryClientId": "adClientId", "activeDirectoryClientPassword": "adClientPassword", + }, + }}, + {name: "private cloud - missing app insights resource URL", isError: true, config: ScalerConfig{ + TriggerMetadata: map[string]string{ + "metricAggregationTimespan": "00:01", "metricAggregationType": "count", "metricId": "unittest/test", "targetValue": "10", + "applicationInsightsId": "appinsightid", "tenantId": "tenantid", + "cloud": "private", "activeDirectoryEndpoint": "adEndpoint", + }, + AuthParams: map[string]string{ + "tenantId": "tenantId", "activeDirectoryClientId": "adClientId", "activeDirectoryClientPassword": "adClientPassword", + }, + }}, + {name: "private cloud - missing active directory endpoint", isError: true, config: ScalerConfig{ + TriggerMetadata: map[string]string{ + "metricAggregationTimespan": "00:01", "metricAggregationType": "count", "metricId": "unittest/test", "targetValue": "10", + "applicationInsightsId": "appinsightid", "tenantId": "tenantid", + "cloud": "private", "appInsightsResourceURL": "appInsightsResourceURL", + }, + AuthParams: map[string]string{ + "tenantId": "tenantId", "activeDirectoryClientId": "adClientId", "activeDirectoryClientPassword": "adClientPassword", + }, + }}, + {name: "unsupported cloud", isError: true, config: ScalerConfig{ + TriggerMetadata: map[string]string{ + "metricAggregationTimespan": "00:01", "metricAggregationType": "count", "metricId": "unittest/test", "targetValue": "10", + "applicationInsightsId": "appinsightid", "tenantId": "tenantid", + "cloud": "azureGermanCloud", + }, + AuthParams: map[string]string{ + "tenantId": "tenantId", "activeDirectoryClientId": "adClientId", "activeDirectoryClientPassword": "adClientPassword", + }, + }}, } func TestNewAzureAppInsightsScaler(t *testing.T) {