From 478c16a76d864690fbc82a6d0748ca1b46d771ad Mon Sep 17 00:00:00 2001 From: changjun Date: Fri, 22 Nov 2024 16:29:23 +0800 Subject: [PATCH] New Resource: alicloud_arms_alert_robot, New Data Source: alicloud_arms_alert_robots --- .../data_source_alicloud_arms_alert_robots.go | 201 ++++++++ ..._source_alicloud_arms_alert_robots_test.go | 106 ++++ alicloud/provider.go | 2 + .../resource_alicloud_arms_alert_robot.go | 204 ++++++++ ...resource_alicloud_arms_alert_robot_test.go | 473 ++++++++++++++++++ alicloud/service_alicloud_arms.go | 45 ++ .../docs/d/arms_alert_robots.html.markdown | 58 +++ website/docs/r/arms_alert_robot.html.markdown | 76 +++ 8 files changed, 1165 insertions(+) create mode 100644 alicloud/data_source_alicloud_arms_alert_robots.go create mode 100644 alicloud/data_source_alicloud_arms_alert_robots_test.go create mode 100644 alicloud/resource_alicloud_arms_alert_robot.go create mode 100644 alicloud/resource_alicloud_arms_alert_robot_test.go create mode 100644 website/docs/d/arms_alert_robots.html.markdown create mode 100644 website/docs/r/arms_alert_robot.html.markdown diff --git a/alicloud/data_source_alicloud_arms_alert_robots.go b/alicloud/data_source_alicloud_arms_alert_robots.go new file mode 100644 index 000000000000..8e312de672c8 --- /dev/null +++ b/alicloud/data_source_alicloud_arms_alert_robots.go @@ -0,0 +1,201 @@ +package alicloud + +import ( + "fmt" + "regexp" + "time" + + "github.com/PaesslerAG/jsonpath" + util "github.com/alibabacloud-go/tea-utils/service" + "github.com/aliyun/terraform-provider-alicloud/alicloud/connectivity" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" +) + +func dataSourceAlicloudArmsAlertRobots() *schema.Resource { + return &schema.Resource{ + Read: dataSourceAlicloudArmsAlertRobotsRead, + Schema: map[string]*schema.Schema{ + "ids": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Computed: true, + }, + "name_regex": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.ValidateRegexp, + ForceNew: true, + }, + "names": { + Type: schema.TypeList, + Elem: &schema.Schema{Type: schema.TypeString}, + Computed: true, + }, + "alert_robot_name": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "robot_type": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "output_file": { + Type: schema.TypeString, + Optional: true, + }, + "robots": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + "robot_id": { + Type: schema.TypeString, + Computed: true, + }, + "robot_name": { + Type: schema.TypeString, + Computed: true, + }, + "robot_type": { + Type: schema.TypeString, + Computed: true, + }, + "robot_addr": { + Type: schema.TypeString, + Computed: true, + }, + "daily_noc": { + Type: schema.TypeString, + Computed: true, + }, + "daily_noc_time": { + Type: schema.TypeString, + Computed: true, + }, + "create_time": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + } +} + +func dataSourceAlicloudArmsAlertRobotsRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*connectivity.AliyunClient) + + action := "DescribeIMRobots" + request := make(map[string]interface{}) + if v, ok := d.GetOk("alert_robot_name"); ok { + request["RobotName"] = v + } + request["Page"] = 1 + request["Size"] = PageSizeXLarge + var objects []map[string]interface{} + var alertContactRobotNameRegex *regexp.Regexp + if v, ok := d.GetOk("name_regex"); ok { + r, err := regexp.Compile(v.(string)) + if err != nil { + return WrapError(err) + } + alertContactRobotNameRegex = r + } + + idsMap := make(map[string]string) + if v, ok := d.GetOk("ids"); ok { + for _, vv := range v.([]interface{}) { + if vv == nil { + continue + } + idsMap[vv.(string)] = vv.(string) + } + } + var response map[string]interface{} + conn, err := client.NewArmsClient() + if err != nil { + return WrapError(err) + } + runtime := util.RuntimeOptions{} + runtime.SetAutoretry(true) + wait := incrementalWait(3*time.Second, 3*time.Second) + err = resource.Retry(5*time.Minute, func() *resource.RetryError { + response, err = conn.DoRequest(StringPointer(action), nil, StringPointer("POST"), StringPointer("2019-08-08"), StringPointer("AK"), nil, request, &runtime) + if err != nil { + if NeedRetry(err) { + wait() + return resource.RetryableError(err) + } + return resource.NonRetryableError(err) + } + return nil + }) + addDebug(action, response, request) + if err != nil { + return WrapErrorf(err, DataDefaultErrorMsg, "alicloud_arms_alert_robots", action, AlibabaCloudSdkGoERROR) + } + resp, err := jsonpath.Get("$.PageBean.AlertIMRobots", response) + if err != nil { + return WrapErrorf(err, FailedGetAttributeMsg, action, "$.PageBean.AlertIMRobots", response) + } + result, _ := resp.([]interface{}) + for _, v := range result { + item := v.(map[string]interface{}) + if alertContactRobotNameRegex != nil && !alertContactRobotNameRegex.MatchString(fmt.Sprint(item["RobotName"])) { + continue + } + if len(idsMap) > 0 { + if _, ok := idsMap[fmt.Sprint(item["RobotId"])]; !ok { + continue + } + } + objects = append(objects, item) + } + ids := make([]string, 0) + names := make([]interface{}, 0) + s := make([]map[string]interface{}, 0) + for _, object := range objects { + mapping := map[string]interface{}{ + "id": fmt.Sprint(object["RobotId"]), + "robot_type": object["Type"], + "robot_id": fmt.Sprint(object["RobotId"]), + "robot_name": object["RobotName"], + "robot_addr": object["RobotAddr"], + "daily_noc": fmt.Sprint(object["DailyNoc"]), + "daily_noc_time": object["DailyNocTime"], + "create_time": fmt.Sprint(object["CreateTime"]), + } + ids = append(ids, fmt.Sprint(mapping["id"])) + names = append(names, object["RobotName"]) + s = append(s, mapping) + } + + d.SetId(dataResourceIdHash(ids)) + if err := d.Set("ids", ids); err != nil { + return WrapError(err) + } + + if err := d.Set("names", names); err != nil { + return WrapError(err) + } + + if err := d.Set("robots", s); err != nil { + return WrapError(err) + } + if output, ok := d.GetOk("output_file"); ok && output.(string) != "" { + writeToFile(output.(string), s) + } + + return nil +} diff --git a/alicloud/data_source_alicloud_arms_alert_robots_test.go b/alicloud/data_source_alicloud_arms_alert_robots_test.go new file mode 100644 index 000000000000..e3e8b31b6d28 --- /dev/null +++ b/alicloud/data_source_alicloud_arms_alert_robots_test.go @@ -0,0 +1,106 @@ +package alicloud + +import ( + "fmt" + "testing" + + "github.com/aliyun/terraform-provider-alicloud/alicloud/connectivity" + + "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" +) + +func TestAccAlicloudARMSAlertRobotsDataSource(t *testing.T) { + rand := acctest.RandInt() + resourceId := "data.alicloud_arms_alert_robots.default" + name := fmt.Sprintf("tf-testacc-ArmsAlertRobots%v", rand) + + testAccConfig := dataSourceTestAccConfigFunc(resourceId, name, dataSourceArmsAlertRobotsConfigDependence) + + nameRegexConf := dataSourceTestAccConfig{ + existConfig: testAccConfig(map[string]interface{}{ + "name_regex": "${alicloud_arms_alert_robot.default.alert_robot_name}", + }), + fakeConfig: testAccConfig(map[string]interface{}{ + "name_regex": "fake_tf-testacc*", + }), + } + idsConf := dataSourceTestAccConfig{ + existConfig: testAccConfig(map[string]interface{}{ + "ids": []string{"${alicloud_arms_alert_robot.default.id}"}, + }), + fakeConfig: testAccConfig(map[string]interface{}{ + "ids": []string{"${alicloud_arms_alert_robot.default.id}_fake"}, + }), + } + robotNameConf := dataSourceTestAccConfig{ + existConfig: testAccConfig(map[string]interface{}{ + "alert_robot_name": "${alicloud_arms_alert_robot.default.alert_robot_name}", + }), + fakeConfig: testAccConfig(map[string]interface{}{ + "alert_robot_name": "${alicloud_arms_alert_robot.default.alert_robot_name}-fake", + }), + } + allConf := dataSourceTestAccConfig{ + existConfig: testAccConfig(map[string]interface{}{ + "robot_type": "${alicloud_arms_alert_robot.default.robot_type}", + "name_regex": "${alicloud_arms_alert_robot.default.alert_robot_name}", + "ids": []string{"${alicloud_arms_alert_robot.default.id}"}, + "alert_robot_name": "${alicloud_arms_alert_robot.default.alert_robot_name}", + }), + fakeConfig: testAccConfig(map[string]interface{}{ + "robot_type": "${alicloud_arms_alert_robot.default.robot_type}", + "name_regex": "${alicloud_arms_alert_robot.default.alert_robot_name}", + "ids": []string{"${alicloud_arms_alert_robot.default.id}"}, + "alert_robot_name": "${alicloud_arms_alert_robot.default.alert_robot_name}-fake", + }), + } + existArmsAlertRobotsMapFunc := func(rand int) map[string]string { + return map[string]string{ + "ids.#": "1", + "names.#": "1", + "robots.#": "1", + "robots.0.id": CHECKSET, + "robots.0.robot_name": name, + "robots.0.robot_type": "wechat", + "robots.0.robot_id": CHECKSET, + "robots.0.robot_addr": "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=1c704e23", + "robots.0.daily_noc": "true", + "robots.0.daily_noc_time": "09:30,17:00", + "robots.0.create_time": CHECKSET, + } + } + + fakeArmsAlertRobotsMapFunc := func(rand int) map[string]string { + return map[string]string{ + "robots.#": "0", + "names.#": "0", + "ids.#": "0", + } + } + + ArmsAlertRobotsCheckInfo := dataSourceAttr{ + resourceId: resourceId, + existMapFunc: existArmsAlertRobotsMapFunc, + fakeMapFunc: fakeArmsAlertRobotsMapFunc, + } + preCheck := func() { + testAccPreCheck(t) + testAccPreCheckWithRegions(t, true, connectivity.ARMSSupportRegions) + } + ArmsAlertRobotsCheckInfo.dataSourceTestCheckWithPreCheck(t, rand, preCheck, nameRegexConf, idsConf, robotNameConf, allConf) +} + +func dataSourceArmsAlertRobotsConfigDependence(name string) string { + return fmt.Sprintf(` + variable "name" { + default = "%v" + } + resource "alicloud_arms_alert_robot" "default" { + alert_robot_name = var.name + robot_type = "wechat" + robot_addr = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=1c704e23" + daily_noc = "true" + daily_noc_time = "09:30,17:00" + } + `, name) +} diff --git a/alicloud/provider.go b/alicloud/provider.go index 3a0c1ee2cb9e..81e91799162a 100644 --- a/alicloud/provider.go +++ b/alicloud/provider.go @@ -505,6 +505,7 @@ func Provider() terraform.ResourceProvider { "alicloud_hbr_vaults": dataSourceAlicloudHbrVaults(), "alicloud_ssl_certificates_service_certificates": dataSourceAliCloudSslCertificatesServiceCertificates(), "alicloud_arms_alert_contacts": dataSourceAlicloudArmsAlertContacts(), + "alicloud_arms_alert_robots": dataSourceAlicloudArmsAlertRobots(), "alicloud_event_bridge_rules": dataSourceAlicloudEventBridgeRules(), "alicloud_cloud_firewall_control_policies": dataSourceAliCloudCloudFirewallControlPolicies(), "alicloud_sae_namespaces": dataSourceAlicloudSaeNamespaces(), @@ -1418,6 +1419,7 @@ func Provider() terraform.ResourceProvider { "alicloud_hbr_vault": resourceAliCloudHbrVault(), "alicloud_ssl_certificates_service_certificate": resourceAliCloudSslCertificatesServiceCertificate(), "alicloud_arms_alert_contact": resourceAlicloudArmsAlertContact(), + "alicloud_arms_alert_robot": resourceAlicloudArmsAlertRobot(), "alicloud_event_bridge_slr": resourceAlicloudEventBridgeServiceLinkedRole(), "alicloud_event_bridge_rule": resourceAliCloudEventBridgeRule(), "alicloud_cloud_firewall_control_policy": resourceAliCloudCloudFirewallControlPolicy(), diff --git a/alicloud/resource_alicloud_arms_alert_robot.go b/alicloud/resource_alicloud_arms_alert_robot.go new file mode 100644 index 000000000000..cb3053e52b7d --- /dev/null +++ b/alicloud/resource_alicloud_arms_alert_robot.go @@ -0,0 +1,204 @@ +package alicloud + +import ( + "fmt" + "log" + "time" + + util "github.com/alibabacloud-go/tea-utils/service" + "github.com/aliyun/terraform-provider-alicloud/alicloud/connectivity" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" +) + +func resourceAlicloudArmsAlertRobot() *schema.Resource { + return &schema.Resource{ + Create: resourceAlicloudArmsAlertRobotCreate, + Read: resourceAlicloudArmsAlertRobotRead, + Update: resourceAlicloudArmsAlertRobotUpdate, + Delete: resourceAlicloudArmsAlertRobotDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + Schema: map[string]*schema.Schema{ + "alert_robot_name": { + Type: schema.TypeString, + Required: true, + }, + "robot_type": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: StringInSlice([]string{"wechat", "dingding", "feishu"}, false), + }, + "robot_addr": { + Type: schema.TypeString, + Required: true, + }, + "daily_noc": { + Type: schema.TypeBool, + Optional: true, + }, + "daily_noc_time": { + Type: schema.TypeString, + Optional: true, + }, + }, + } +} + +func resourceAlicloudArmsAlertRobotCreate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*connectivity.AliyunClient) + var response map[string]interface{} + action := "CreateOrUpdateIMRobot" + request := make(map[string]interface{}) + conn, err := client.NewArmsClient() + if err != nil { + return WrapError(err) + } + request["RobotName"] = d.Get("alert_robot_name") + request["Type"] = d.Get("robot_type") + request["RobotAddress"] = d.Get("robot_addr") + if v, ok := d.GetOk("daily_noc"); ok { + request["DailyNoc"] = v + if v, ok := d.GetOk("daily_noc_time"); ok && v.(string) == "" { + return WrapError(fmt.Errorf("attribute '%s' is required when '%s' is %v", "daily_noc_time", "daily_noc", d.Get("daily_noc"))) + } + } + request["DailyNocTime"] = d.Get("daily_noc_time") + wait := incrementalWait(3*time.Second, 3*time.Second) + err = resource.Retry(d.Timeout(schema.TimeoutCreate), func() *resource.RetryError { + response, err = conn.DoRequest(StringPointer(action), nil, StringPointer("POST"), StringPointer("2019-08-08"), StringPointer("AK"), nil, request, &util.RuntimeOptions{}) + if err != nil { + if NeedRetry(err) { + wait() + return resource.RetryableError(err) + } + return resource.NonRetryableError(err) + } + return nil + }) + addDebug(action, response, request) + if err != nil { + return WrapErrorf(err, DefaultErrorMsg, "alicloud_arms_alert_robot", action, AlibabaCloudSdkGoERROR) + } + + d.SetId(fmt.Sprint(response["AlertRobot"].(map[string]interface{})["RobotId"])) + + return resourceAlicloudArmsAlertRobotRead(d, meta) +} +func resourceAlicloudArmsAlertRobotRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*connectivity.AliyunClient) + armsService := ArmsService{client} + object, err := armsService.DescribeArmsAlertRobot(d.Id()) + if err != nil { + if NotFoundError(err) { + log.Printf("[DEBUG] Resource alicloud_arms_alert_robot armsService.DescribeArmsAlertRobot Failed!!! %s", err) + d.SetId("") + return nil + } + return WrapError(err) + } + d.Set("alert_robot_name", object["RobotName"]) + d.Set("robot_type", object["Type"]) + d.Set("robot_addr", object["RobotAddr"]) + d.Set("daily_noc", object["DailyNoc"]) + d.Set("daily_noc_time", object["DailyNocTime"]) + return nil +} +func resourceAlicloudArmsAlertRobotUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*connectivity.AliyunClient) + conn, err := client.NewArmsClient() + if err != nil { + return WrapError(err) + } + var response map[string]interface{} + update := false + request := map[string]interface{}{ + "RobotId": d.Id(), + } + if d.HasChange("alert_robot_name") { + update = true + } + if v, ok := d.GetOk("alert_robot_name"); ok { + request["RobotName"] = v + } + if d.HasChange("robot_type") { + update = true + } + if v, ok := d.GetOk("robot_type"); ok { + request["Type"] = v + } + if d.HasChange("robot_addr") { + update = true + } + if v, ok := d.GetOk("robot_addr"); ok { + request["RobotAddress"] = v + } + if d.HasChange("daily_noc") { + update = true + } + if v, ok := d.GetOk("daily_noc"); ok { + request["DailyNoc"] = v + } + if d.HasChange("daily_noc_time") { + update = true + } + if v, ok := d.GetOk("daily_noc_time"); ok { + if d.Get("daily_noc").(bool) && v.(string) == "" { + return WrapError(fmt.Errorf("attribute '%s' is required when '%s' is %v", "daily_noc_time", "daily_noc", d.Get("daily_noc"))) + } + request["DailyNocTime"] = v + } + + if update { + action := "CreateOrUpdateIMRobot" + wait := incrementalWait(3*time.Second, 3*time.Second) + err = resource.Retry(d.Timeout(schema.TimeoutUpdate), func() *resource.RetryError { + response, err = conn.DoRequest(StringPointer(action), nil, StringPointer("POST"), StringPointer("2019-08-08"), StringPointer("AK"), nil, request, &util.RuntimeOptions{}) + if err != nil { + if NeedRetry(err) { + wait() + return resource.RetryableError(err) + } + return resource.NonRetryableError(err) + } + return nil + }) + addDebug(action, response, request) + if err != nil { + return WrapErrorf(err, DefaultErrorMsg, d.Id(), action, AlibabaCloudSdkGoERROR) + } + } + return resourceAlicloudArmsAlertRobotRead(d, meta) +} +func resourceAlicloudArmsAlertRobotDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*connectivity.AliyunClient) + action := "DeleteIMRobot" + var response map[string]interface{} + conn, err := client.NewArmsClient() + if err != nil { + return WrapError(err) + } + request := map[string]interface{}{ + "RobotId": d.Id(), + } + + wait := incrementalWait(3*time.Second, 3*time.Second) + err = resource.Retry(d.Timeout(schema.TimeoutDelete), func() *resource.RetryError { + response, err = conn.DoRequest(StringPointer(action), nil, StringPointer("POST"), StringPointer("2019-08-08"), StringPointer("AK"), nil, request, &util.RuntimeOptions{}) + if err != nil { + if NeedRetry(err) { + wait() + return resource.RetryableError(err) + } + return resource.NonRetryableError(err) + } + return nil + }) + addDebug(action, response, request) + if err != nil { + return WrapErrorf(err, DefaultErrorMsg, d.Id(), action, AlibabaCloudSdkGoERROR) + } + return nil +} diff --git a/alicloud/resource_alicloud_arms_alert_robot_test.go b/alicloud/resource_alicloud_arms_alert_robot_test.go new file mode 100644 index 000000000000..94df19babcdd --- /dev/null +++ b/alicloud/resource_alicloud_arms_alert_robot_test.go @@ -0,0 +1,473 @@ +package alicloud + +import ( + "fmt" + "log" + "os" + "reflect" + "strconv" + "strings" + "testing" + + "github.com/agiledragon/gomonkey/v2" + "github.com/alibabacloud-go/tea/tea" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/terraform" + "github.com/stretchr/testify/assert" + + "github.com/PaesslerAG/jsonpath" + util "github.com/alibabacloud-go/tea-utils/service" + + "github.com/alibabacloud-go/tea-rpc/client" + "github.com/aliyun/terraform-provider-alicloud/alicloud/connectivity" + "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" +) + +func init() { + resource.AddTestSweepers("alicloud_arms_alert_robot", &resource.Sweeper{ + Name: "alicloud_arms_alert_robot", + F: testSweepArmsAlertRobot, + }) +} + +func testSweepArmsAlertRobot(region string) error { + rawClient, err := sharedClientForRegion(region) + if err != nil { + return WrapErrorf(err, "error getting Alicloud client.") + } + client := rawClient.(*connectivity.AliyunClient) + + prefixes := []string{ + "tf-testAcc", + "tf_testacc", + } + + action := "DescribeIMRobots" + request := make(map[string]interface{}) + request["Page"] = 1 + request["Size"] = PageSizeXLarge + conn, err := client.NewArmsClient() + if err != nil { + return WrapError(err) + } + runtime := util.RuntimeOptions{} + runtime.SetAutoretry(true) + response, err := conn.DoRequest(StringPointer(action), nil, StringPointer("POST"), StringPointer("2019-08-08"), StringPointer("AK"), nil, request, &runtime) + if err != nil { + log.Printf("[ERROR] %s failed error: %v", action, err) + return nil + } + resp, err := jsonpath.Get("$.PageBean.AlertIMRobots", response) + if err != nil { + log.Printf("[ERROR] %s error: %v", action, err) + return nil + } + result, _ := resp.([]interface{}) + for _, v := range result { + item := v.(map[string]interface{}) + name := fmt.Sprint(item["RobotName"]) + skip := true + for _, prefix := range prefixes { + if strings.HasPrefix(strings.ToLower(name), strings.ToLower(prefix)) { + skip = false + break + } + } + if skip { + log.Printf("[INFO] Skipping arms alert robot: %s ", name) + continue + } + log.Printf("[INFO] delete arms alert robot: %s ", name) + action = "DeleteIMRobot" + request = map[string]interface{}{ + "RobotId": fmt.Sprint(item["RobotId"]), + } + _, err = conn.DoRequest(StringPointer(action), nil, StringPointer("POST"), StringPointer("2019-08-08"), StringPointer("AK"), nil, request, &util.RuntimeOptions{}) + if err != nil { + log.Printf("[ERROR] %s failed error: %v", action, err) + } + } + return nil +} + +func TestAccAliCloudARMSAlertRobot_basic(t *testing.T) { + var v map[string]interface{} + resourceId := "alicloud_arms_alert_robot.default" + ra := resourceAttrInit(resourceId, ArmsAlertRobotMap) + rc := resourceCheckInitWithDescribeMethod(resourceId, &v, func() interface{} { + return &ArmsService{testAccProvider.Meta().(*connectivity.AliyunClient)} + }, "DescribeArmsAlertRobot") + rac := resourceAttrCheckInit(rc, ra) + testAccCheck := rac.resourceAttrMapUpdateSet() + rand := acctest.RandIntRange(1000000, 9999999) + name := fmt.Sprintf("tf-testAccArmsAlertRobot%d", rand) + testAccConfig := resourceTestAccConfigFunc(resourceId, name, ArmsAlertRobotBasicdependence) + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + testAccPreCheckWithRegions(t, true, connectivity.ARMSSupportRegions) + }, + + IDRefreshName: resourceId, + Providers: testAccProviders, + CheckDestroy: rac.checkResourceDestroy(), + Steps: []resource.TestStep{ + { + Config: testAccConfig(map[string]interface{}{ + "alert_robot_name": "${var.name}", + "robot_type": "wechat", + "robot_addr": "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=1c704e23", + "daily_noc": true, + "daily_noc_time": "09:00,17:00", + }), + Check: resource.ComposeTestCheckFunc( + testAccCheck(map[string]string{ + "alert_robot_name": name, + "robot_type": "wechat", + "robot_addr": "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=1c704e23", + "daily_noc": "true", + "daily_noc_time": "09:00,17:00", + }), + ), + }, + { + Config: testAccConfig(map[string]interface{}{ + "alert_robot_name": "${var.name}_update", + "robot_type": "dingding", + "robot_addr": "https://oapi.dingtalk.com/robot/send?access_token=1c704e23", + "daily_noc": false, + "daily_noc_time": "09:30,17:00", + }), + Check: resource.ComposeTestCheckFunc( + testAccCheck(map[string]string{ + "alert_robot_name": name + "_update", + "robot_type": "dingding", + "robot_addr": "https://oapi.dingtalk.com/robot/send?access_token=1c704e23", + "daily_noc": "false", + "daily_noc_time": "09:30,17:00", + }), + ), + }, + { + ResourceName: resourceId, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{}, + }, + }, + }) +} + +var ArmsAlertRobotMap = map[string]string{} + +func ArmsAlertRobotBasicdependence(name string) string { + return fmt.Sprintf(` +variable "name" { + default = "%s" +} +`, name) +} + +func TestUnitAlicloudARMSAlertRobot(t *testing.T) { + p := Provider().(*schema.Provider).ResourcesMap + d, _ := schema.InternalMap(p["alicloud_arms_alert_robot"].Schema).Data(nil, nil) + dCreate, _ := schema.InternalMap(p["alicloud_arms_alert_robot"].Schema).Data(nil, nil) + dCreate.MarkNewResource() + dMock, _ := schema.InternalMap(p["alicloud_arms_alert_robot"].Schema).Data(nil, nil) + dMock.MarkNewResource() + for key, value := range map[string]interface{}{ + "alert_robot_name": "alert_robot_name", + "robot_type": "wechat", + "robot_addr": "robot_addr", + "daily_noc": true, + "daily_noc_time": "09:30,17:00", + } { + err := dCreate.Set(key, value) + assert.Nil(t, err) + err = d.Set(key, value) + assert.Nil(t, err) + } + region := os.Getenv("ALICLOUD_REGION") + rawClient, err := sharedClientForRegion(region) + if err != nil { + t.Skipf("Skipping the test case with err: %s", err) + t.Skipped() + } + rawClient = rawClient.(*connectivity.AliyunClient) + ReadMockResponse := map[string]interface{}{ + "PageBean": map[string]interface{}{ + "AlertIMRobots": []interface{}{ + map[string]interface{}{ + "Type": "wechat", + "RobotId": "MockContactId", + "RobotName": "robot_name", + "RobotAddr": "robot_addr", + "CreateTime": "2024-11-19 10:37:05", + "DailyNoc": true, + "DailyNocTime": "09:30,17:00", + }, + }, + }, + } + + responseMock := map[string]func(errorCode string) (map[string]interface{}, error){ + "RetryError": func(errorCode string) (map[string]interface{}, error) { + return nil, &tea.SDKError{ + Code: String(errorCode), + Data: String(errorCode), + Message: String(errorCode), + StatusCode: tea.Int(400), + } + }, + "NotFoundError": func(errorCode string) (map[string]interface{}, error) { + return nil, GetNotFoundErrorFromString(GetNotFoundMessage("alicloud_arms_alert_robot", "MockContactRobotId")) + }, + "NoRetryError": func(errorCode string) (map[string]interface{}, error) { + return nil, &tea.SDKError{ + Code: String(errorCode), + Data: String(errorCode), + Message: String(errorCode), + StatusCode: tea.Int(400), + } + }, + "CreateNormal": func(errorCode string) (map[string]interface{}, error) { + result := ReadMockResponse + result["RobotId"] = "MockRobotId" + return result, nil + }, + "UpdateNormal": func(errorCode string) (map[string]interface{}, error) { + result := ReadMockResponse + return result, nil + }, + "DeleteNormal": func(errorCode string) (map[string]interface{}, error) { + result := ReadMockResponse + return result, nil + }, + "ReadNormal": func(errorCode string) (map[string]interface{}, error) { + result := ReadMockResponse + return result, nil + }, + } + // Create + t.Run("CreateClientAbnormal", func(t *testing.T) { + patches := gomonkey.ApplyMethod(reflect.TypeOf(&connectivity.AliyunClient{}), "NewArmsClient", func(_ *connectivity.AliyunClient) (*client.Client, error) { + return nil, &tea.SDKError{ + Code: String("loadEndpoint error"), + Data: String("loadEndpoint error"), + Message: String("loadEndpoint error"), + StatusCode: tea.Int(400), + } + }) + err := resourceAlicloudArmsAlertRobotCreate(d, rawClient) + patches.Reset() + assert.NotNil(t, err) + }) + t.Run("CreateAbnormal", func(t *testing.T) { + retryFlag := true + noRetryFlag := true + patches := gomonkey.ApplyMethod(reflect.TypeOf(&client.Client{}), "DoRequest", func(_ *client.Client, _ *string, _ *string, _ *string, _ *string, _ *string, _ map[string]interface{}, _ map[string]interface{}, _ *util.RuntimeOptions) (map[string]interface{}, error) { + if retryFlag { + retryFlag = false + return responseMock["RetryError"]("Throttling") + } else if noRetryFlag { + noRetryFlag = false + return responseMock["NoRetryError"]("NonRetryableError") + } + return responseMock["CreateNormal"]("") + }) + err := resourceAlicloudArmsAlertRobotCreate(d, rawClient) + patches.Reset() + assert.NotNil(t, err) + }) + t.Run("CreateNormal", func(t *testing.T) { + retryFlag := false + noRetryFlag := false + target := reflect.TypeOf(&client.Client{}) + data := func(_ *client.Client, _ *string, _ *string, _ *string, _ *string, _ *string, _ map[string]interface{}, _ map[string]interface{}, _ *util.RuntimeOptions) (map[string]interface{}, error) { + if retryFlag { + retryFlag = false + return responseMock["RetryError"]("Throttling") + } else if noRetryFlag { + noRetryFlag = false + return responseMock["NoRetryError"]("NonRetryableError") + } + return responseMock["CreateNormal"]("") + } + + patches := gomonkey.ApplyMethod(target, "DoRequest", data) + err := resourceAlicloudArmsAlertRobotCreate(dCreate, rawClient) + patches.Reset() + assert.Nil(t, err) + }) + + // Set ID for Update and Delete Method + d.SetId("MockRobotId") + // Update + t.Run("UpdateClientAbnormal", func(t *testing.T) { + patches := gomonkey.ApplyMethod(reflect.TypeOf(&connectivity.AliyunClient{}), "NewArmsClient", func(_ *connectivity.AliyunClient) (*client.Client, error) { + return nil, &tea.SDKError{ + Code: String("loadEndpoint error"), + Data: String("loadEndpoint error"), + Message: String("loadEndpoint error"), + StatusCode: tea.Int(400), + } + }) + + err := resourceAlicloudArmsAlertRobotUpdate(d, rawClient) + patches.Reset() + assert.NotNil(t, err) + }) + + t.Run("UpdateAlertRobotAbnormal", func(t *testing.T) { + diff := terraform.NewInstanceDiff() + for _, key := range []string{"alert_robot_name"} { + switch p["alicloud_arms_alert_robot"].Schema[key].Type { + case schema.TypeString: + diff.SetAttribute(key, &terraform.ResourceAttrDiff{Old: d.Get(key).(string), New: d.Get(key).(string) + "_update"}) + case schema.TypeBool: + diff.SetAttribute(key, &terraform.ResourceAttrDiff{Old: strconv.FormatBool(d.Get(key).(bool)), New: strconv.FormatBool(true)}) + case schema.TypeInt: + diff.SetAttribute(key, &terraform.ResourceAttrDiff{Old: strconv.Itoa(d.Get(key).(int)), New: strconv.Itoa(2)}) + case schema.TypeMap: + diff.SetAttribute("tags.%", &terraform.ResourceAttrDiff{Old: "0", New: "2"}) + diff.SetAttribute("tags.For", &terraform.ResourceAttrDiff{Old: "", New: "Test"}) + diff.SetAttribute("tags.Created", &terraform.ResourceAttrDiff{Old: "", New: "TF"}) + } + } + resourceData1, _ := schema.InternalMap(p["alicloud_arms_alert_robot"].Schema).Data(nil, diff) + resourceData1.SetId(d.Id()) + retryFlag := true + noRetryFlag := true + patches := gomonkey.ApplyMethod(reflect.TypeOf(&client.Client{}), "DoRequest", func(_ *client.Client, _ *string, _ *string, _ *string, _ *string, _ *string, _ map[string]interface{}, _ map[string]interface{}, _ *util.RuntimeOptions) (map[string]interface{}, error) { + if retryFlag { + retryFlag = false + return responseMock["RetryError"]("Throttling") + } else if noRetryFlag { + noRetryFlag = false + return responseMock["NoRetryError"]("NonRetryableError") + } + return responseMock["UpdateNormal"]("") + }) + err := resourceAlicloudArmsAlertRobotUpdate(resourceData1, rawClient) + patches.Reset() + assert.NotNil(t, err) + }) + + t.Run("UpdateAlertRobotNormal", func(t *testing.T) { + diff := terraform.NewInstanceDiff() + for _, key := range []string{"alert_robot_name"} { + switch p["alicloud_arms_alert_robot"].Schema[key].Type { + case schema.TypeString: + diff.SetAttribute(key, &terraform.ResourceAttrDiff{Old: d.Get(key).(string), New: d.Get(key).(string) + "_update"}) + case schema.TypeBool: + diff.SetAttribute(key, &terraform.ResourceAttrDiff{Old: strconv.FormatBool(d.Get(key).(bool)), New: strconv.FormatBool(true)}) + case schema.TypeInt: + diff.SetAttribute(key, &terraform.ResourceAttrDiff{Old: strconv.Itoa(d.Get(key).(int)), New: strconv.Itoa(3)}) + case schema.TypeMap: + diff.SetAttribute("tags.%", &terraform.ResourceAttrDiff{Old: "0", New: "2"}) + diff.SetAttribute("tags.For", &terraform.ResourceAttrDiff{Old: "", New: "Test"}) + diff.SetAttribute("tags.Created", &terraform.ResourceAttrDiff{Old: "", New: "TF"}) + } + } + resourceData1, _ := schema.InternalMap(p["alicloud_arms_alert_robot"].Schema).Data(nil, diff) + resourceData1.SetId(d.Id()) + retryFlag := false + noRetryFlag := false + patches := gomonkey.ApplyMethod(reflect.TypeOf(&client.Client{}), "DoRequest", func(_ *client.Client, _ *string, _ *string, _ *string, _ *string, _ *string, _ map[string]interface{}, _ map[string]interface{}, _ *util.RuntimeOptions) (map[string]interface{}, error) { + if retryFlag { + retryFlag = false + return responseMock["RetryError"]("Throttling") + } else if noRetryFlag { + noRetryFlag = false + return responseMock["NoRetryError"]("NonRetryableError") + } + return responseMock["UpdateNormal"]("") + }) + err := resourceAlicloudArmsAlertRobotUpdate(resourceData1, rawClient) + patches.Reset() + assert.Nil(t, err) + }) + + // Delete + t.Run("DeleteClientAbnormal", func(t *testing.T) { + patches := gomonkey.ApplyMethod(reflect.TypeOf(&connectivity.AliyunClient{}), "NewArmsClient", func(_ *connectivity.AliyunClient) (*client.Client, error) { + return nil, &tea.SDKError{ + Code: String("loadEndpoint error"), + Data: String("loadEndpoint error"), + Message: String("loadEndpoint error"), + StatusCode: tea.Int(400), + } + }) + err := resourceAlicloudArmsAlertRobotDelete(d, rawClient) + patches.Reset() + assert.NotNil(t, err) + }) + t.Run("DeleteMockAbnormal", func(t *testing.T) { + retryFlag := true + noRetryFlag := true + patches := gomonkey.ApplyMethod(reflect.TypeOf(&client.Client{}), "DoRequest", func(_ *client.Client, _ *string, _ *string, _ *string, _ *string, _ *string, _ map[string]interface{}, _ map[string]interface{}, _ *util.RuntimeOptions) (map[string]interface{}, error) { + if retryFlag { + retryFlag = false + return responseMock["RetryError"]("Throttling") + } else if noRetryFlag { + noRetryFlag = false + return responseMock["NoRetryError"]("NonRetryableError") + } + return responseMock["DeleteNormal"]("") + }) + err := resourceAlicloudArmsAlertRobotDelete(d, rawClient) + patches.Reset() + assert.NotNil(t, err) + }) + t.Run("DeleteMockNormal", func(t *testing.T) { + retryFlag := false + noRetryFlag := false + patches := gomonkey.ApplyMethod(reflect.TypeOf(&client.Client{}), "DoRequest", func(_ *client.Client, _ *string, _ *string, _ *string, _ *string, _ *string, _ map[string]interface{}, _ map[string]interface{}, _ *util.RuntimeOptions) (map[string]interface{}, error) { + if retryFlag { + retryFlag = false + return responseMock["RetryError"]("Throttling") + } else if noRetryFlag { + noRetryFlag = false + return responseMock["NoRetryError"]("NonRetryableError") + } + return responseMock["DeleteNormal"]("") + }) + err := resourceAlicloudArmsAlertRobotDelete(d, rawClient) + patches.Reset() + assert.Nil(t, err) + }) + + //Read + t.Run("ReadDescribeArmsAlertRobotNotFound", func(t *testing.T) { + patcheDorequest := gomonkey.ApplyMethod(reflect.TypeOf(&client.Client{}), "DoRequest", func(_ *client.Client, _ *string, _ *string, _ *string, _ *string, _ *string, _ map[string]interface{}, _ map[string]interface{}, _ *util.RuntimeOptions) (map[string]interface{}, error) { + NotFoundFlag := true + noRetryFlag := false + if NotFoundFlag { + return responseMock["NotFoundError"]("ResourceNotfound") + } else if noRetryFlag { + return responseMock["NoRetryError"]("NoRetryError") + } + return responseMock["ReadNormal"]("") + }) + err := resourceAlicloudArmsAlertRobotRead(d, rawClient) + patcheDorequest.Reset() + assert.Nil(t, err) + }) + + t.Run("ReadDescribeArmsAlertRobotAbnormal", func(t *testing.T) { + patcheDorequest := gomonkey.ApplyMethod(reflect.TypeOf(&client.Client{}), "DoRequest", func(_ *client.Client, _ *string, _ *string, _ *string, _ *string, _ *string, _ map[string]interface{}, _ map[string]interface{}, _ *util.RuntimeOptions) (map[string]interface{}, error) { + retryFlag := false + noRetryFlag := true + if retryFlag { + return responseMock["RetryError"]("Throttling") + } else if noRetryFlag { + return responseMock["NoRetryError"]("NonRetryableError") + } + return responseMock["ReadNormal"]("") + }) + err := resourceAlicloudArmsAlertRobotRead(d, rawClient) + patcheDorequest.Reset() + assert.NotNil(t, err) + }) +} diff --git a/alicloud/service_alicloud_arms.go b/alicloud/service_alicloud_arms.go index bc2e89d80e54..16c01fe0879c 100644 --- a/alicloud/service_alicloud_arms.go +++ b/alicloud/service_alicloud_arms.go @@ -106,6 +106,51 @@ func (s *ArmsService) DescribeArmsAlertContactGroup(id string) (object map[strin return object, nil } +func (s *ArmsService) DescribeArmsAlertRobot(id string) (object map[string]interface{}, err error) { + var response map[string]interface{} + conn, err := s.client.NewArmsClient() + if err != nil { + return nil, WrapError(err) + } + action := "DescribeIMRobots" + request := map[string]interface{}{ + "RobotIds": id, + "Page": 1, + "Size": PageSizeXLarge, + } + runtime := util.RuntimeOptions{} + runtime.SetAutoretry(true) + wait := incrementalWait(3*time.Second, 3*time.Second) + err = resource.Retry(5*time.Minute, func() *resource.RetryError { + response, err = conn.DoRequest(StringPointer(action), nil, StringPointer("POST"), StringPointer("2019-08-08"), StringPointer("AK"), nil, request, &runtime) + if err != nil { + if NeedRetry(err) { + wait() + return resource.RetryableError(err) + } + return resource.NonRetryableError(err) + } + return nil + }) + addDebug(action, response, request) + if err != nil { + return object, WrapErrorf(err, DefaultErrorMsg, id, action, AlibabaCloudSdkGoERROR) + } + v, err := jsonpath.Get("$.PageBean.AlertIMRobots", response) + if err != nil { + return object, WrapErrorf(err, FailedGetAttributeMsg, id, "$.PageBean.AlertIMRobots", response) + } + if len(v.([]interface{})) < 1 { + return object, WrapErrorf(Error(GetNotFoundMessage("ARMS", id)), NotFoundWithResponse, response) + } else { + if fmt.Sprint(v.([]interface{})[0].(map[string]interface{})["RobotId"]) != id { + return object, WrapErrorf(Error(GetNotFoundMessage("ARMS", id)), NotFoundWithResponse, response) + } + } + object = v.([]interface{})[0].(map[string]interface{}) + return object, nil +} + func (s *ArmsService) DescribeArmsDispatchRule(id string) (object map[string]interface{}, err error) { conn, err := s.client.NewArmsClient() if err != nil { diff --git a/website/docs/d/arms_alert_robots.html.markdown b/website/docs/d/arms_alert_robots.html.markdown new file mode 100644 index 000000000000..bee97d969a9a --- /dev/null +++ b/website/docs/d/arms_alert_robots.html.markdown @@ -0,0 +1,58 @@ +--- +subcategory: "Application Real-Time Monitoring Service (ARMS)" +layout: "alicloud" +page_title: "Alicloud: alicloud_arms_alert_robots" +sidebar_current: "docs-alicloud-datasource-arms-alert-robots" +description: |- + Provides a list of Arms Alert Robots to the user. +--- + +# alicloud_arms_alert_robots + +This data source provides the Arms Alert Robots of the current Alibaba Cloud user. + +-> **NOTE:** Available since v1.236.0. + +## Example Usage + +Basic Usage + +```terraform +resource "alicloud_arms_alert_robot" "default" { + alert_robot_name = "my-AlertRobot" + robot_type = "wechat" + robot_addr = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=1c704e23" +} +data "alicloud_arms_alert_robots" "nameRegex" { + alert_robot_name = alicloud_arms_alert_robot.default.alert_robot_name +} +output "arms_alert_robot_id" { + value = data.alicloud_arms_alert_robots.nameRegex.robots.0.id +} +``` + +## Argument Reference + +The following arguments are supported: + +* `ids` - (Optional, ForceNew, Computed) A list of Alert Robot IDs. +* `name_regex` - (Optional, ForceNew) A regex string to filter results by Alert Robot name. +* `alert_robot_name` - (Optional, ForceNew) The robot name. +* `robot_type` - (Optional, ForceNew) The robot type. +* `output_file` - (Optional) File name where to save data source results (after running `terraform plan`). + +## Attributes Reference + +The following attributes are exported in addition to the arguments listed above: + +* `ids` - A list of Alert Robot IDs. +* `names` - A list of Alert Robot names. +* `robots` - A list of Arms Alert Robots. Each element contains the following attributes: + * `robot_id` - The id of the robot. + * `robot_name` - The name of the robot. + * `robot_type` - The type of the robot. + * `robot_addr` - The webhook url of the robot. + * `daily_noc` - Specifies whether the alert robot receives daily notifications. + * `daily_noc_time` - The time of the daily notification. + * `create_time` - The creation time of the resource. + * `id` - The ID of the Alert Robot. diff --git a/website/docs/r/arms_alert_robot.html.markdown b/website/docs/r/arms_alert_robot.html.markdown new file mode 100644 index 000000000000..f7600dfde7b4 --- /dev/null +++ b/website/docs/r/arms_alert_robot.html.markdown @@ -0,0 +1,76 @@ +--- +subcategory: "Application Real-Time Monitoring Service (ARMS)" +layout: "alicloud" +page_title: "Alicloud: alicloud_arms_alert_robot" +sidebar_current: "docs-alicloud-resource-arms-alert-robot" +description: |- + Provides a Alicloud Application Real-Time Monitoring Service (ARMS) Alert Robot resource. +--- + +# alicloud_arms_alert_robot + +Provides a Application Real-Time Monitoring Service (ARMS) Alert Robot resource. + +For information about Application Real-Time Monitoring Service (ARMS) Alert Robot and how to use it, see [What is Alert Robot](https://next.api.alibabacloud.com/document/ARMS/2019-08-08/CreateOrUpdateIMRobot). + +-> **NOTE:** Available since v1.236.0. + +## Example Usage + +Basic Usage + +
+ +```terraform +resource "alicloud_arms_alert_robot" "wechat" { + alert_robot_name = "example_wechat" + robot_type = "wechat" + robot_addr = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=1c704e23" + daily_noc = true + daily_noc_time = "09:30,17:00" +} + +resource "alicloud_arms_alert_robot" "dingding" { + alert_robot_name = "example_dingding" + robot_type = "dingding" + robot_addr = "https://oapi.dingtalk.com/robot/send?access_token=1c704e23" + daily_noc = true + daily_noc_time = "09:30,17:00" +} + +resource "alicloud_arms_alert_robot" "feishu" { + alert_robot_name = "example_feishu" + robot_type = "feishu" + robot_addr = "https://open.feishu.cn/open-apis/bot/v2/hook/a48efa01" + daily_noc = true + daily_noc_time = "09:30,17:00" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `alert_robot_name` - (Required) The name of the resource. +* `robot_type` - (Required, ForceNew) The type of the robot, Valid values: `wechat`, `dingding`, `feishu`. +* `robot_addr` - (Required) The webhook url of the robot. +* `daily_noc` - (Optional) Specifies whether the alert robot receives daily notifications. Valid values: `true`: receives daily notifications. `false`: does not receive daily notifications, default to `false`. +* `daily_noc_time` - (Optional) The time of the daily notification. + +## Attributes Reference + +The following attributes are exported: + +* `id` - The resource ID in terraform of Alert Robot. + +## Import + +Application Real-Time Monitoring Service (ARMS) Alert Robot can be imported using the id, e.g. + +```shell +$ terraform import alicloud_arms_alert_robot.example +```