From dc0a42a035157cadad028e722b5f5f0395c37894 Mon Sep 17 00:00:00 2001 From: magodo Date: Mon, 3 Aug 2020 17:20:32 +0800 Subject: [PATCH 1/2] WIP --- .../monitor/monitor_metric_alert_resource.go | 78 +++++++++++++++---- 1 file changed, 65 insertions(+), 13 deletions(-) diff --git a/azurerm/internal/services/monitor/monitor_metric_alert_resource.go b/azurerm/internal/services/monitor/monitor_metric_alert_resource.go index 3d97784d7f50..a51484ad19e1 100644 --- a/azurerm/internal/services/monitor/monitor_metric_alert_resource.go +++ b/azurerm/internal/services/monitor/monitor_metric_alert_resource.go @@ -399,10 +399,20 @@ func resourceArmMonitorMetricAlertCreateUpdate(d *schema.ResourceData, meta inte t := d.Get("tags").(map[string]interface{}) expandedTags := tags.Expand(t) + + // To keep backward compatibility for the "old" created resources, whose criteria type + // is `MetricAlertSingleResourceMultipleMetricCriteria` (rather than `MetricAlertMultipleResourceMultipleMetricCriteria`). + // We need to check whether this is such an "old" resource already existed. + existing, err := client.Get(ctx, resourceGroup, name) + if err != nil { + // TODO + } + criteria, err := expandMonitorMetricAlertCriteria(d) if err != nil { return fmt.Errorf(`Expanding criteria: %+v`, err) } + parameters := insights.MetricAlertResource{ Location: utils.String(azure.NormalizeLocation("Global")), MetricAlertProperties: &insights.MetricAlertProperties{ @@ -646,19 +656,9 @@ func expandMonitorMetricAlertAction(input []interface{}) *[]insights.MetricAlert func flattenMonitorMetricAlertCriteria(input insights.BasicMetricAlertCriteria) []interface{} { switch criteria := input.(type) { case insights.MetricAlertSingleResourceMultipleMetricCriteria: - // As service is gonna deprecate data type of `MetricAlertSingleResourceMultipleMetricCriteria`, - // we use the same function to handle both single/multiple ResourceMultipleMetricCriteria cases. - // This is possible because their `AllOf` member implement the same interface: `MultiMetricCriteria`. - if criteria.AllOf == nil { - return nil - } - l := make([]insights.BasicMultiMetricCriteria, len(*criteria.AllOf)) - for i, c := range *criteria.AllOf { - l[i] = c - } - return flattenMonitorMetricAlertMultiMetricCriteria(&l) + return flattenMonitorMetricAlertSingleResourceMultiMetricCriteria(criteria.AllOf) case insights.MetricAlertMultipleResourceMultipleMetricCriteria: - return flattenMonitorMetricAlertMultiMetricCriteria(criteria.AllOf) + return flattenMonitorMetricAlertMultiResourceMultiMetricCriteria(criteria.AllOf) case insights.WebtestLocationAvailabilityCriteria: return flattenMonitorMetricAlertWebtestLocAvailCriteria(&criteria) default: @@ -666,7 +666,59 @@ func flattenMonitorMetricAlertCriteria(input insights.BasicMetricAlertCriteria) } } -func flattenMonitorMetricAlertMultiMetricCriteria(input *[]insights.BasicMultiMetricCriteria) []interface{} { +func flattenMonitorMetricAlertSingleResourceMultiMetricCriteria(input *[]insights.MetricCriteria) []interface{} { + if input == nil || len(*input) == 0 { + return nil + } + criteria := (*input)[0] + + metricName := "" + if criteria.MetricName != nil { + metricName = *criteria.MetricName + } + + metricNamespace := "" + if criteria.MetricNamespace != nil { + metricNamespace = *criteria.MetricNamespace + } + + timeAggregation := criteria.TimeAggregation + + dimResult := make([]map[string]interface{}, 0) + if criteria.Dimensions != nil { + for _, dimension := range *criteria.Dimensions { + dVal := make(map[string]interface{}) + if dimension.Name != nil { + dVal["name"] = *dimension.Name + } + if dimension.Operator != nil { + dVal["operator"] = *dimension.Operator + } + dVal["values"] = utils.FlattenStringSlice(dimension.Values) + dimResult = append(dimResult, dVal) + } + } + + operator := string(criteria.Operator) + + threshold := 0.0 + if criteria.Threshold != nil { + threshold = *criteria.Threshold + } + + return []interface{}{ + map[string]interface{}{ + "metric_namespace": metricNamespace, + "metric_name": metricName, + "aggregation": timeAggregation, + "dimension": dimResult, + "operator": operator, + "threshold": threshold, + }, + } +} + +func flattenMonitorMetricAlertMultiResourceMultiMetricCriteria(input *[]insights.BasicMultiMetricCriteria) []interface{} { if input == nil { return nil } From 2787a60b937973465c6be2103bd5d7ffadbbf0b9 Mon Sep 17 00:00:00 2001 From: magodo Date: Tue, 4 Aug 2020 10:25:03 +0800 Subject: [PATCH 2/2] azurerm_monitor_metric_alert_resource: keep using SingleResourceMultiMetricCriteria for legacy metric alerts --- .../monitor/monitor_metric_alert_resource.go | 63 ++++++++++++++----- 1 file changed, 47 insertions(+), 16 deletions(-) diff --git a/azurerm/internal/services/monitor/monitor_metric_alert_resource.go b/azurerm/internal/services/monitor/monitor_metric_alert_resource.go index a51484ad19e1..f24a11c20e2b 100644 --- a/azurerm/internal/services/monitor/monitor_metric_alert_resource.go +++ b/azurerm/internal/services/monitor/monitor_metric_alert_resource.go @@ -399,16 +399,22 @@ func resourceArmMonitorMetricAlertCreateUpdate(d *schema.ResourceData, meta inte t := d.Get("tags").(map[string]interface{}) expandedTags := tags.Expand(t) - - // To keep backward compatibility for the "old" created resources, whose criteria type - // is `MetricAlertSingleResourceMultipleMetricCriteria` (rather than `MetricAlertMultipleResourceMultipleMetricCriteria`). - // We need to check whether this is such an "old" resource already existed. - existing, err := client.Get(ctx, resourceGroup, name) - if err != nil { - // TODO + // The criteria type of "old" resource is `MetricAlertSingleResourceMultipleMetricCriteria` (rather than `MetricAlertMultipleResourceMultipleMetricCriteria`). + // We need to keep using that type in order to keep backward compatibility. Otherwise, changing the criteria type will cause error as reported in issue: + // https://github.com/terraform-providers/terraform-provider-azurerm/issues/7910 + var isLegacy bool + if !d.IsNewResource() { + existing, err := client.Get(ctx, resourceGroup, name) + if err != nil { + return fmt.Errorf("retrieving Monitor Metric Alert %q (Resource Group %q): %+v", name, resourceGroup, err) + } + if existing.MetricAlertProperties == nil || existing.MetricAlertProperties.Criteria == nil { + return fmt.Errorf("unexpected nil properties of Monitor Metric Alert %q (Resource Group %q)", name, resourceGroup) + } + _, isLegacy = existing.MetricAlertProperties.Criteria.AsMetricAlertSingleResourceMultipleMetricCriteria() } - criteria, err := expandMonitorMetricAlertCriteria(d) + criteria, err := expandMonitorMetricAlertCriteria(d, isLegacy) if err != nil { return fmt.Errorf(`Expanding criteria: %+v`, err) } @@ -540,12 +546,15 @@ func resourceArmMonitorMetricAlertDelete(d *schema.ResourceData, meta interface{ return nil } -func expandMonitorMetricAlertCriteria(d *schema.ResourceData) (insights.BasicMetricAlertCriteria, error) { +func expandMonitorMetricAlertCriteria(d *schema.ResourceData, isLegacy bool) (insights.BasicMetricAlertCriteria, error) { switch { case d.Get("criteria").(*schema.Set).Len() != 0: - return expandMonitorMetricAlertMetricCriteria(d.Get("criteria").(*schema.Set).List()), nil + if isLegacy { + return expandMonitorMetricAlertSingleResourceMultiMetricCriteria(d.Get("criteria").(*schema.Set).List()), nil + } + return expandMonitorMetricAlertMultiResourceMultiMetricForStaticMetricCriteria(d.Get("criteria").(*schema.Set).List()), nil case d.Get("dynamic_criteria").(*schema.Set).Len() != 0: - return expandMonitorMetricAlertDynamicMetricCriteria(d.Get("dynamic_criteria").(*schema.Set).List()), nil + return expandMonitorMetricAlertMultiResourceMultiMetricForDynamicMetricCriteria(d.Get("dynamic_criteria").(*schema.Set).List()), nil case len(d.Get("application_insights_web_test_location_availability_criteria").([]interface{})) != 0: return expandMonitorMetricAlertWebtestLocAvailCriteria(d.Get("application_insights_web_test_location_availability_criteria").([]interface{})), nil default: @@ -554,11 +563,32 @@ func expandMonitorMetricAlertCriteria(d *schema.ResourceData) (insights.BasicMet } } -func expandMonitorMetricAlertMetricCriteria(input []interface{}) insights.BasicMetricAlertCriteria { +func expandMonitorMetricAlertSingleResourceMultiMetricCriteria(input []interface{}) insights.BasicMetricAlertCriteria { + criteria := make([]insights.MetricCriteria, 0) + for i, item := range input { + v := item.(map[string]interface{}) + dimensions := expandMonitorMetricDimension(v["dimension"].([]interface{})) + criteria = append(criteria, insights.MetricCriteria{ + Name: utils.String(fmt.Sprintf("Metric%d", i+1)), + MetricNamespace: utils.String(v["metric_namespace"].(string)), + MetricName: utils.String(v["metric_name"].(string)), + TimeAggregation: v["aggregation"].(string), + Dimensions: &dimensions, + Operator: insights.Operator(v["operator"].(string)), + Threshold: utils.Float(v["threshold"].(float64)), + }) + } + return &insights.MetricAlertSingleResourceMultipleMetricCriteria{ + AllOf: &criteria, + OdataType: insights.OdataTypeMicrosoftAzureMonitorSingleResourceMultipleMetricCriteria, + } +} + +func expandMonitorMetricAlertMultiResourceMultiMetricForStaticMetricCriteria(input []interface{}) insights.BasicMetricAlertCriteria { criteria := make([]insights.BasicMultiMetricCriteria, 0) for i, item := range input { v := item.(map[string]interface{}) - dimensions := expandMonitorMetricAlertMultiMetricCriteriaDimension(v["dimension"].([]interface{})) + dimensions := expandMonitorMetricDimension(v["dimension"].([]interface{})) criteria = append(criteria, insights.MetricCriteria{ Name: utils.String(fmt.Sprintf("Metric%d", i+1)), MetricNamespace: utils.String(v["metric_namespace"].(string)), @@ -574,11 +604,12 @@ func expandMonitorMetricAlertMetricCriteria(input []interface{}) insights.BasicM OdataType: insights.OdataTypeMicrosoftAzureMonitorMultipleResourceMultipleMetricCriteria, } } -func expandMonitorMetricAlertDynamicMetricCriteria(input []interface{}) insights.BasicMetricAlertCriteria { + +func expandMonitorMetricAlertMultiResourceMultiMetricForDynamicMetricCriteria(input []interface{}) insights.BasicMetricAlertCriteria { criteria := make([]insights.BasicMultiMetricCriteria, 0) for i, item := range input { v := item.(map[string]interface{}) - dimensions := expandMonitorMetricAlertMultiMetricCriteriaDimension(v["dimension"].([]interface{})) + dimensions := expandMonitorMetricDimension(v["dimension"].([]interface{})) var ignoreDataBefore *date.Time if v := v["ignore_data_before"].(string); v != "" { // Guaranteed in schema validation func. @@ -619,7 +650,7 @@ func expandMonitorMetricAlertWebtestLocAvailCriteria(input []interface{}) insigh } } -func expandMonitorMetricAlertMultiMetricCriteriaDimension(input []interface{}) []insights.MetricDimension { +func expandMonitorMetricDimension(input []interface{}) []insights.MetricDimension { result := make([]insights.MetricDimension, 0) for _, dimension := range input { dVal := dimension.(map[string]interface{})