From 6d0d60c8f5599fd548f1a661a417158998b9b08c Mon Sep 17 00:00:00 2001 From: Yarden Shoham Date: Wed, 8 Mar 2023 15:31:08 +0200 Subject: [PATCH] Azure Application Insights: Add option to ignore null values (#4329) Signed-off-by: Yarden Shoham --- CHANGELOG.md | 1 + pkg/scalers/azure/azure_app_insights.go | 10 ++++++--- pkg/scalers/azure_app_insights_scaler.go | 22 ++++++++++++++++++- pkg/scalers/azure_app_insights_scaler_test.go | 18 +++++++++++++++ 4 files changed, 47 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index faa36346846..56f8e0626d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -66,6 +66,7 @@ Here is an overview of all new **experimental** features: - **General**: Add a warning when KEDA run outside supported k8s versions ([#4130](https://github.com/kedacore/keda/issues/4130)) - **General**: Use (self-signed) certificates for all the communications (internals and externals) ([#3931](https://github.com/kedacore/keda/issues/3931)) - **General**: Use TLS1.2 as minimum TLS version ([#4193](https://github.com/kedacore/keda/issues/4193)) +- **Azure Application Insights Scaler**: Add ignoreNullValues to ignore errors when the data returned has null in its values ([#4316](https://github.com/kedacore/keda/issues/4316)) - **Azure Pipelines Scaler**: Improve error logging for `validatePoolID` ([#3996](https://github.com/kedacore/keda/issues/3996)) - **Azure Pipelines Scaler**: New configuration parameter `requireAllDemands` to scale only if jobs request all demands provided by the scaling definition ([#4138](https://github.com/kedacore/keda/issues/4138)) - **Hashicorp Vault**: Add support to secrets backend version 1 ([#2645](https://github.com/kedacore/keda/issues/2645)) diff --git a/pkg/scalers/azure/azure_app_insights.go b/pkg/scalers/azure/azure_app_insights.go index 2582dabe7e2..c4c64d78c34 100644 --- a/pkg/scalers/azure/azure_app_insights.go +++ b/pkg/scalers/azure/azure_app_insights.go @@ -89,7 +89,7 @@ func extractAppInsightValue(info AppInsightsInfo, metric ApplicationInsightsMetr } floatVal = val.(float64) } else { - return -1, fmt.Errorf("metric %s did not containe aggregation type %s", info.MetricID, info.AggregationType) + return -1, fmt.Errorf("metric %s did not contain aggregation type %s", info.MetricID, info.AggregationType) } azureAppInsightsLog.V(2).Info("value extracted from metric request", "metric type", info.AggregationType, "metric value", floatVal) @@ -115,7 +115,7 @@ func queryParamsForAppInsightsRequest(info AppInsightsInfo) (map[string]interfac } // GetAzureAppInsightsMetricValue returns the value of an Azure App Insights metric, rounded to the nearest int -func GetAzureAppInsightsMetricValue(ctx context.Context, info AppInsightsInfo, podIdentity kedav1alpha1.AuthPodIdentity) (float64, error) { +func GetAzureAppInsightsMetricValue(ctx context.Context, info AppInsightsInfo, podIdentity kedav1alpha1.AuthPodIdentity, ignoreNullValues bool) (float64, error) { config := getAuthConfig(ctx, info, podIdentity) authorizer, err := config.Authorizer() if err != nil { @@ -154,5 +154,9 @@ func GetAzureAppInsightsMetricValue(ctx context.Context, info AppInsightsInfo, p return -1, err } - return extractAppInsightValue(info, *metric) + val, err := extractAppInsightValue(info, *metric) + if err != nil && ignoreNullValues { + return 0.0, nil + } + return val, err } diff --git a/pkg/scalers/azure_app_insights_scaler.go b/pkg/scalers/azure_app_insights_scaler.go index a0663d8f500..d704bd3bde4 100644 --- a/pkg/scalers/azure_app_insights_scaler.go +++ b/pkg/scalers/azure_app_insights_scaler.go @@ -24,6 +24,11 @@ const ( azureAppInsightsMetricAggregationTypeName = "metricAggregationType" azureAppInsightsMetricFilterName = "metricFilter" azureAppInsightsTenantIDName = "tenantId" + azureAppInsightsIgnoreNullValues = "ignoreNullValues" +) + +var ( + azureAppInsightsDefaultIgnoreNullValues = false ) type azureAppInsightsMetadata struct { @@ -31,6 +36,11 @@ type azureAppInsightsMetadata struct { targetValue float64 activationTargetValue float64 scalerIndex int + // sometimes we should consider there is an error we can accept + // default value is true/t, to ignore the null value returned from prometheus + // change to false/f if you can not accept prometheus returning null values + // https://github.com/kedacore/keda/issues/4316 + ignoreNullValues bool } type azureAppInsightsScaler struct { @@ -139,6 +149,16 @@ func parseAzureAppInsightsMetadata(config *ScalerConfig, logger logr.Logger) (*a } meta.azureAppInsightsInfo.ActiveDirectoryEndpoint = activeDirectoryEndpoint + meta.ignoreNullValues = azureAppInsightsDefaultIgnoreNullValues + if val, ok := config.TriggerMetadata[azureAppInsightsIgnoreNullValues]; ok && val != "" { + azureAppInsightsIgnoreNullValues, err := strconv.ParseBool(val) + if err != nil { + return nil, fmt.Errorf("err incorrect value for azureAppInsightsIgnoreNullValues given: %s, "+ + "please use true or false", val) + } + meta.ignoreNullValues = azureAppInsightsIgnoreNullValues + } + // Required authentication parameters below val, err = getParameterFromConfig(config, azureAppInsightsAppIDName, true) @@ -182,7 +202,7 @@ func (s *azureAppInsightsScaler) GetMetricSpecForScaling(context.Context) []v2.M // GetMetricsAndActivity returns value for a supported metric and an error if there is a problem getting the metric func (s *azureAppInsightsScaler) GetMetricsAndActivity(ctx context.Context, metricName string) ([]external_metrics.ExternalMetricValue, bool, error) { - val, err := azure.GetAzureAppInsightsMetricValue(ctx, s.metadata.azureAppInsightsInfo, s.podIdentity) + val, err := azure.GetAzureAppInsightsMetricValue(ctx, s.metadata.azureAppInsightsInfo, s.podIdentity, s.metadata.ignoreNullValues) if err != nil { s.logger.Error(err, "error getting azure app insights metric") return []external_metrics.ExternalMetricValue{}, false, err diff --git a/pkg/scalers/azure_app_insights_scaler_test.go b/pkg/scalers/azure_app_insights_scaler_test.go index 0cab054a6df..41500918e11 100644 --- a/pkg/scalers/azure_app_insights_scaler_test.go +++ b/pkg/scalers/azure_app_insights_scaler_test.go @@ -138,6 +138,24 @@ var azureAppInsightsScalerData = []azureAppInsightsScalerTestData{ }, PodIdentity: kedav1alpha1.AuthPodIdentity{Provider: kedav1alpha1.PodIdentityProvider("notAzureWorkload")}, }}, + {name: "correct ignoreNullValues (true)", isError: false, config: ScalerConfig{ + TriggerMetadata: map[string]string{ + "targetValue": "11", "applicationInsightsId": "1234", "metricId": "unittest/test", "metricAggregationTimespan": "01:02", "metricAggregationType": "max", "metricFilter": "cloud/roleName eq 'test'", "tenantId": "1234", "ignoreNullValues": "true", + }, + PodIdentity: kedav1alpha1.AuthPodIdentity{Provider: kedav1alpha1.PodIdentityProviderAzureWorkload}, + }}, + {name: "correct ignoreNullValues (false)", isError: false, config: ScalerConfig{ + TriggerMetadata: map[string]string{ + "targetValue": "11", "applicationInsightsId": "1234", "metricId": "unittest/test", "metricAggregationTimespan": "01:02", "metricAggregationType": "max", "metricFilter": "cloud/roleName eq 'test'", "tenantId": "1234", "ignoreNullValues": "false", + }, + PodIdentity: kedav1alpha1.AuthPodIdentity{Provider: kedav1alpha1.PodIdentityProviderAzureWorkload}, + }}, + {name: "incorrect ignoreNullValues", isError: true, config: ScalerConfig{ + TriggerMetadata: map[string]string{ + "targetValue": "11", "applicationInsightsId": "1234", "metricId": "unittest/test", "metricAggregationTimespan": "01:02", "metricAggregationType": "max", "metricFilter": "cloud/roleName eq 'test'", "tenantId": "1234", "ignoreNullValues": "not a boolean", + }, + PodIdentity: kedav1alpha1.AuthPodIdentity{Provider: kedav1alpha1.PodIdentityProviderAzureWorkload}, + }}, {name: "app insights id in auth", isError: false, config: ScalerConfig{ TriggerMetadata: map[string]string{ "targetValue": "11", "metricId": "unittest/test", "metricAggregationTimespan": "01:02", "metricAggregationType": "max", "metricFilter": "cloud/roleName eq 'test'", "tenantId": "1234",