From f1406b45757540ef42a1129e65840c0546aa8b60 Mon Sep 17 00:00:00 2001 From: MrWolong Date: Mon, 30 Mar 2026 09:47:29 +0800 Subject: [PATCH] New Data Source: alicloud_esa_waf_rulesets --- .../data_source_alicloud_esa_waf_rulesets.go | 289 ++++++++++++++++++ ...a_source_alicloud_esa_waf_rulesets_test.go | 255 ++++++++++++++++ alicloud/provider.go | 1 + website/docs/d/esa_waf_rulesets.html.markdown | 83 +++++ 4 files changed, 628 insertions(+) create mode 100644 alicloud/data_source_alicloud_esa_waf_rulesets.go create mode 100644 alicloud/data_source_alicloud_esa_waf_rulesets_test.go create mode 100644 website/docs/d/esa_waf_rulesets.html.markdown diff --git a/alicloud/data_source_alicloud_esa_waf_rulesets.go b/alicloud/data_source_alicloud_esa_waf_rulesets.go new file mode 100644 index 000000000000..41202b207560 --- /dev/null +++ b/alicloud/data_source_alicloud_esa_waf_rulesets.go @@ -0,0 +1,289 @@ +package alicloud + +import ( + "fmt" + "regexp" + "time" + + "github.com/PaesslerAG/jsonpath" + "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 dataSourceAliCloudEsaWafRuleSets() *schema.Resource { + return &schema.Resource{ + Read: dataSourceAliCloudEsaWafRuleSetRead, + Schema: map[string]*schema.Schema{ + "ids": { + Type: schema.TypeList, + Optional: true, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "name_regex": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringIsValidRegExp, + }, + "site_id": { + Type: schema.TypeString, + Required: true, + }, + "phase": { + Type: schema.TypeString, + Required: true, + }, + "site_version": { + Type: schema.TypeInt, + Required: true, + }, + "status": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: StringInSlice([]string{"on", "off"}, true), + }, + "query_args": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "any_like": { + Type: schema.TypeString, + Optional: true, + }, + "name_like": { + Type: schema.TypeString, + Optional: true, + }, + "order_by": { + Type: schema.TypeString, + Optional: true, + }, + "desc": { + Type: schema.TypeBool, + Optional: true, + }, + }, + }, + }, + "output_file": { + Type: schema.TypeString, + Optional: true, + }, + "names": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "sets": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + "ruleset_id": { + Type: schema.TypeString, + Computed: true, + }, + "phase": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + "target": { + Type: schema.TypeString, + Computed: true, + }, + "status": { + Type: schema.TypeString, + Computed: true, + }, + "update_time": { + Type: schema.TypeString, + Computed: true, + }, + "types": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "fields": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + }, + } +} + +func dataSourceAliCloudEsaWafRuleSetRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*connectivity.AliyunClient) + + action := "ListWafRulesets" + request := make(map[string]interface{}) + request["RegionId"] = client.RegionId + request["PageSize"] = PageSizeLarge + request["PageNumber"] = 1 + + request["SiteId"] = d.Get("site_id") + request["Phase"] = d.Get("phase") + request["SiteVersion"] = d.Get("site_version") + + if v, ok := d.GetOk("query_args"); ok { + queryArgsMap := map[string]interface{}{} + for _, queryArgsList := range v.([]interface{}) { + queryArgsArg := queryArgsList.(map[string]interface{}) + + if anyLike, ok := queryArgsArg["any_like"]; ok { + queryArgsMap["AnyLike"] = anyLike + } + + if nameLike, ok := queryArgsArg["name_like"]; ok { + queryArgsMap["NameLike"] = nameLike + } + + if orderBy, ok := queryArgsArg["order_by"]; ok { + queryArgsMap["OrderBy"] = orderBy + } + + if desc, ok := d.GetOkExists("query_args.0.desc"); ok { + queryArgsMap["Desc"] = desc + } + } + + request["QueryArgs"] = convertObjectToJsonString(queryArgsMap) + } + + status, statusOk := d.GetOk("status") + + var objects []map[string]interface{} + + 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 wafRuleSetNameRegex *regexp.Regexp + if v, ok := d.GetOk("name_regex"); ok { + r, err := regexp.Compile(v.(string)) + if err != nil { + return WrapError(err) + } + + wafRuleSetNameRegex = r + } + + var response map[string]interface{} + var err error + + for { + wait := incrementalWait(3*time.Second, 5*time.Second) + err = resource.Retry(5*time.Minute, func() *resource.RetryError { + response, err = client.RpcPost("ESA", "2024-09-10", action, nil, request, true) + if err != nil { + if IsExpectedErrors(err, []string{"Site.ServiceBusy", "TooManyRequests"}) || 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_esa_waf_rulesets", action, AlibabaCloudSdkGoERROR) + } + + resp, err := jsonpath.Get("$.Rulesets", response) + if err != nil { + return WrapErrorf(err, FailedGetAttributeMsg, action, "$.Rulesets", response) + } + + result, _ := resp.([]interface{}) + for _, v := range result { + item := v.(map[string]interface{}) + if len(idsMap) > 0 { + if _, ok := idsMap[fmt.Sprintf("%v:%v", item["Id"], request["SiteId"])]; !ok { + continue + } + } + + if wafRuleSetNameRegex != nil { + if !wafRuleSetNameRegex.MatchString(fmt.Sprint(item["Name"])) { + continue + } + } + + if statusOk && status.(string) != "" && status.(string) != item["Status"].(string) { + continue + } + + objects = append(objects, item) + } + + if len(result) < PageSizeLarge { + break + } + + request["PageNumber"] = request["PageNumber"].(int) + 1 + } + + ids := make([]string, 0) + names := make([]interface{}, 0) + s := make([]map[string]interface{}, 0) + for _, object := range objects { + mapping := map[string]interface{}{ + "id": fmt.Sprintf("%v:%v", object["Id"], request["SiteId"]), + "ruleset_id": fmt.Sprint(object["Id"]), + "phase": object["Phase"], + "name": object["Name"], + "target": object["Target"], + "status": object["Status"], + "update_time": object["UpdateTime"], + "types": object["Types"], + "fields": object["Fields"], + } + + ids = append(ids, fmt.Sprint(mapping["id"])) + names = append(names, object["Name"]) + 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("sets", 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_esa_waf_rulesets_test.go b/alicloud/data_source_alicloud_esa_waf_rulesets_test.go new file mode 100644 index 000000000000..61eef0e9fe28 --- /dev/null +++ b/alicloud/data_source_alicloud_esa_waf_rulesets_test.go @@ -0,0 +1,255 @@ +package alicloud + +import ( + "fmt" + "testing" + + "github.com/aliyun/terraform-provider-alicloud/alicloud/connectivity" + "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" +) + +func TestAccAliCloudEsaWafRuleSetsDataSource_basic0(t *testing.T) { + rand := acctest.RandIntRange(10000, 99999) + resourceId := "data.alicloud_esa_waf_rulesets.default" + name := fmt.Sprintf("tf-testAcc-EsaWafRuleSet%d", rand) + testAccConfig := dataSourceTestAccConfigFunc(resourceId, name, dataSourceEsaWafRuleSetsConfig) + + idsConf := dataSourceTestAccConfig{ + existConfig: testAccConfig(map[string]interface{}{ + "site_id": "${alicloud_esa_waf_rule.default.site_id}", + "phase": "http_custom", + "site_version": "0", + "ids": []string{"${alicloud_esa_waf_ruleset.default.id}"}, + }), + fakeConfig: testAccConfig(map[string]interface{}{ + "site_id": "${alicloud_esa_waf_rule.default.site_id}", + "phase": "http_custom", + "site_version": "0", + "ids": []string{"${alicloud_esa_waf_ruleset.default.id}_fake"}, + }), + } + + nameRegexConf := dataSourceTestAccConfig{ + existConfig: testAccConfig(map[string]interface{}{ + "site_id": "${alicloud_esa_waf_rule.default.site_id}", + "phase": "http_custom", + "site_version": "0", + "name_regex": "${alicloud_esa_waf_ruleset.default.name}", + }), + fakeConfig: testAccConfig(map[string]interface{}{ + "site_id": "${alicloud_esa_waf_rule.default.site_id}", + "phase": "http_custom", + "site_version": "0", + "name_regex": "${alicloud_esa_waf_ruleset.default.name}_fake", + }), + } + + statusConf := dataSourceTestAccConfig{ + existConfig: testAccConfig(map[string]interface{}{ + "site_id": "${alicloud_esa_waf_rule.default.site_id}", + "phase": "http_custom", + "site_version": "0", + "ids": []string{"${alicloud_esa_waf_ruleset.default.id}"}, + "status": "on", + }), + fakeConfig: testAccConfig(map[string]interface{}{ + "site_id": "${alicloud_esa_waf_rule.default.site_id}", + "phase": "http_custom", + "site_version": "0", + "ids": []string{"${alicloud_esa_waf_ruleset.default.id}_fake"}, + "status": "off", + }), + } + + anyQueryArgsConf := dataSourceTestAccConfig{ + existConfig: testAccConfig(map[string]interface{}{ + "site_id": "${alicloud_esa_waf_rule.default.site_id}", + "phase": "http_custom", + "site_version": "0", + "query_args": []map[string]interface{}{ + { + "any_like": "${alicloud_esa_waf_rule.default.ruleset_id}", + "order_by": "id", + "desc": "true", + }, + }, + }), + fakeConfig: testAccConfig(map[string]interface{}{ + "site_id": "${alicloud_esa_waf_rule.default.site_id}", + "phase": "http_custom", + "site_version": "0", + "query_args": []map[string]interface{}{ + { + "any_like": "${alicloud_esa_waf_rule.default.ruleset_id}_fake", + "order_by": "id", + "desc": "false", + }, + }, + }), + } + + nameQueryArgsConf := dataSourceTestAccConfig{ + existConfig: testAccConfig(map[string]interface{}{ + "site_id": "${alicloud_esa_waf_rule.default.site_id}", + "phase": "http_custom", + "site_version": "0", + "query_args": []map[string]interface{}{ + { + "name_like": "${alicloud_esa_waf_ruleset.default.name}", + "order_by": "name", + "desc": "true", + }, + }, + }), + fakeConfig: testAccConfig(map[string]interface{}{ + "site_id": "${alicloud_esa_waf_rule.default.site_id}", + "phase": "http_custom", + "site_version": "0", + "query_args": []map[string]interface{}{ + { + "name_like": "${alicloud_esa_waf_ruleset.default.name}_fake", + "order_by": "name", + "desc": "false", + }, + }, + }), + } + + allQueryArgsConf := dataSourceTestAccConfig{ + existConfig: testAccConfig(map[string]interface{}{ + "site_id": "${alicloud_esa_waf_rule.default.site_id}", + "phase": "http_custom", + "site_version": "0", + "query_args": []map[string]interface{}{ + { + "any_like": "${alicloud_esa_waf_rule.default.ruleset_id}", + "name_like": "${alicloud_esa_waf_ruleset.default.name}", + "order_by": "id", + "desc": "true", + }, + }, + }), + fakeConfig: testAccConfig(map[string]interface{}{ + "site_id": "${alicloud_esa_waf_rule.default.site_id}", + "phase": "http_custom", + "site_version": "0", + "query_args": []map[string]interface{}{ + { + "any_like": "${alicloud_esa_waf_rule.default.ruleset_id}_fake", + "name_like": "${alicloud_esa_waf_ruleset.default.name}_fake", + "order_by": "id", + "desc": "false", + }, + }, + }), + } + + allConf := dataSourceTestAccConfig{ + existConfig: testAccConfig(map[string]interface{}{ + "site_id": "${alicloud_esa_waf_rule.default.site_id}", + "phase": "http_custom", + "site_version": "0", + "ids": []string{"${alicloud_esa_waf_ruleset.default.id}"}, + "name_regex": "${alicloud_esa_waf_ruleset.default.name}", + "status": "on", + "query_args": []map[string]interface{}{ + { + "any_like": "${alicloud_esa_waf_rule.default.ruleset_id}", + "name_like": "${alicloud_esa_waf_ruleset.default.name}", + "order_by": "id", + "desc": "true", + }, + }, + }), + fakeConfig: testAccConfig(map[string]interface{}{ + "site_id": "${alicloud_esa_waf_rule.default.site_id}", + "phase": "http_custom", + "site_version": "0", + "ids": []string{"${alicloud_esa_waf_ruleset.default.id}_fake"}, + "name_regex": "${alicloud_esa_waf_ruleset.default.name}_fake", + "status": "off", + "query_args": []map[string]interface{}{ + { + "any_like": "${alicloud_esa_waf_rule.default.ruleset_id}_fake", + "name_like": "${alicloud_esa_waf_ruleset.default.name}_fake", + "order_by": "id", + "desc": "false", + }, + }, + }), + } + + var existAliCloudEsaWafRuleSetsMapFunc = func(rand int) map[string]string { + return map[string]string{ + "ids.#": "1", + "names.#": "1", + "sets.#": "1", + "sets.0.id": CHECKSET, + "sets.0.ruleset_id": CHECKSET, + "sets.0.phase": CHECKSET, + "sets.0.name": CHECKSET, + "sets.0.status": CHECKSET, + "sets.0.update_time": CHECKSET, + "sets.0.types.#": CHECKSET, + //"sets.0.target": CHECKSET, + //"sets.0.fields.#": CHECKSET, + } + } + + var fakeAliCloudEsaWafRuleSetsMapFunc = func(rand int) map[string]string { + return map[string]string{ + "ids.#": "0", + "names.#": "0", + "sets.#": "0", + } + } + + var aliCloudEsaWafRuleSetsInfo = dataSourceAttr{ + resourceId: "data.alicloud_esa_waf_rulesets.default", + existMapFunc: existAliCloudEsaWafRuleSetsMapFunc, + fakeMapFunc: fakeAliCloudEsaWafRuleSetsMapFunc, + } + + preCheck := func() { + testAccPreCheckWithRegions(t, true, connectivity.TestSalveRegions) + } + + aliCloudEsaWafRuleSetsInfo.dataSourceTestCheckWithPreCheck(t, rand, preCheck, idsConf, nameRegexConf, statusConf, anyQueryArgsConf, nameQueryArgsConf, allQueryArgsConf, allConf) +} + +func dataSourceEsaWafRuleSetsConfig(name string) string { + return fmt.Sprintf(` + variable "name" { + default = "%s" + } + +data "alicloud_esa_sites" "default" { + plan_subscribe_type = "enterpriseplan" +} + +resource "alicloud_esa_waf_ruleset" "default" { + site_id = data.alicloud_esa_sites.default.sites.0.site_id + phase = "http_custom" + site_version = "0" + name = var.name +} + +resource "alicloud_esa_waf_rule" "default" { + site_id = data.alicloud_esa_sites.default.sites.0.site_id + ruleset_id = alicloud_esa_waf_ruleset.default.ruleset_id + phase = "http_custom" + site_version = "0" + config { + status = "on" + action = "deny" + expression = "(http.host in {\"123.example.top\"})" + actions { + response { + id = "0" + code = "403" + } + } + } +} +`, name) +} diff --git a/alicloud/provider.go b/alicloud/provider.go index 175223aa9a10..babd8fc02164 100644 --- a/alicloud/provider.go +++ b/alicloud/provider.go @@ -171,6 +171,7 @@ func Provider() terraform.ResourceProvider { }, }, DataSourcesMap: map[string]*schema.Resource{ + "alicloud_esa_waf_rulesets": dataSourceAliCloudEsaWafRuleSets(), "alicloud_cs_clusters": dataSourceAliCloudAckClusters(), "alicloud_threat_detection_check_item_configs": dataSourceAliCloudThreatDetectionCheckItemConfigs(), "alicloud_threat_detection_check_structures": dataSourceAliCloudThreatDetectionCheckStructures(), diff --git a/website/docs/d/esa_waf_rulesets.html.markdown b/website/docs/d/esa_waf_rulesets.html.markdown new file mode 100644 index 000000000000..4e11b131736e --- /dev/null +++ b/website/docs/d/esa_waf_rulesets.html.markdown @@ -0,0 +1,83 @@ +--- +subcategory: "ESA" +layout: "alicloud" +page_title: "Alicloud: alicloud_esa_waf_rulesets" +description: |- + Provides a list of ESA Waf Rulesets to the user. +--- + +# alicloud_esa_waf_rulesets + +This data source provides the ESA Waf Rulesets of the current Alibaba Cloud user. + +-> **NOTE:** Available since v1.274.0. + +## Example Usage + +Basic Usage + +```terraform +variable "name" { + default = "terraform-example" +} + +data "alicloud_esa_sites" "default" { + plan_subscribe_type = "enterpriseplan" +} + +resource "alicloud_esa_waf_ruleset" "default" { + site_id = data.alicloud_esa_sites.default.sites.0.site_id + phase = "http_custom" + site_version = "0" + name = var.name +} + +data "alicloud_esa_waf_rulesets" "ids" { + ids = [alicloud_esa_waf_ruleset.default.id] + site_id = alicloud_esa_waf_ruleset.default.site_id + phase = alicloud_esa_waf_ruleset.default.phase + site_version = alicloud_esa_waf_ruleset.default.site_version +} + +output "esa_waf_rulesets_id_0" { + value = data.alicloud_esa_waf_rulesets.ids.sets.0.id +} +``` + +## Argument Reference + +The following attributes are exported: + +* `ids` - (Optional, List) A list of Waf Ruleset IDs. +* `name_regex` - (Optional) A regex string to filter results by Waf Ruleset name. +* `site_id` - (Required) The ID of the Site. +* `phase` - (Required) The WAF operation phase. +* `site_version` - (Required) The version of the Site. +* `status` - (Optional) The status of the rule set. Valid values: `on`, `off`. +* `query_args` - (Optional, Set) The query parameters. See [`query_args`](#query_args) below. +* `output_file` - (Optional) File name where to save data source results (after running `terraform plan`). + +### `query_args` + +The query_args supports the following: + +* `any_like` - (Optional) The fuzzy search for rule set ID, rule set name, rule ID, and rule name. +* `name_like` - (Optional) The fuzzy search for rule set name. +* `order_by` - (Optional) Specify the column to sort by. +* `desc` - (Optional, Bool) Whether to sort in descending order. Valid values: `true`, `false`. + +## Attributes Reference + +The following attributes are exported in addition to the arguments listed above: + +* `names` - A list of Waf Ruleset names. +* `sets` - A list of Waf Rulesets. Each element contains the following attributes: + * `id` - The ID of the WAF Rule Set. + * `ruleset_id` - The ID of the WAF rule set. + * `phase` - The WAF operation phase. + * `name` - The name of the rule set. + * `target` - Protection target type in http_bot. + * `status` - The status of the rule set. + * `update_time` - The last modification time of the rule set. + * `types` - The list of rule types. + * `fields` - The list of match objects.