From 579595a5f98df7664204ad3ff53e36d2f967ee46 Mon Sep 17 00:00:00 2001 From: Vighnesh Shenoy Date: Fri, 25 Mar 2022 14:08:59 +0530 Subject: [PATCH 1/4] Enable support for non-public clouds in Application Insights scaler. Signed-off-by: Vighnesh Shenoy --- CHANGELOG.md | 3 +- pkg/scalers/azure/azure_app_insights.go | 34 ++++++++----- pkg/scalers/azure_app_insights_scaler.go | 28 +++++++++++ pkg/scalers/azure_app_insights_scaler_test.go | 50 +++++++++++++++++++ pkg/scalers/datadog_scaler.go | 4 +- 5 files changed, 104 insertions(+), 15 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..d130fe92bec 100644 --- a/pkg/scalers/azure/azure_app_insights.go +++ b/pkg/scalers/azure/azure_app_insights.go @@ -16,18 +16,27 @@ 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 + Cloud string + AppInsightsResourceURL string + ActiveDirectoryEndpoint string } type ApplicationInsightsMetric struct { @@ -55,12 +64,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 +125,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..271e08d7a97 100644 --- a/pkg/scalers/azure_app_insights_scaler.go +++ b/pkg/scalers/azure_app_insights_scaler.go @@ -13,6 +13,7 @@ import ( "k8s.io/metrics/pkg/apis/external_metrics" logf "sigs.k8s.io/controller-runtime/pkg/log" + az "github.com/Azure/go-autorest/autorest/azure" kedav1alpha1 "github.com/kedacore/keda/v2/apis/keda/v1alpha1" "github.com/kedacore/keda/v2/pkg/scalers/azure" kedautil "github.com/kedacore/keda/v2/pkg/util" @@ -97,6 +98,33 @@ func parseAzureAppInsightsMetadata(config *ScalerConfig) (*azureAppInsightsMetad meta.azureAppInsightsInfo.Filter = "" } + meta.azureAppInsightsInfo.Cloud = azure.DefaultCloud + meta.azureAppInsightsInfo.AppInsightsResourceURL = azure.DefaultAppInsightsResourceURL + + if cloud, ok := config.TriggerMetadata["cloud"]; ok { + meta.azureAppInsightsInfo.Cloud = cloud + 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) { diff --git a/pkg/scalers/datadog_scaler.go b/pkg/scalers/datadog_scaler.go index 888097b09bf..33cd224fa4d 100644 --- a/pkg/scalers/datadog_scaler.go +++ b/pkg/scalers/datadog_scaler.go @@ -191,7 +191,7 @@ func newDatadogConnection(ctx context.Context, meta *datadogMetadata, config *Sc configuration.HTTPClient = kedautil.CreateHTTPClient(config.GlobalHTTPTimeout, false) apiClient := datadog.NewAPIClient(configuration) - _, _, err := apiClient.AuthenticationApi.Validate(ctx) //nolint:bodyclose + _, _, err := apiClient.AuthenticationApi.Validate(ctx) if err != nil { return nil, fmt.Errorf("error connecting to Datadog API endpoint: %v", err) } @@ -236,7 +236,7 @@ func (s *datadogScaler) getQueryResult(ctx context.Context) (float64, error) { "site": s.metadata.datadogSite, }) - resp, r, err := s.apiClient.MetricsApi.QueryMetrics(ctx, time.Now().Unix()-int64(s.metadata.age), time.Now().Unix(), s.metadata.query) //nolint:bodyclose + resp, r, err := s.apiClient.MetricsApi.QueryMetrics(ctx, time.Now().Unix()-int64(s.metadata.age), time.Now().Unix(), s.metadata.query) if err != nil { return -1, fmt.Errorf("error when retrieving Datadog metrics: %s", err) } From f45b1b2e9cb06ae6e4ff83a2ec757600f45c3572 Mon Sep 17 00:00:00 2001 From: Vighnesh Shenoy Date: Fri, 25 Mar 2022 14:57:01 +0530 Subject: [PATCH 2/4] Revert DataDog scaler linter changes. Signed-off-by: Vighnesh Shenoy --- pkg/scalers/datadog_scaler.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/scalers/datadog_scaler.go b/pkg/scalers/datadog_scaler.go index 33cd224fa4d..888097b09bf 100644 --- a/pkg/scalers/datadog_scaler.go +++ b/pkg/scalers/datadog_scaler.go @@ -191,7 +191,7 @@ func newDatadogConnection(ctx context.Context, meta *datadogMetadata, config *Sc configuration.HTTPClient = kedautil.CreateHTTPClient(config.GlobalHTTPTimeout, false) apiClient := datadog.NewAPIClient(configuration) - _, _, err := apiClient.AuthenticationApi.Validate(ctx) + _, _, err := apiClient.AuthenticationApi.Validate(ctx) //nolint:bodyclose if err != nil { return nil, fmt.Errorf("error connecting to Datadog API endpoint: %v", err) } @@ -236,7 +236,7 @@ func (s *datadogScaler) getQueryResult(ctx context.Context) (float64, error) { "site": s.metadata.datadogSite, }) - resp, r, err := s.apiClient.MetricsApi.QueryMetrics(ctx, time.Now().Unix()-int64(s.metadata.age), time.Now().Unix(), s.metadata.query) + resp, r, err := s.apiClient.MetricsApi.QueryMetrics(ctx, time.Now().Unix()-int64(s.metadata.age), time.Now().Unix(), s.metadata.query) //nolint:bodyclose if err != nil { return -1, fmt.Errorf("error when retrieving Datadog metrics: %s", err) } From f3e2a689c4abdb1cb3232bd8325ffdbba5bb9d79 Mon Sep 17 00:00:00 2001 From: Vighnesh Shenoy Date: Fri, 25 Mar 2022 15:09:12 +0530 Subject: [PATCH 3/4] Remove unsused field from struct. Signed-off-by: Vighnesh Shenoy --- pkg/scalers/azure/azure_app_insights.go | 1 - pkg/scalers/azure_app_insights_scaler.go | 2 -- 2 files changed, 3 deletions(-) diff --git a/pkg/scalers/azure/azure_app_insights.go b/pkg/scalers/azure/azure_app_insights.go index d130fe92bec..5a8de634013 100644 --- a/pkg/scalers/azure/azure_app_insights.go +++ b/pkg/scalers/azure/azure_app_insights.go @@ -34,7 +34,6 @@ type AppInsightsInfo struct { Filter string ClientID string ClientPassword string - Cloud string AppInsightsResourceURL string ActiveDirectoryEndpoint string } diff --git a/pkg/scalers/azure_app_insights_scaler.go b/pkg/scalers/azure_app_insights_scaler.go index 271e08d7a97..e5bf9ad853c 100644 --- a/pkg/scalers/azure_app_insights_scaler.go +++ b/pkg/scalers/azure_app_insights_scaler.go @@ -98,11 +98,9 @@ func parseAzureAppInsightsMetadata(config *ScalerConfig) (*azureAppInsightsMetad meta.azureAppInsightsInfo.Filter = "" } - meta.azureAppInsightsInfo.Cloud = azure.DefaultCloud meta.azureAppInsightsInfo.AppInsightsResourceURL = azure.DefaultAppInsightsResourceURL if cloud, ok := config.TriggerMetadata["cloud"]; ok { - meta.azureAppInsightsInfo.Cloud = cloud if strings.EqualFold(cloud, azure.PrivateCloud) { if resource, ok := config.TriggerMetadata["appInsightsResourceURL"]; ok && resource != "" { meta.azureAppInsightsInfo.AppInsightsResourceURL = resource From 3a9f16795d4e707fb58b2b5d8ad3860d18c05015 Mon Sep 17 00:00:00 2001 From: Vighnesh Shenoy Date: Fri, 25 Mar 2022 18:13:09 +0530 Subject: [PATCH 4/4] Fix imports. Signed-off-by: Vighnesh Shenoy --- pkg/scalers/azure_app_insights_scaler.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/scalers/azure_app_insights_scaler.go b/pkg/scalers/azure_app_insights_scaler.go index e5bf9ad853c..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" @@ -13,7 +14,6 @@ import ( "k8s.io/metrics/pkg/apis/external_metrics" logf "sigs.k8s.io/controller-runtime/pkg/log" - az "github.com/Azure/go-autorest/autorest/azure" kedav1alpha1 "github.com/kedacore/keda/v2/apis/keda/v1alpha1" "github.com/kedacore/keda/v2/pkg/scalers/azure" kedautil "github.com/kedacore/keda/v2/pkg/util"