From 41dba37bd72c8173a0203847ba78e2fd0eb93837 Mon Sep 17 00:00:00 2001 From: profoundwu Date: Tue, 7 Jan 2025 14:34:39 +0800 Subject: [PATCH] feat(cfw): add this data source to get the list of CFW IPS basic protection rules (#6146) --- docs/data-sources/cfw_ips_rules.md | 75 +++++++ huaweicloud/provider.go | 1 + ...a_source_huaweicloud_cfw_ips_rules_test.go | 97 +++++++++ .../data_source_huaweicloud_cfw_ips_rules.go | 204 ++++++++++++++++++ 4 files changed, 377 insertions(+) create mode 100644 docs/data-sources/cfw_ips_rules.md create mode 100644 huaweicloud/services/acceptance/cfw/data_source_huaweicloud_cfw_ips_rules_test.go create mode 100644 huaweicloud/services/cfw/data_source_huaweicloud_cfw_ips_rules.go diff --git a/docs/data-sources/cfw_ips_rules.md b/docs/data-sources/cfw_ips_rules.md new file mode 100644 index 0000000000..c92e3572ff --- /dev/null +++ b/docs/data-sources/cfw_ips_rules.md @@ -0,0 +1,75 @@ +--- +subcategory: "Cloud Firewall (CFW)" +layout: "huaweicloud" +page_title: "HuaweiCloud: huaweicloud_cfw_ips_rules" +description: |- + Use this data source to get the list of CFW IPS basic protection rules. +--- + +# huaweicloud_cfw_ips_rules + +Use this data source to get the list of CFW IPS basic protection rules. + +## Example Usage + +```hcl +variable "object_id" {} + +data "huaweicloud_cfw_ips_rules" "test" { + object_id = var.object_id +} +``` + +## Argument Reference + +The following arguments are supported: + +* `region` - (Optional, String) Specifies the region in which to query the resource. + If omitted, the provider-level region will be used. + +* `object_id` - (Required, String) Specifies the protected object ID. + +* `ips_id` - (Optional, String) Specifies the IPS rule ID. + +* `ips_name_like` - (Optional, String) Specifies the IPS rule name. + This parameter supports fuzzy search. + +* `ips_status` - (Optional, String) Specifies the IPS rule status. + The valid value can be **OBSERVE**, **ENABLE**, or **CLOSE**. + +* `is_updated_ips_rule_queried` - (Optional, Bool) Specifies whether to check for new update rules. + +* `enterprise_project_id` - (Optional, String) Specifies the enterprise project ID. + +## Attribute Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - The data source ID. + +* `records` - The IPS rule list. + + The [records](#data_records_struct) structure is documented below. + + +The `records` block supports: + +* `ips_group` - The IPS rule group. + +* `ips_id` - The IPS rule ID. + +* `ips_name` - The IPS rule name. + +* `ips_rules_type` - The IPS rule type. + +* `affected_application` - The application affected by the rule. + +* `create_time` - The creation time. + +* `ips_cve` - The CVE. + +* `default_status` - The default status of the IPS rule. + +* `ips_level` - The risk level. + +* `ips_status` - The current status of the IPS rule. diff --git a/huaweicloud/provider.go b/huaweicloud/provider.go index eb5231646f..c1ec92f6a3 100644 --- a/huaweicloud/provider.go +++ b/huaweicloud/provider.go @@ -569,6 +569,7 @@ func Provider() *schema.Provider { "huaweicloud_cfw_attack_logs": cfw.DataSourceCfwAttackLogs(), "huaweicloud_cfw_flow_logs": cfw.DataSourceCfwFlowLogs(), "huaweicloud_cfw_regions": cfw.DataSourceCfwRegions(), + "huaweicloud_cfw_ips_rules": cfw.DataSourceCfwIpsRules(), "huaweicloud_cnad_advanced_instances": cnad.DataSourceInstances(), "huaweicloud_cnad_advanced_available_objects": cnad.DataSourceAvailableProtectedObjects(), diff --git a/huaweicloud/services/acceptance/cfw/data_source_huaweicloud_cfw_ips_rules_test.go b/huaweicloud/services/acceptance/cfw/data_source_huaweicloud_cfw_ips_rules_test.go new file mode 100644 index 0000000000..400ca287c5 --- /dev/null +++ b/huaweicloud/services/acceptance/cfw/data_source_huaweicloud_cfw_ips_rules_test.go @@ -0,0 +1,97 @@ +package cfw + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/services/acceptance" +) + +func TestAccDataSourceCfwIpsRules_basic(t *testing.T) { + dataSource := "data.huaweicloud_cfw_ips_rules.test" + dc := acceptance.InitDataSourceCheck(dataSource) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acceptance.TestAccPreCheck(t) + acceptance.TestAccPreCheckCfw(t) + }, + ProviderFactories: acceptance.TestAccProviderFactories, + Steps: []resource.TestStep{ + { + Config: testDataSourceCfwIpsRules_basic(), + Check: resource.ComposeTestCheckFunc( + dc.CheckResourceExists(), + resource.TestCheckResourceAttrSet(dataSource, "records.0.affected_application"), + resource.TestCheckResourceAttrSet(dataSource, "records.0.create_time"), + resource.TestCheckResourceAttrSet(dataSource, "records.0.default_status"), + resource.TestCheckResourceAttrSet(dataSource, "records.0.ips_id"), + resource.TestCheckResourceAttrSet(dataSource, "records.0.ips_level"), + resource.TestCheckResourceAttrSet(dataSource, "records.0.ips_name"), + resource.TestCheckResourceAttrSet(dataSource, "records.0.ips_group"), + resource.TestCheckResourceAttrSet(dataSource, "records.0.ips_status"), + resource.TestCheckResourceAttrSet(dataSource, "records.0.ips_rules_type"), + resource.TestCheckOutput("is_default_filter_useful", "true"), + resource.TestCheckOutput("is_id_filter_useful", "true"), + resource.TestCheckOutput("is_name_like_filter_useful", "true"), + resource.TestCheckOutput("is_status_filter_useful", "true"), + ), + }, + }, + }) +} + +func testDataSourceCfwIpsRules_basic() string { + return fmt.Sprintf(` +%[1]s + +locals { + ips_id = "340710" + ips_name_like = "web" + ips_status = "OBSERVE" +} + +data "huaweicloud_cfw_ips_rules" "test" { + object_id = data.huaweicloud_cfw_firewalls.test.records[0].protect_objects[0].object_id +} + +output "is_default_filter_useful" { + value = length(data.huaweicloud_cfw_ips_rules.test.records) >= 1 +} + +data "huaweicloud_cfw_ips_rules" "filter_by_id" { + object_id = data.huaweicloud_cfw_firewalls.test.records[0].protect_objects[0].object_id + ips_id = local.ips_id +} + +output "is_id_filter_useful" { + value = length(data.huaweicloud_cfw_ips_rules.filter_by_id.records) >= 1 && alltrue( + [for r in data.huaweicloud_cfw_ips_rules.filter_by_id.records[*] : r.ips_id == local.ips_id] + ) +} + +data "huaweicloud_cfw_ips_rules" "filter_by_name_like" { + object_id = data.huaweicloud_cfw_firewalls.test.records[0].protect_objects[0].object_id + ips_name_like = local.ips_name_like +} + +output "is_name_like_filter_useful" { + value = length(data.huaweicloud_cfw_ips_rules.filter_by_name_like.records) >= 1 && alltrue( + [for r in data.huaweicloud_cfw_ips_rules.filter_by_name_like.records[*] : can(regex("(?i).*web.*", r.ips_name))] + ) +} + +data "huaweicloud_cfw_ips_rules" "filter_by_status" { + object_id = data.huaweicloud_cfw_firewalls.test.records[0].protect_objects[0].object_id + ips_status = local.ips_status +} + +output "is_status_filter_useful" { + value = length(data.huaweicloud_cfw_ips_rules.filter_by_status.records) >= 1 && alltrue( + [for r in data.huaweicloud_cfw_ips_rules.filter_by_status.records[*] : r.ips_status == local.ips_status] + ) +} +`, testAccDatasourceFirewalls_basic()) +} diff --git a/huaweicloud/services/cfw/data_source_huaweicloud_cfw_ips_rules.go b/huaweicloud/services/cfw/data_source_huaweicloud_cfw_ips_rules.go new file mode 100644 index 0000000000..968b739ba8 --- /dev/null +++ b/huaweicloud/services/cfw/data_source_huaweicloud_cfw_ips_rules.go @@ -0,0 +1,204 @@ +// Generated by PMS #508 +package cfw + +import ( + "context" + + "github.com/hashicorp/go-multierror" + "github.com/hashicorp/go-uuid" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/tidwall/gjson" + + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/config" + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/helper/httphelper" + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/helper/schemas" + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/utils" +) + +func DataSourceCfwIpsRules() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceCfwIpsRulesRead, + + Schema: map[string]*schema.Schema{ + "region": { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: `Specifies the region in which to query the resource. If omitted, the provider-level region will be used.`, + }, + "object_id": { + Type: schema.TypeString, + Required: true, + Description: `Specifies the protected object ID.`, + }, + "ips_id": { + Type: schema.TypeString, + Optional: true, + Description: `Specifies the IPS rule ID.`, + }, + "ips_name_like": { + Type: schema.TypeString, + Optional: true, + Description: `Specifies the IPS rule name.`, + }, + "ips_status": { + Type: schema.TypeString, + Optional: true, + Description: `Specifies the IPS rule status.`, + }, + "is_updated_ips_rule_queried": { + Type: schema.TypeBool, + Optional: true, + Description: `Specifies whether to check for new update rules.`, + }, + "enterprise_project_id": { + Type: schema.TypeString, + Optional: true, + Description: `Specifies the enterprise project ID.`, + }, + "records": { + Type: schema.TypeList, + Computed: true, + Description: `The IPS rule list.`, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ips_group": { + Type: schema.TypeString, + Computed: true, + Description: `The IPS rule group.`, + }, + "ips_id": { + Type: schema.TypeString, + Computed: true, + Description: `The IPS rule ID.`, + }, + "ips_name": { + Type: schema.TypeString, + Computed: true, + Description: `The IPS rule name.`, + }, + "ips_rules_type": { + Type: schema.TypeString, + Computed: true, + Description: `The IPS rule type.`, + }, + "affected_application": { + Type: schema.TypeString, + Computed: true, + Description: `The application affected by the rule.`, + }, + "create_time": { + Type: schema.TypeString, + Computed: true, + Description: `The creation time.`, + }, + "ips_cve": { + Type: schema.TypeString, + Computed: true, + Description: `The CVE.`, + }, + "default_status": { + Type: schema.TypeString, + Computed: true, + Description: `The default status of the IPS rule.`, + }, + "ips_level": { + Type: schema.TypeString, + Computed: true, + Description: `The risk level.`, + }, + "ips_status": { + Type: schema.TypeString, + Computed: true, + Description: `The current status of the IPS rule.`, + }, + }, + }, + }, + }, + } +} + +type IpsRulesDSWrapper struct { + *schemas.ResourceDataWrapper + Config *config.Config +} + +func newIpsRulesDSWrapper(d *schema.ResourceData, meta interface{}) *IpsRulesDSWrapper { + return &IpsRulesDSWrapper{ + ResourceDataWrapper: schemas.NewSchemaWrapper(d), + Config: meta.(*config.Config), + } +} + +func dataSourceCfwIpsRulesRead(_ context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + wrapper := newIpsRulesDSWrapper(d, meta) + listIpsRules1Rst, err := wrapper.ListIpsRules1() + if err != nil { + return diag.FromErr(err) + } + + id, err := uuid.GenerateUUID() + if err != nil { + return diag.FromErr(err) + } + d.SetId(id) + + err = wrapper.listIpsRules1ToSchema(listIpsRules1Rst) + if err != nil { + return diag.FromErr(err) + } + + return nil +} + +// @API CFW GET /v1/{project_id}/ips-rule +func (w *IpsRulesDSWrapper) ListIpsRules1() (*gjson.Result, error) { + client, err := w.NewClient(w.Config, "cfw") + if err != nil { + return nil, err + } + + uri := "/v1/{project_id}/ips-rule" + params := map[string]any{ + "ips_id": w.Get("ips_id"), + "ips_name_like": w.Get("ips_name_like"), + "ips_status": w.Get("ips_status"), + "is_updated_ips_rule_queried": w.Get("is_updated_ips_rule_queried"), + "object_id": w.Get("object_id"), + "enterprise_project_id": w.Get("enterprise_project_id"), + } + params = utils.RemoveNil(params) + return httphelper.New(client). + Method("GET"). + URI(uri). + Query(params). + OffsetPager("data.records", "offset", "limit", 1000). + Request(). + Result() +} + +func (w *IpsRulesDSWrapper) listIpsRules1ToSchema(body *gjson.Result) error { + d := w.ResourceData + mErr := multierror.Append(nil, + d.Set("region", w.Config.GetRegion(w.ResourceData)), + d.Set("records", schemas.SliceToList(body.Get("data.records"), + func(records gjson.Result) any { + return map[string]any{ + "ips_group": records.Get("ips_group").Value(), + "ips_id": records.Get("ips_id").Value(), + "ips_name": records.Get("ips_name").Value(), + "ips_rules_type": records.Get("ips_rules_type").Value(), + "affected_application": records.Get("affected_application").Value(), + "create_time": records.Get("create_time").Value(), + "ips_cve": records.Get("ips_cve").Value(), + "default_status": records.Get("default_status").Value(), + "ips_level": records.Get("ips_level").Value(), + "ips_status": records.Get("ips_status").Value(), + } + }, + )), + ) + return mErr.ErrorOrNil() +}