Skip to content

Commit 9c45695

Browse files
feat(waf): add data source to get the average bandwidth usage (#7019)
1 parent c881c67 commit 9c45695

File tree

4 files changed

+359
-0
lines changed

4 files changed

+359
-0
lines changed
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
---
2+
subcategory: "Web Application Firewall (WAF)"
3+
layout: "huaweicloud"
4+
page_title: "HuaweiCloud: huaweicloud_waf_overviews_bandwidth_timeline"
5+
description: |-
6+
Use this data source to query the average bandwidth usage.
7+
---
8+
9+
# huaweicloud_waf_overviews_bandwidth_timeline
10+
11+
Use this data source to query the average bandwidth usage.
12+
13+
## Example Usage
14+
15+
```hcl
16+
variable "start_time" {}
17+
variable "end_time" {}
18+
19+
data "huaweicloud_waf_overviews_bandwidth_timeline" "test" {
20+
from = var.start_time
21+
to = var.end_time
22+
}
23+
```
24+
25+
## Argument Reference
26+
27+
The following arguments are supported:
28+
29+
* `region` - (Optional, String) Specifies the region in which to query the resource.
30+
If omitted, the provider-level region will be used.
31+
32+
* `from` - (Required, Int) Specifies the query start time.
33+
The format is 13-digit timestamp in millisecond.
34+
35+
* `to` - (Required, Int) Specifies the query end time.
36+
The format is 13-digit timestamp in millisecond.
37+
38+
* `group_by` - (Optional, String) Specifies the display dimension.
39+
The value can be **DAY**, indicates data is displayed by the day.
40+
If this parameter is not specified, the data is displayed by the minute.
41+
42+
* `display_option` - (Optional, String) Specifies the number of sent or received bytes.
43+
The valid values are as follows:
44+
+ **1**: Indicates view the peak value.
45+
+ **0**: Indicates view the average value.
46+
47+
* `hosts` - (Optional, String) Specifies the ID of the domain.
48+
49+
* `instances` - (Optional, String) Specifies the ID of the dedicated WAF instance.
50+
This parameter is used to query the average bandwidth usage of domain protected by the dedicated WAF instance.
51+
52+
* `enterprise_project_id` - (Optional, String) Specifies the enterprise project ID.
53+
If you want to query resources under all enterprise projects, set this parameter to **all_granted_eps**.
54+
55+
## Attribute Reference
56+
57+
In addition to all arguments above, the following attributes are exported:
58+
59+
* `id` - The data source ID.
60+
61+
* `bandwidths` - The bandwidth statistics over the time.
62+
63+
The [bandwidths](#bandwidths_struct) structure is documented below.
64+
65+
<a name="bandwidths_struct"></a>
66+
The `bandwidths` block supports:
67+
68+
* `key` - The key type.
69+
The options are **BANDWIDTH**, **IN_BANDWIDTH** and **OUT_BANDWIDTH**.
70+
71+
* `timeline` - The statistics data over time for the corresponding key.
72+
73+
The [timeline](#bandwidths_timeline_struct) structure is documented below.
74+
75+
<a name="bandwidths_timeline_struct"></a>
76+
The `timeline` block supports:
77+
78+
* `time` - The time point.
79+
80+
* `num` - The statistics data for the time range from the previous time point to the point specified by `time`.

huaweicloud/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1436,6 +1436,7 @@ func Provider() *schema.Provider {
14361436
"huaweicloud_waf_dedicated_instances": waf.DataSourceWafDedicatedInstances(),
14371437
"huaweicloud_waf_domains": waf.DataSourceWafDomains(),
14381438
"huaweicloud_waf_instance_groups": waf.DataSourceWafInstanceGroups(),
1439+
"huaweicloud_waf_overviews_bandwidth_timeline": waf.DataSourceWafOverviewsBandwidthTimeline(),
14391440
"huaweicloud_waf_overviews_classification": waf.DataSourceWafOverviewsClassification(),
14401441
"huaweicloud_waf_overviews_qps_timeline": waf.DataSourceWafOverviewsQPSTimeline(),
14411442
"huaweicloud_waf_overviews_statistics": waf.DataSourceWafOverviewsStatistics(),
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package waf
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
"time"
7+
8+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
9+
10+
"github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/services/acceptance"
11+
)
12+
13+
func TestAccDataSourceOverviewsBandwidthTimeline_basic(t *testing.T) {
14+
var (
15+
dataSourceName = "data.huaweicloud_waf_overviews_bandwidth_timeline.test"
16+
dc = acceptance.InitDataSourceCheck(dataSourceName)
17+
startTime = time.Now().Add(-24*time.Hour).UnixNano() / int64(time.Millisecond)
18+
endTime = time.Now().UnixNano() / int64(time.Millisecond)
19+
)
20+
21+
resource.ParallelTest(t, resource.TestCase{
22+
PreCheck: func() {
23+
// Before running test, please ensure have data on console.
24+
acceptance.TestAccPreCheck(t)
25+
acceptance.TestAccPrecheckWafInstance(t)
26+
},
27+
ProviderFactories: acceptance.TestAccProviderFactories,
28+
Steps: []resource.TestStep{
29+
{
30+
Config: testDataSourceOverviewsBandwidthTimeline_basic(startTime, endTime),
31+
Check: resource.ComposeTestCheckFunc(
32+
dc.CheckResourceExists(),
33+
resource.TestCheckResourceAttrSet(dataSourceName, "bandwidths.#"),
34+
resource.TestCheckResourceAttrSet(dataSourceName, "bandwidths.0.key"),
35+
resource.TestCheckResourceAttrSet(dataSourceName, "bandwidths.0.timeline.#"),
36+
resource.TestCheckResourceAttrSet(dataSourceName, "bandwidths.0.timeline.0.time"),
37+
38+
resource.TestCheckOutput("value_is_exist", "true"),
39+
resource.TestCheckOutput("group_by_filter_is_useful", "true"),
40+
resource.TestCheckOutput("display_option_filter_is_useful", "true"),
41+
),
42+
},
43+
},
44+
})
45+
}
46+
47+
func testDataSourceOverviewsBandwidthTimeline_basic(startTime, endTime int64) string {
48+
return fmt.Sprintf(`
49+
data "huaweicloud_waf_overviews_bandwidth_timeline" "test" {
50+
from = %[1]d
51+
to = %[2]d
52+
}
53+
54+
output "value_is_exist" {
55+
value = length(data.huaweicloud_waf_overviews_bandwidth_timeline.test.bandwidths) > 0
56+
}
57+
58+
data "huaweicloud_waf_overviews_bandwidth_timeline" "filter_group_by" {
59+
from = %[1]d
60+
to = %[2]d
61+
group_by = "DAY"
62+
}
63+
64+
output "group_by_filter_is_useful" {
65+
value = length(data.huaweicloud_waf_overviews_bandwidth_timeline.filter_group_by.bandwidths[0].timeline) > 0
66+
}
67+
68+
data "huaweicloud_waf_overviews_bandwidth_timeline" "filter_display_option" {
69+
from = %[1]d
70+
to = %[2]d
71+
display_option = "1"
72+
}
73+
74+
output "display_option_filter_is_useful" {
75+
value = length(data.huaweicloud_waf_overviews_bandwidth_timeline.filter_display_option.bandwidths[0].timeline) > 0
76+
}
77+
`, startTime, endTime)
78+
}
Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
package waf
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"strings"
7+
8+
"github.com/hashicorp/go-multierror"
9+
"github.com/hashicorp/go-uuid"
10+
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
11+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
12+
13+
"github.com/chnsz/golangsdk"
14+
15+
"github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/config"
16+
"github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/utils"
17+
)
18+
19+
// @API WAF GET /v1/{project_id}/waf/overviews/bandwidth/timeline
20+
func DataSourceWafOverviewsBandwidthTimeline() *schema.Resource {
21+
return &schema.Resource{
22+
ReadContext: dataSourceWafOverviewsBandwidthTimelineRead,
23+
24+
Schema: map[string]*schema.Schema{
25+
"region": {
26+
Type: schema.TypeString,
27+
Optional: true,
28+
Computed: true,
29+
},
30+
"from": {
31+
Type: schema.TypeInt,
32+
Required: true,
33+
},
34+
"to": {
35+
Type: schema.TypeInt,
36+
Required: true,
37+
},
38+
"group_by": {
39+
Type: schema.TypeString,
40+
Optional: true,
41+
},
42+
"display_option": {
43+
Type: schema.TypeString,
44+
Optional: true,
45+
},
46+
"hosts": {
47+
Type: schema.TypeString,
48+
Optional: true,
49+
},
50+
"instances": {
51+
Type: schema.TypeString,
52+
Optional: true,
53+
},
54+
"enterprise_project_id": {
55+
Type: schema.TypeString,
56+
Optional: true,
57+
},
58+
"bandwidths": {
59+
Type: schema.TypeList,
60+
Computed: true,
61+
Elem: &schema.Resource{
62+
Schema: map[string]*schema.Schema{
63+
"key": {
64+
Type: schema.TypeString,
65+
Computed: true,
66+
},
67+
"timeline": {
68+
Type: schema.TypeList,
69+
Computed: true,
70+
Elem: &schema.Resource{
71+
Schema: map[string]*schema.Schema{
72+
"time": {
73+
Type: schema.TypeInt,
74+
Computed: true,
75+
},
76+
"num": {
77+
Type: schema.TypeInt,
78+
Computed: true,
79+
},
80+
},
81+
},
82+
},
83+
},
84+
},
85+
},
86+
},
87+
}
88+
}
89+
90+
func buildOverviewsBandwidthQueryParams(cfg *config.Config, d *schema.ResourceData) string {
91+
epsId := cfg.GetEnterpriseProjectID(d)
92+
rst := fmt.Sprintf("?from=%v&to=%v", d.Get("from"), d.Get("to"))
93+
94+
if groupBy, ok := d.GetOk("group_by"); ok {
95+
rst += fmt.Sprintf("&group_by=%v", groupBy)
96+
}
97+
98+
if displayOption, ok := d.GetOk("display_option"); ok {
99+
rst += fmt.Sprintf("&display_option=%v", displayOption)
100+
}
101+
102+
if hostId, ok := d.GetOk("hosts"); ok {
103+
rst += fmt.Sprintf("&hosts=%v", hostId)
104+
}
105+
106+
if instanceId, ok := d.GetOk("instances"); ok {
107+
rst += fmt.Sprintf("&instances=%v", instanceId)
108+
}
109+
110+
if epsId != "" {
111+
rst += fmt.Sprintf("&enterprise_project_id=%v", epsId)
112+
}
113+
114+
return rst
115+
}
116+
117+
func dataSourceWafOverviewsBandwidthTimelineRead(_ context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
118+
var (
119+
cfg = meta.(*config.Config)
120+
region = cfg.GetRegion(d)
121+
httpUrl = "v1/{project_id}/waf/overviews/bandwidth/timeline"
122+
)
123+
124+
client, err := cfg.NewServiceClient("waf", region)
125+
if err != nil {
126+
return diag.Errorf("error creating WAF client: %s", err)
127+
}
128+
129+
listPath := client.Endpoint + httpUrl
130+
listPath = strings.ReplaceAll(listPath, "{project_id}", client.ProjectID)
131+
listPath += buildOverviewsBandwidthQueryParams(cfg, d)
132+
133+
listOpt := golangsdk.RequestOpts{
134+
KeepResponseBody: true,
135+
MoreHeaders: map[string]string{
136+
"Content-Type": "application/json;charset=utf8",
137+
},
138+
}
139+
140+
listResp, err := client.Request("GET", listPath, &listOpt)
141+
if err != nil {
142+
return diag.Errorf("error retrieving bandwidth usage statistics: %s", err)
143+
}
144+
145+
listRespBody, err := utils.FlattenResponse(listResp)
146+
if err != nil {
147+
return diag.FromErr(err)
148+
}
149+
150+
listArray, ok := listRespBody.([]interface{})
151+
if !ok {
152+
return diag.Errorf("convert inteface array failed")
153+
}
154+
155+
dataSourceId, err := uuid.GenerateUUID()
156+
if err != nil {
157+
return diag.Errorf("unable to generate ID: %s", err)
158+
}
159+
160+
d.SetId(dataSourceId)
161+
162+
mErr := multierror.Append(nil,
163+
d.Set("region", region),
164+
d.Set("bandwidths", flattenOverviewsBandwidths(listArray)),
165+
)
166+
167+
return diag.FromErr(mErr.ErrorOrNil())
168+
}
169+
170+
func flattenOverviewsBandwidths(rawBandwidths []interface{}) []interface{} {
171+
if len(rawBandwidths) == 0 {
172+
return nil
173+
}
174+
175+
rst := make([]interface{}, 0, len(rawBandwidths))
176+
for _, v := range rawBandwidths {
177+
rst = append(rst, map[string]interface{}{
178+
"key": utils.PathSearch("key", v, nil),
179+
"timeline": flattenOverviewsBandwidthsTimeline(utils.PathSearch("timeline", v, make([]interface{}, 0)).([]interface{})),
180+
})
181+
}
182+
183+
return rst
184+
}
185+
186+
func flattenOverviewsBandwidthsTimeline(rawTimeline []interface{}) []interface{} {
187+
if len(rawTimeline) == 0 {
188+
return nil
189+
}
190+
191+
rst := make([]interface{}, 0, len(rawTimeline))
192+
for _, v := range rawTimeline {
193+
rst = append(rst, map[string]interface{}{
194+
"time": utils.PathSearch("time", v, nil),
195+
"num": utils.PathSearch("num", v, nil),
196+
})
197+
}
198+
199+
return rst
200+
}

0 commit comments

Comments
 (0)