alibabacloudstack/resource_apsarastack_cloudmonitorservice_metricalarmrule.go (566 lines of code) (raw):

package alibabacloudstack import ( "encoding/json" "fmt" "strings" "time" "strconv" "github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests" "github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses" "github.com/aliyun/alibaba-cloud-sdk-go/services/cms" "github.com/aliyun/terraform-provider-alibabacloudstack/alibabacloudstack/connectivity" "github.com/aliyun/terraform-provider-alibabacloudstack/alibabacloudstack/errmsgs" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" ) func resourceAlibabacloudStackCmsAlarm() *schema.Resource { resource := &schema.Resource{ Schema: map[string]*schema.Schema{ "rule_name": { Type: schema.TypeString, Optional: true, Computed: true, ConflictsWith: []string{"name"}, }, "rule_id": { Type: schema.TypeString, Computed: true, }, "name": { Type: schema.TypeString, Optional: true, Computed: true, Deprecated: "Field 'name' is deprecated and will be removed in a future release. Please use new field 'rule_name' instead.", ConflictsWith: []string{"rule_name"}, }, "namespace": { Type: schema.TypeString, Optional: true, Computed: true, ForceNew: true, ConflictsWith: []string{"project"}, }, "project": { Type: schema.TypeString, Optional: true, Computed: true, ForceNew: true, Deprecated: "Field 'project' is deprecated and will be removed in a future release. Please use new field 'namespace' instead.", ConflictsWith: []string{"namespace"}, }, "metric_name": { Type: schema.TypeString, Optional: true, Computed: true, ForceNew: true, ConflictsWith: []string{"metric"}, }, "metric": { Type: schema.TypeString, Optional: true, Computed: true, ForceNew: true, Deprecated: "Field 'metric' is deprecated and will be removed in a future release. Please use new field 'metric_name' instead.", ConflictsWith: []string{"metric_name"}, }, "dimensions": { Type: schema.TypeMap, Optional: true, ForceNew: true, Elem: schema.TypeString, Deprecated: "Field 'dimensions' is deprecated and will be removed in a future release. Please use new field 'resources' instead.", ConflictsWith: []string{"resources"}, }, "resources": { Type: schema.TypeMap, Optional: true, ForceNew: true, Elem: &schema.Schema{ Type: schema.TypeString, Elem: &schema.Schema{ Type: schema.TypeString, }, ValidateFunc: func(i interface{}, k string) ([]string, []error) { m := i.(map[string]interface{}) if len(m) > 1 { return nil, []error{fmt.Errorf("too large map")} } return nil, nil }, }, }, "period": { Type: schema.TypeInt, Optional: true, }, "escalations_critical": { Type: schema.TypeList, Optional: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "statistics": { Type: schema.TypeString, Optional: true, Default: Average, ValidateFunc: validation.StringInSlice([]string{Average, Minimum, Maximum, ErrorCodeMaximum, Value}, false), }, "comparison_operator": { Type: schema.TypeString, Optional: true, Default: Equal, ValidateFunc: validation.StringInSlice([]string{ MoreThan, MoreThanOrEqual, LessThan, LessThanOrEqual, NotEqual, }, false), }, "threshold": { Type: schema.TypeString, Optional: true, }, "times": { Type: schema.TypeInt, Optional: true, Default: 3, }, }, }, DiffSuppressFunc: cmsClientCriticalSuppressFunc, MaxItems: 1, }, "escalations_warn": { Type: schema.TypeList, Optional: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "statistics": { Type: schema.TypeString, Optional: true, Default: Average, ValidateFunc: validation.StringInSlice([]string{Average, Minimum, Maximum, ErrorCodeMaximum, Value}, false), }, "comparison_operator": { Type: schema.TypeString, Optional: true, Default: Equal, ValidateFunc: validation.StringInSlice([]string{ MoreThan, MoreThanOrEqual, LessThan, LessThanOrEqual, NotEqual, }, false), }, "threshold": { Type: schema.TypeString, Optional: true, }, "times": { Type: schema.TypeInt, Optional: true, Default: 3, }, }, }, DiffSuppressFunc: cmsClientWarnSuppressFunc, MaxItems: 1, }, "escalations_info": { Type: schema.TypeList, Optional: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "statistics": { Type: schema.TypeString, Optional: true, Default: Average, ValidateFunc: validation.StringInSlice([]string{Average, Minimum, Maximum, ErrorCodeMaximum, Value}, false), }, "comparison_operator": { Type: schema.TypeString, Optional: true, Default: Equal, ValidateFunc: validation.StringInSlice([]string{ MoreThan, MoreThanOrEqual, LessThan, LessThanOrEqual, NotEqual, }, false), }, "threshold": { Type: schema.TypeString, Optional: true, }, "times": { Type: schema.TypeInt, Optional: true, Default: 3, }, }, }, DiffSuppressFunc: cmsClientInfoSuppressFunc, MaxItems: 1, }, "contact_groups": { Type: schema.TypeList, Required: true, Elem: &schema.Schema{Type: schema.TypeString}, }, "effective_interval": { Type: schema.TypeString, Optional: true, Default: "00:00-23:59", }, "silence_time": { Type: schema.TypeInt, Optional: true, Default: 86400, ValidateFunc: validation.IntBetween(300, 86400), }, "enabled": { Type: schema.TypeBool, Optional: true, Default: true, }, "status": { Type: schema.TypeString, Computed: true, }, "webhook": { Type: schema.TypeString, Optional: true, }, }, } setResourceFunc(resource, resourceAlibabacloudStackCmsAlarmCreate, resourceAlibabacloudStackCmsAlarmRead, resourceAlibabacloudStackCmsAlarmUpdate, resourceAlibabacloudStackCmsAlarmDelete) return resource } func resourceAlibabacloudStackCmsAlarmCreate(d *schema.ResourceData, meta interface{}) error { client := meta.(*connectivity.AlibabacloudStackClient) cmsService := CmsService{client} d.Partial(true) request := cms.CreatePutResourceMetricRuleRequest() client.InitRpcRequest(*request.RpcRequest) d.SetId(resource.UniqueId() + ":" + request.RuleName) request.RuleName = connectivity.GetResourceData(d, "rule_name", "name").(string) if err := errmsgs.CheckEmpty(request.RuleName, schema.TypeString, "rule_name", "name"); err != nil { return errmsgs.WrapError(err) } parts, err := ParseResourceId(d.Id(), 2) request.RuleId = parts[0] request.Namespace = connectivity.GetResourceData(d, "namespace", "project").(string) if err := errmsgs.CheckEmpty(request.Namespace, schema.TypeString, "namespace", "project"); err != nil { return errmsgs.WrapError(err) } request.MetricName = connectivity.GetResourceData(d, "metric_name", "metric").(string) if err := errmsgs.CheckEmpty(request.MetricName, schema.TypeString, "metric_name", "metric"); err != nil { return errmsgs.WrapError(err) } request.Period = strconv.Itoa(d.Get("period").(int)) request.ContactGroups = strings.Join(expandStringList(d.Get("contact_groups").([]interface{})), ",") if v, ok := d.GetOk("escalations_critical"); ok && len(v.([]interface{})) != 0 { for _, val := range v.([]interface{}) { val := val.(map[string]interface{}) request.EscalationsCriticalStatistics = val["statistics"].(string) request.EscalationsCriticalComparisonOperator = convertOperator(val["comparison_operator"].(string)) request.EscalationsCriticalThreshold = val["threshold"].(string) request.EscalationsCriticalTimes = requests.NewInteger(val["times"].(int)) } } // Warn if v, ok := d.GetOk("escalations_warn"); ok && len(v.([]interface{})) != 0 { for _, val := range v.([]interface{}) { val := val.(map[string]interface{}) request.EscalationsWarnStatistics = val["statistics"].(string) request.EscalationsWarnComparisonOperator = convertOperator(val["comparison_operator"].(string)) request.EscalationsWarnThreshold = val["threshold"].(string) request.EscalationsWarnTimes = requests.NewInteger(val["times"].(int)) } } // Info if v, ok := d.GetOk("escalations_info"); ok && len(v.([]interface{})) != 0 { for _, val := range v.([]interface{}) { val := val.(map[string]interface{}) request.EscalationsInfoStatistics = val["statistics"].(string) request.EscalationsInfoComparisonOperator = convertOperator(val["comparison_operator"].(string)) request.EscalationsInfoThreshold = val["threshold"].(string) request.EscalationsInfoTimes = requests.NewInteger(val["times"].(int)) } } if v, ok := d.GetOk("effective_interval"); ok && v.(string) != "" { request.EffectiveInterval = v.(string) } else { start, startOk := d.GetOk("start_time") end, endOk := d.GetOk("end_time") if startOk && endOk && end.(int) > 0 { // The EffectiveInterval valid value between 00:00 and 23:59 request.EffectiveInterval = fmt.Sprintf("%d:00-%d:59", start.(int), end.(int)-1) } } request.SilenceTime = requests.NewInteger(d.Get("silence_time").(int)) var instanceId string var dimList []map[string]string if dimensions, ok := connectivity.GetResourceDataOk(d, "dimensions", "resource"); ok { for k, v := range dimensions.(map[string]interface{}) { values := strings.Split(v.(string), COMMA_SEPARATED) if len(values) > 0 { instanceId = values[0] for _, vv := range values { dimList = append(dimList, map[string]string{k: Trim(vv)}) } } else { dimList = append(dimList, map[string]string{k: Trim(v.(string))}) } } } else if resources, ok := d.GetOk("resources"); ok { for _, item := range resources.([]interface{}) { for k, v := range item.(map[string]interface{}) { dimList = append(dimList, map[string]string{k: Trim(v.(string))}) } } } else { return fmt.Errorf("dimensions and resources can not be empty at the same time") } if len(dimList) > 0 { if bytes, err := json.Marshal(dimList); err != nil { return fmt.Errorf("marshaling dimensions to json string got an error: %#v", err) } else { request.Resources = string(bytes[:]) } } nrequest := client.NewCommonRequest("POST", "Cms", "2019-01-01", "PutResourceMetricRule", "") mergeMaps(nrequest.QueryParams, map[string]string{ "RuleName": request.RuleName, "RuleId": request.RuleId, "Namespace": request.Namespace, "MetricName": request.MetricName, "Period": request.Period, "EffectiveInterval": request.EffectiveInterval, "ContactGroups": request.ContactGroups, "InstanceID": instanceId, "Resources": request.Resources, "Escalations.Critical.Threshold": request.EscalationsCriticalThreshold, "Escalations.Critical.ComparisonOperator": request.EscalationsCriticalComparisonOperator, "Escalations.Critical.Statistics": request.EscalationsCriticalStatistics, "Escalations.Critical.Times": fmt.Sprint(request.EscalationsCriticalTimes), "Escalations.Warn.Threshold": request.EscalationsWarnThreshold, "Escalations.Warn.ComparisonOperator": request.EscalationsWarnComparisonOperator, "Escalations.Warn.Statistics": request.EscalationsWarnStatistics, "Escalations.Warn.Times": fmt.Sprint(request.EscalationsWarnTimes), "Escalations.Info.Threshold": request.EscalationsInfoThreshold, "Escalations.Info.ComparisonOperator": request.EscalationsCriticalComparisonOperator, "Escalations.Info.Statistics": request.EscalationsInfoStatistics, "Escalations.Info.Times": fmt.Sprint(request.EscalationsInfoTimes), "SilenceTime": fmt.Sprint(request.SilenceTime), "Format": "JSON", "SignatureVersion": "1.0", }) response, err := client.ProcessCommonRequest(nrequest) if err != nil { if response == nil { return errmsgs.WrapErrorf(err, "Process Common Request Failed") } errmsg := errmsgs.GetBaseResponseErrorMessage(response.BaseResponse) return errmsgs.WrapErrorf(err, errmsgs.RequestV1ErrorMsg, "alibabacloudstack_cms", request.GetActionName(), errmsgs.AlibabacloudStackSdkGoERROR, errmsg) } if d.Get("enabled").(bool) { request := cms.CreateEnableMetricRulesRequest() client.InitRpcRequest(*request.RpcRequest) request.RuleId = &[]string{d.Id()} wait := incrementalWait(1*time.Second, 2*time.Second) err = resource.Retry(5*time.Minute, func() *resource.RetryError { raw, err := client.WithCmsClient(func(cmsClient *cms.Client) (interface{}, error) { return cmsClient.EnableMetricRules(request) }) response, ok := raw.(*responses.CommonResponse) if err != nil { errmsg := "" if ok { errmsg = errmsgs.GetBaseResponseErrorMessage(response.BaseResponse) } if errmsgs.IsExpectedErrors(err, []string{errmsgs.ThrottlingUser}) { wait() return resource.RetryableError(err) } return resource.NonRetryableError(errmsgs.WrapErrorf(err, errmsgs.RequestV1ErrorMsg, "alibabacloudstack_cms", request.GetActionName(), errmsgs.AlibabacloudStackSdkGoERROR, errmsg)) } return nil }) if err != nil { return fmt.Errorf("Enabling alarm got an error: %#v", err) } } else if err != nil { return err } else { request := cms.CreateDisableMetricRulesRequest() client.InitRpcRequest(*request.RpcRequest) request.RuleId = &[]string{d.Id()} wait := incrementalWait(1*time.Second, 2*time.Second) err = resource.Retry(5*time.Minute, func() *resource.RetryError { raw, err := client.WithCmsClient(func(cmsClient *cms.Client) (interface{}, error) { return cmsClient.DisableMetricRules(request) }) response, ok := raw.(*responses.CommonResponse) if err != nil { errmsg := "" if ok { errmsg = errmsgs.GetBaseResponseErrorMessage(response.BaseResponse) } if errmsgs.IsExpectedErrors(err, []string{errmsgs.ThrottlingUser}) { wait() return resource.RetryableError(err) } return resource.NonRetryableError(errmsgs.WrapErrorf(err, errmsgs.RequestV1ErrorMsg, "alibabacloudstack_cms", request.GetActionName(), errmsgs.AlibabacloudStackSdkGoERROR, errmsg)) } return nil }) if err != nil { return fmt.Errorf("Disabling alarm got an error: %#v", err) } } if err := cmsService.WaitForCmsAlarm(d.Id(), d.Get("enabled").(bool), 102); err != nil { return err } d.Partial(false) return nil } func resourceAlibabacloudStackCmsAlarmRead(d *schema.ResourceData, meta interface{}) error { client := meta.(*connectivity.AlibabacloudStackClient) cmsService := CmsService{client} alarm, err := cmsService.DescribeCmsAlarm(d.Id()) if err != nil { if errmsgs.NotFoundError(err) { d.SetId("") return nil } return err } connectivity.SetResourceData(d, alarm.RuleName, "rule_name", "name") connectivity.SetResourceData(d, alarm.Namespace, "namespace", "project") connectivity.SetResourceData(d, alarm.MetricName, "metric_name", "metric") if period, err := strconv.Atoi(alarm.Period); err != nil { return errmsgs.WrapError(err) } else { d.Set("period", period) } escalationsCritical := make([]map[string]interface{}, 1) if alarm.Escalations.Critical.Times != 0 { mapping := map[string]interface{}{ "statistics": alarm.Escalations.Critical.Statistics, "comparison_operator": convertOperator(alarm.Escalations.Critical.ComparisonOperator), "threshold": alarm.Escalations.Critical.Threshold, "times": alarm.Escalations.Critical.Times, } escalationsCritical[0] = mapping d.Set("escalations_critical", escalationsCritical) } escalationsWarn := make([]map[string]interface{}, 1) if alarm.Escalations.Warn.Times != "" { if count, err := strconv.Atoi(alarm.Escalations.Warn.Times); err != nil { return errmsgs.WrapError(err) } else { mappingWarn := map[string]interface{}{ "statistics": alarm.Escalations.Warn.Statistics, "comparison_operator": convertOperator(alarm.Escalations.Warn.ComparisonOperator), "threshold": alarm.Escalations.Warn.Threshold, "times": count, } escalationsWarn[0] = mappingWarn d.Set("escalations_warn", escalationsWarn) } } escalationsInfo := make([]map[string]interface{}, 1) if alarm.Escalations.Info.Times != 0 { mappingInfo := map[string]interface{}{ "statistics": alarm.Escalations.Info.Statistics, "comparison_operator": convertOperator(alarm.Escalations.Info.ComparisonOperator), "threshold": alarm.Escalations.Info.Threshold, "times": alarm.Escalations.Info.Times, } escalationsInfo[0] = mappingInfo d.Set("escalations_info", escalationsInfo) } d.Set("rule_id", alarm.RuleId) d.Set("effective_interval", alarm.EffectiveInterval) d.Set("silence_time", alarm.SilenceTime) d.Set("status", alarm.AlertState) d.Set("enabled", alarm.EnableState) d.Set("contact_groups", strings.Split(alarm.ContactGroups, ",")) if alarm.Resources != "" { var res []interface{} resources := make(map[string]string) if err := json.Unmarshal([]byte(alarm.Resources), &res); err != nil { return fmt.Errorf("Unmarshaling Resources got an error: %#v.", err) } for _, resource := range res { for k, v := range resource.(map[string]interface{}) { if vv, ok := resources[k]; ok { resources[k] = vv + "," + v.(string) } else { resources[k] = v.(string) } } } connectivity.SetResourceData(d, resources, "dimensions", "resources") } return nil } func resourceAlibabacloudStackCmsAlarmUpdate(d *schema.ResourceData, meta interface{}) error { noUpdateAllowedFields := []string{"period", "effective_interval", "enabled", "escalations_warn", "contact_groups", "escalations_info", "silence_time", "webhook", "escalations_critical"} return noUpdatesAllowedCheck(d, noUpdateAllowedFields) } func resourceAlibabacloudStackCmsAlarmDelete(d *schema.ResourceData, meta interface{}) error { client := meta.(*connectivity.AlibabacloudStackClient) cmsService := CmsService{client} parts, err := ParseResourceId(d.Id(), 2) if err != nil { return errmsgs.WrapError(err) } request := cms.CreateDeleteMetricRulesRequest() client.InitRpcRequest(*request.RpcRequest) request.Id = &[]string{parts[0]} wait := incrementalWait(1*time.Second, 2*time.Second) return resource.Retry(10*time.Minute, func() *resource.RetryError { raw, err := client.WithCmsClient(func(cmsClient *cms.Client) (interface{}, error) { return cmsClient.DeleteMetricRules(request) }) response, ok := raw.(*responses.CommonResponse) if err != nil { errmsg := "" if ok { errmsg = errmsgs.GetBaseResponseErrorMessage(response.BaseResponse) } if errmsgs.IsExpectedErrors(err, []string{errmsgs.ThrottlingUser}) { wait() return resource.RetryableError(err) } return resource.NonRetryableError(errmsgs.WrapErrorf(err, errmsgs.RequestV1ErrorMsg, "alibabacloudstack_cms", request.GetActionName(), errmsgs.AlibabacloudStackSdkGoERROR, errmsg)) } _, err = cmsService.DescribeCmsAlarm(d.Id()) if err != nil { if errmsgs.NotFoundError(err) { return nil } return resource.NonRetryableError(errmsgs.WrapErrorf(err, errmsgs.RequestV1ErrorMsg, "alibabacloudstack_cms", request.GetActionName(), errmsgs.AlibabacloudStackSdkGoERROR, "")) } return resource.RetryableError(fmt.Errorf("Deleting alarm rule got an error: %#v", err)) }) } func convertOperator(operator string) string { switch operator { case MoreThan: return "GreaterThanThreshold" case MoreThanOrEqual: return "GreaterThanOrEqualToThreshold" case LessThan: return "LessThanThreshold" case LessThanOrEqual: return "LessThanOrEqualToThreshold" case NotEqual: return "NotEqualToThreshold" case Equal: return "GreaterThanThreshold" case "GreaterThanThreshold": return MoreThan case "GreaterThanOrEqualToThreshold": return MoreThanOrEqual case "LessThanThreshold": return LessThan case "LessThanOrEqualToThreshold": return LessThanOrEqual case "NotEqualToThreshold": return NotEqual default: return "" } }