Skip to content

Commit

Permalink
Add Tag Support for aws_waf_rate_based_rule resource (#10479)
Browse files Browse the repository at this point in the history
Output from acceptance testing:

```
--- PASS: TestAccAWSWafRateBasedRule_noPredicates (18.39s)
--- PASS: TestAccAWSWafRateBasedRule_basic (43.32s)
--- PASS: TestAccAWSWafRateBasedRule_disappears (46.17s)
--- PASS: TestAccAWSWafRateBasedRule_changePredicates (69.26s)
--- PASS: TestAccAWSWafRateBasedRule_Tags (75.38s)
--- PASS: TestAccAWSWafRateBasedRule_changeNameForceNew (94.17s)
```
  • Loading branch information
DrFaust92 authored and bflad committed Nov 2, 2019
1 parent dc3fcdc commit 39a53cf
Show file tree
Hide file tree
Showing 5 changed files with 155 additions and 3 deletions.
5 changes: 5 additions & 0 deletions aws/internal/keyvaluetags/generators/listtags/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ var serviceNames = []string{
"storagegateway",
"swf",
"transfer",
"waf",
"workspaces",
}

Expand Down Expand Up @@ -269,6 +270,8 @@ func ServiceListTagsInputIdentifierField(serviceName string) string {
return "Arn"
case "workspaces":
return "ResourceId"
case "waf":
return "ResourceARN"
default:
return "ResourceArn"
}
Expand All @@ -287,6 +290,8 @@ func ServiceListTagsInputResourceTypeField(serviceName string) string {
// ServiceListTagsOutputTagsField determines the service tag field.
func ServiceListTagsOutputTagsField(serviceName string) string {
switch serviceName {
case "waf":
return "TagInfoForResource.TagList"
case "cloudhsmv2":
return "TagList"
case "databasemigrationservice":
Expand Down
18 changes: 18 additions & 0 deletions aws/internal/keyvaluetags/list_tags_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

50 changes: 48 additions & 2 deletions aws/resource_aws_waf_rate_based_rule.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import (
"log"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/arn"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/service/waf"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags"
)

func resourceAwsWafRateBasedRule() *schema.Resource {
Expand Down Expand Up @@ -64,12 +66,18 @@ func resourceAwsWafRateBasedRule() *schema.Resource {
Required: true,
ValidateFunc: validation.IntAtLeast(100),
},
"tags": tagsSchema(),
"arn": {
Type: schema.TypeString,
Computed: true,
},
},
}
}

func resourceAwsWafRateBasedRuleCreate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).wafconn
tags := keyvaluetags.New(d.Get("tags").(map[string]interface{})).IgnoreAws().WafTags()

wr := newWafRetryer(conn)
out, err := wr.RetryWithToken(func(token *string) (interface{}, error) {
Expand All @@ -81,14 +89,28 @@ func resourceAwsWafRateBasedRuleCreate(d *schema.ResourceData, meta interface{})
RateLimit: aws.Int64(int64(d.Get("rate_limit").(int))),
}

if len(tags) > 0 {
params.Tags = tags
}

return conn.CreateRateBasedRule(params)
})
if err != nil {
return err
}
resp := out.(*waf.CreateRateBasedRuleOutput)
d.SetId(*resp.Rule.RuleId)
return resourceAwsWafRateBasedRuleUpdate(d, meta)

newPredicates := d.Get("predicates").(*schema.Set).List()
if len(newPredicates) > 0 {
noPredicates := []interface{}{}
err := updateWafRateBasedRuleResource(*resp.Rule.RuleId, noPredicates, newPredicates, d.Get("rate_limit"), conn)
if err != nil {
return fmt.Errorf("Error Updating WAF Rate Based Rule: %s", err)
}
}

return resourceAwsWafRateBasedRuleRead(d, meta)
}

func resourceAwsWafRateBasedRuleRead(d *schema.ResourceData, meta interface{}) error {
Expand All @@ -100,7 +122,7 @@ func resourceAwsWafRateBasedRuleRead(d *schema.ResourceData, meta interface{}) e

resp, err := conn.GetRateBasedRule(params)
if err != nil {
if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "WAFNonexistentItemException" {
if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == waf.ErrCodeNonexistentItemException {
log.Printf("[WARN] WAF Rate Based Rule (%s) not found, removing from state", d.Id())
d.SetId("")
return nil
Expand All @@ -120,6 +142,22 @@ func resourceAwsWafRateBasedRuleRead(d *schema.ResourceData, meta interface{}) e
predicates = append(predicates, predicate)
}

arn := arn.ARN{
Partition: meta.(*AWSClient).partition,
Service: "waf",
AccountID: meta.(*AWSClient).accountid,
Resource: fmt.Sprintf("ratebasedrule/%s", d.Id()),
}.String()
d.Set("arn", arn)

tagList, err := keyvaluetags.WafListTags(conn, arn)
if err != nil {
return fmt.Errorf("Failed to get WAF Rated Based Rule parameter tags for %s: %s", d.Get("name"), err)
}
if err := d.Set("tags", tagList.IgnoreAws().Map()); err != nil {
return fmt.Errorf("error setting tags: %s", err)
}

d.Set("predicates", predicates)
d.Set("name", resp.Rule.Name)
d.Set("metric_name", resp.Rule.MetricName)
Expand All @@ -143,6 +181,14 @@ func resourceAwsWafRateBasedRuleUpdate(d *schema.ResourceData, meta interface{})
}
}

if d.HasChange("tags") {
o, n := d.GetChange("tags")

if err := keyvaluetags.WafUpdateTags(conn, d.Get("arn").(string), o, n); err != nil {
return fmt.Errorf("error updating tags: %s", err)
}
}

return resourceAwsWafRateBasedRuleRead(d, meta)
}

Expand Down
83 changes: 82 additions & 1 deletion aws/resource_aws_waf_rate_based_rule_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package aws

import (
"fmt"
"regexp"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
Expand All @@ -28,6 +29,7 @@ func TestAccAWSWafRateBasedRule_basic(t *testing.T) {
Config: testAccAWSWafRateBasedRuleConfig(wafRuleName),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSWafRateBasedRuleExists(resourceName, &v),
testAccMatchResourceAttrGlobalARN(resourceName, "arn", "waf", regexp.MustCompile(`ratebasedrule/.+`)),
resource.TestCheckResourceAttr(resourceName, "name", wafRuleName),
resource.TestCheckResourceAttr(resourceName, "predicates.#", "1"),
resource.TestCheckResourceAttr(resourceName, "metric_name", wafRuleName),
Expand Down Expand Up @@ -214,6 +216,54 @@ func TestAccAWSWafRateBasedRule_noPredicates(t *testing.T) {
})
}

func TestAccAWSWafRateBasedRule_Tags(t *testing.T) {
var rule waf.RateBasedRule
ruleName := fmt.Sprintf("wafrule%s", acctest.RandString(5))
resourceName := "aws_waf_rate_based_rule.wafrule"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSWaf(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSWafRateBasedRuleDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSWafRateBasedRuleConfigTags1(ruleName, "key1", "value1"),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckAWSWafRateBasedRuleExists(resourceName, &rule),
testAccMatchResourceAttrGlobalARN(resourceName, "arn", "waf", regexp.MustCompile(`ratebasedrule/.+`)),
resource.TestCheckResourceAttr(resourceName, "name", ruleName),
resource.TestCheckResourceAttr(resourceName, "tags.%", "1"),
resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"),
),
},
{
Config: testAccAWSWafRateBasedRuleConfigTags2(ruleName, "key1", "value1updated", "key2", "value2"),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckAWSWafRateBasedRuleExists(resourceName, &rule),
resource.TestCheckResourceAttr(resourceName, "name", ruleName),
resource.TestCheckResourceAttr(resourceName, "tags.%", "2"),
resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"),
resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"),
),
},
{
Config: testAccAWSWafRateBasedRuleConfigTags1(ruleName, "key2", "value2"),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckAWSWafRateBasedRuleExists(resourceName, &rule),
resource.TestCheckResourceAttr(resourceName, "name", ruleName),
resource.TestCheckResourceAttr(resourceName, "tags.%", "1"),
resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func testAccCheckAWSWafRateBasedRuleDisappears(v *waf.RateBasedRule) resource.TestCheckFunc {
return func(s *terraform.State) error {
conn := testAccProvider.Meta().(*AWSClient).wafconn
Expand Down Expand Up @@ -278,7 +328,7 @@ func testAccCheckAWSWafRateBasedRuleDestroy(s *terraform.State) error {

// Return nil if the Rule is already destroyed
if awsErr, ok := err.(awserr.Error); ok {
if awsErr.Code() == "WAFNonexistentItemException" {
if awsErr.Code() == waf.ErrCodeNonexistentItemException {
return nil
}
}
Expand Down Expand Up @@ -423,3 +473,34 @@ resource "aws_waf_rate_based_rule" "wafrule" {
}
`, name, name)
}

func testAccAWSWafRateBasedRuleConfigTags1(name, tag1Key, tag1Value string) string {
return fmt.Sprintf(`
resource "aws_waf_rate_based_rule" "wafrule" {
name = "%s"
metric_name = "%s"
rate_key = "IP"
rate_limit = 2000
tags = {
%q = %q
}
}
`, name, name, tag1Key, tag1Value)
}

func testAccAWSWafRateBasedRuleConfigTags2(name, tag1Key, tag1Value, tag2Key, tag2Value string) string {
return fmt.Sprintf(`
resource "aws_waf_rate_based_rule" "wafrule" {
name = "%s"
metric_name = "%s"
rate_key = "IP"
rate_limit = 2000
tags = {
%q = %q
%q = %q
}
}
`, name, name, tag1Key, tag1Value, tag2Key, tag2Value)
}
2 changes: 2 additions & 0 deletions website/docs/r/waf_rate_based_rule.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ The following arguments are supported:
* `rate_key` - (Required) Valid value is IP.
* `rate_limit` - (Required) The maximum number of requests, which have an identical value in the field specified by the RateKey, allowed in a five-minute period. Minimum value is 100.
* `predicates` - (Optional) The objects to include in a rule (documented below).
* `tags` - (Optional) Key-value mapping of resource tags

## Nested Blocks

Expand All @@ -69,6 +70,7 @@ See the [WAF Documentation](https://docs.aws.amazon.com/waf/latest/APIReference/
In addition to all arguments above, the following attributes are exported:

* `id` - The ID of the WAF rule.
* `arn` - Amazon Resource Name (ARN)

## Import

Expand Down

0 comments on commit 39a53cf

Please sign in to comment.