Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Tag Support for aws_waf_rate_based_rule resource #10479

Merged
merged 9 commits into from
Nov 2, 2019
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 @@ -79,6 +79,7 @@ var serviceNames = []string{
"storagegateway",
"swf",
"transfer",
"waf",
"workspaces",
}

Expand Down Expand Up @@ -268,6 +269,8 @@ func ServiceListTagsInputIdentifierField(serviceName string) string {
return "Arn"
case "workspaces":
return "ResourceId"
case "waf":
return "ResourceARN"
default:
return "ResourceArn"
}
Expand All @@ -286,6 +289,8 @@ func ServiceListTagsInputResourceTypeField(serviceName string) string {
// ServiceListTagsOutputTagsField determines the service tag field.
func ServiceListTagsOutputTagsField(serviceName string) string {
switch serviceName {
case "waf":
return "TagInfoForResource.TagList"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice 👍

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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❤️


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/.+`)),
DrFaust92 marked this conversation as resolved.
Show resolved Hide resolved
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