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

provider/aws: Allow updating tuples in WAF ByteMatchSet + no tuples #14071

Merged
merged 2 commits into from
May 19, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 88 additions & 31 deletions builtin/providers/aws/resource_aws_waf_byte_match_set.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package aws

import (
"fmt"
"log"

"github.com/aws/aws-sdk-go/aws"
Expand Down Expand Up @@ -106,34 +107,47 @@ func resourceAwsWafByteMatchSetRead(d *schema.ResourceData, meta interface{}) er
}

d.Set("name", resp.ByteMatchSet.Name)
d.Set("byte_match_tuples", flattenWafByteMatchTuples(resp.ByteMatchSet.ByteMatchTuples))

return nil
}

func resourceAwsWafByteMatchSetUpdate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).wafconn

log.Printf("[INFO] Updating ByteMatchSet: %s", d.Get("name").(string))
err := updateByteMatchSetResource(d, meta, waf.ChangeActionInsert)
if err != nil {
return errwrap.Wrapf("[ERROR] Error updating ByteMatchSet: {{err}}", err)

if d.HasChange("byte_match_tuples") {
o, n := d.GetChange("byte_match_tuples")
oldT, newT := o.(*schema.Set).List(), n.(*schema.Set).List()
err := updateByteMatchSetResource(d.Id(), oldT, newT, conn)
if err != nil {
return errwrap.Wrapf("[ERROR] Error updating ByteMatchSet: {{err}}", err)
}
}

return resourceAwsWafByteMatchSetRead(d, meta)
}

func resourceAwsWafByteMatchSetDelete(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).wafconn

log.Printf("[INFO] Deleting ByteMatchSet: %s", d.Get("name").(string))
err := updateByteMatchSetResource(d, meta, waf.ChangeActionDelete)
if err != nil {
return errwrap.Wrapf("[ERROR] Error deleting ByteMatchSet: {{err}}", err)
oldTuples := d.Get("byte_match_tuples").(*schema.Set).List()
if len(oldTuples) > 0 {
noTuples := []interface{}{}
err := updateByteMatchSetResource(d.Id(), oldTuples, noTuples, conn)
if err != nil {
return fmt.Errorf("Error updating ByteMatchSet: %s", err)
}
}

wr := newWafRetryer(conn, "global")
_, err = wr.RetryWithToken(func(token *string) (interface{}, error) {
_, err := wr.RetryWithToken(func(token *string) (interface{}, error) {
req := &waf.DeleteByteMatchSetInput{
ChangeToken: token,
ByteMatchSetId: aws.String(d.Id()),
}
log.Printf("[INFO] Deleting WAF ByteMatchSet: %s", req)
return conn.DeleteByteMatchSet(req)
})
if err != nil {
Expand All @@ -143,29 +157,13 @@ func resourceAwsWafByteMatchSetDelete(d *schema.ResourceData, meta interface{})
return nil
}

func updateByteMatchSetResource(d *schema.ResourceData, meta interface{}, ChangeAction string) error {
conn := meta.(*AWSClient).wafconn

func updateByteMatchSetResource(id string, oldT, newT []interface{}, conn *waf.WAF) error {
wr := newWafRetryer(conn, "global")
_, err := wr.RetryWithToken(func(token *string) (interface{}, error) {
req := &waf.UpdateByteMatchSetInput{
ChangeToken: token,
ByteMatchSetId: aws.String(d.Id()),
}

ByteMatchTuples := d.Get("byte_match_tuples").(*schema.Set)
for _, ByteMatchTuple := range ByteMatchTuples.List() {
ByteMatch := ByteMatchTuple.(map[string]interface{})
ByteMatchUpdate := &waf.ByteMatchSetUpdate{
Action: aws.String(ChangeAction),
ByteMatchTuple: &waf.ByteMatchTuple{
FieldToMatch: expandFieldToMatch(ByteMatch["field_to_match"].(*schema.Set).List()[0].(map[string]interface{})),
PositionalConstraint: aws.String(ByteMatch["positional_constraint"].(string)),
TargetString: []byte(ByteMatch["target_string"].(string)),
TextTransformation: aws.String(ByteMatch["text_transformation"].(string)),
},
}
req.Updates = append(req.Updates, ByteMatchUpdate)
ByteMatchSetId: aws.String(id),
Updates: diffWafByteMatchSetTuples(oldT, newT),
}

return conn.UpdateByteMatchSet(req)
Expand All @@ -177,16 +175,75 @@ func updateByteMatchSetResource(d *schema.ResourceData, meta interface{}, Change
return nil
}

func flattenWafByteMatchTuples(bmt []*waf.ByteMatchTuple) []interface{} {
out := make([]interface{}, len(bmt), len(bmt))
for i, t := range bmt {
m := make(map[string]interface{})

if t.FieldToMatch != nil {
m["field_to_match"] = flattenFieldToMatch(t.FieldToMatch)
}
m["positional_constraint"] = *t.PositionalConstraint
m["target_string"] = string(t.TargetString)
m["text_transformation"] = *t.TextTransformation

out[i] = m
}
return out
}

func expandFieldToMatch(d map[string]interface{}) *waf.FieldToMatch {
return &waf.FieldToMatch{
Type: aws.String(d["type"].(string)),
Data: aws.String(d["data"].(string)),
}
}

func flattenFieldToMatch(fm *waf.FieldToMatch) map[string]interface{} {
func flattenFieldToMatch(fm *waf.FieldToMatch) []interface{} {
m := make(map[string]interface{})
m["data"] = *fm.Data
m["type"] = *fm.Type
return m
if fm.Data != nil {
m["data"] = *fm.Data
}
if fm.Type != nil {
m["type"] = *fm.Type
}
return []interface{}{m}
}

func diffWafByteMatchSetTuples(oldT, newT []interface{}) []*waf.ByteMatchSetUpdate {
updates := make([]*waf.ByteMatchSetUpdate, 0)

for _, ot := range oldT {
tuple := ot.(map[string]interface{})

if idx, contains := sliceContainsMap(newT, tuple); contains {
newT = append(newT[:idx], newT[idx+1:]...)
continue
}

updates = append(updates, &waf.ByteMatchSetUpdate{
Action: aws.String(waf.ChangeActionDelete),
ByteMatchTuple: &waf.ByteMatchTuple{
FieldToMatch: expandFieldToMatch(tuple["field_to_match"].(*schema.Set).List()[0].(map[string]interface{})),
PositionalConstraint: aws.String(tuple["positional_constraint"].(string)),
TargetString: []byte(tuple["target_string"].(string)),
TextTransformation: aws.String(tuple["text_transformation"].(string)),
},
})
}

for _, nt := range newT {
tuple := nt.(map[string]interface{})

updates = append(updates, &waf.ByteMatchSetUpdate{
Action: aws.String(waf.ChangeActionInsert),
ByteMatchTuple: &waf.ByteMatchTuple{
FieldToMatch: expandFieldToMatch(tuple["field_to_match"].(*schema.Set).List()[0].(map[string]interface{})),
PositionalConstraint: aws.String(tuple["positional_constraint"].(string)),
TargetString: []byte(tuple["target_string"].(string)),
TextTransformation: aws.String(tuple["text_transformation"].(string)),
},
})
}
return updates
}
127 changes: 123 additions & 4 deletions builtin/providers/aws/resource_aws_waf_byte_match_set_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,20 @@ func TestAccAWSWafByteMatchSet_basic(t *testing.T) {
Config: testAccAWSWafByteMatchSetConfig(byteMatchSet),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSWafByteMatchSetExists("aws_waf_byte_match_set.byte_set", &v),
resource.TestCheckResourceAttr(
"aws_waf_byte_match_set.byte_set", "name", byteMatchSet),
resource.TestCheckResourceAttr(
"aws_waf_byte_match_set.byte_set", "byte_match_tuples.#", "2"),
resource.TestCheckResourceAttr("aws_waf_byte_match_set.byte_set", "name", byteMatchSet),
resource.TestCheckResourceAttr("aws_waf_byte_match_set.byte_set", "byte_match_tuples.#", "2"),
resource.TestCheckResourceAttr("aws_waf_byte_match_set.byte_set", "byte_match_tuples.2174619346.field_to_match.#", "1"),
resource.TestCheckResourceAttr("aws_waf_byte_match_set.byte_set", "byte_match_tuples.2174619346.field_to_match.2991901334.data", "referer"),
resource.TestCheckResourceAttr("aws_waf_byte_match_set.byte_set", "byte_match_tuples.2174619346.field_to_match.2991901334.type", "HEADER"),
resource.TestCheckResourceAttr("aws_waf_byte_match_set.byte_set", "byte_match_tuples.2174619346.positional_constraint", "CONTAINS"),
resource.TestCheckResourceAttr("aws_waf_byte_match_set.byte_set", "byte_match_tuples.2174619346.target_string", "badrefer1"),
resource.TestCheckResourceAttr("aws_waf_byte_match_set.byte_set", "byte_match_tuples.2174619346.text_transformation", "NONE"),
resource.TestCheckResourceAttr("aws_waf_byte_match_set.byte_set", "byte_match_tuples.839525137.field_to_match.#", "1"),
resource.TestCheckResourceAttr("aws_waf_byte_match_set.byte_set", "byte_match_tuples.839525137.field_to_match.2991901334.data", "referer"),
resource.TestCheckResourceAttr("aws_waf_byte_match_set.byte_set", "byte_match_tuples.839525137.field_to_match.2991901334.type", "HEADER"),
resource.TestCheckResourceAttr("aws_waf_byte_match_set.byte_set", "byte_match_tuples.839525137.positional_constraint", "CONTAINS"),
resource.TestCheckResourceAttr("aws_waf_byte_match_set.byte_set", "byte_match_tuples.839525137.target_string", "badrefer2"),
resource.TestCheckResourceAttr("aws_waf_byte_match_set.byte_set", "byte_match_tuples.839525137.text_transformation", "NONE"),
),
},
},
Expand Down Expand Up @@ -71,6 +81,82 @@ func TestAccAWSWafByteMatchSet_changeNameForceNew(t *testing.T) {
})
}

func TestAccAWSWafByteMatchSet_changeTuples(t *testing.T) {
var before, after waf.ByteMatchSet
byteMatchSetName := fmt.Sprintf("byteMatchSet-%s", acctest.RandString(5))

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSWafByteMatchSetDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSWafByteMatchSetConfig(byteMatchSetName),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckAWSWafByteMatchSetExists("aws_waf_byte_match_set.byte_set", &before),
resource.TestCheckResourceAttr("aws_waf_byte_match_set.byte_set", "name", byteMatchSetName),
resource.TestCheckResourceAttr("aws_waf_byte_match_set.byte_set", "byte_match_tuples.#", "2"),
resource.TestCheckResourceAttr("aws_waf_byte_match_set.byte_set", "byte_match_tuples.2174619346.field_to_match.#", "1"),
resource.TestCheckResourceAttr("aws_waf_byte_match_set.byte_set", "byte_match_tuples.2174619346.field_to_match.2991901334.data", "referer"),
resource.TestCheckResourceAttr("aws_waf_byte_match_set.byte_set", "byte_match_tuples.2174619346.field_to_match.2991901334.type", "HEADER"),
resource.TestCheckResourceAttr("aws_waf_byte_match_set.byte_set", "byte_match_tuples.2174619346.positional_constraint", "CONTAINS"),
resource.TestCheckResourceAttr("aws_waf_byte_match_set.byte_set", "byte_match_tuples.2174619346.target_string", "badrefer1"),
resource.TestCheckResourceAttr("aws_waf_byte_match_set.byte_set", "byte_match_tuples.2174619346.text_transformation", "NONE"),
resource.TestCheckResourceAttr("aws_waf_byte_match_set.byte_set", "byte_match_tuples.839525137.field_to_match.#", "1"),
resource.TestCheckResourceAttr("aws_waf_byte_match_set.byte_set", "byte_match_tuples.839525137.field_to_match.2991901334.data", "referer"),
resource.TestCheckResourceAttr("aws_waf_byte_match_set.byte_set", "byte_match_tuples.839525137.field_to_match.2991901334.type", "HEADER"),
resource.TestCheckResourceAttr("aws_waf_byte_match_set.byte_set", "byte_match_tuples.839525137.positional_constraint", "CONTAINS"),
resource.TestCheckResourceAttr("aws_waf_byte_match_set.byte_set", "byte_match_tuples.839525137.target_string", "badrefer2"),
resource.TestCheckResourceAttr("aws_waf_byte_match_set.byte_set", "byte_match_tuples.839525137.text_transformation", "NONE"),
),
},
{
Config: testAccAWSWafByteMatchSetConfig_changeTuples(byteMatchSetName),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckAWSWafByteMatchSetExists("aws_waf_byte_match_set.byte_set", &after),
resource.TestCheckResourceAttr("aws_waf_byte_match_set.byte_set", "name", byteMatchSetName),
resource.TestCheckResourceAttr("aws_waf_byte_match_set.byte_set", "byte_match_tuples.#", "2"),
resource.TestCheckResourceAttr("aws_waf_byte_match_set.byte_set", "byte_match_tuples.2174619346.field_to_match.#", "1"),
resource.TestCheckResourceAttr("aws_waf_byte_match_set.byte_set", "byte_match_tuples.2174619346.field_to_match.2991901334.data", "referer"),
resource.TestCheckResourceAttr("aws_waf_byte_match_set.byte_set", "byte_match_tuples.2174619346.field_to_match.2991901334.type", "HEADER"),
resource.TestCheckResourceAttr("aws_waf_byte_match_set.byte_set", "byte_match_tuples.2174619346.positional_constraint", "CONTAINS"),
resource.TestCheckResourceAttr("aws_waf_byte_match_set.byte_set", "byte_match_tuples.2174619346.target_string", "badrefer1"),
resource.TestCheckResourceAttr("aws_waf_byte_match_set.byte_set", "byte_match_tuples.2174619346.text_transformation", "NONE"),
resource.TestCheckResourceAttr("aws_waf_byte_match_set.byte_set", "byte_match_tuples.4224486115.field_to_match.#", "1"),
resource.TestCheckResourceAttr("aws_waf_byte_match_set.byte_set", "byte_match_tuples.4224486115.field_to_match.4253810390.data", "GET"),
resource.TestCheckResourceAttr("aws_waf_byte_match_set.byte_set", "byte_match_tuples.4224486115.field_to_match.4253810390.type", "METHOD"),
resource.TestCheckResourceAttr("aws_waf_byte_match_set.byte_set", "byte_match_tuples.4224486115.positional_constraint", "CONTAINS_WORD"),
resource.TestCheckResourceAttr("aws_waf_byte_match_set.byte_set", "byte_match_tuples.4224486115.target_string", "blah"),
resource.TestCheckResourceAttr("aws_waf_byte_match_set.byte_set", "byte_match_tuples.4224486115.text_transformation", "URL_DECODE"),
),
},
},
})
}

func TestAccAWSWafByteMatchSet_noTuples(t *testing.T) {
var byteSet waf.ByteMatchSet
byteMatchSetName := fmt.Sprintf("byteMatchSet-%s", acctest.RandString(5))

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSWafByteMatchSetDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSWafByteMatchSetConfig_noTuples(byteMatchSetName),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckAWSWafByteMatchSetExists("aws_waf_byte_match_set.byte_set", &byteSet),
resource.TestCheckResourceAttr(
"aws_waf_byte_match_set.byte_set", "name", byteMatchSetName),
resource.TestCheckResourceAttr(
"aws_waf_byte_match_set.byte_set", "byte_match_tuples.#", "0"),
),
},
},
})
}

func TestAccAWSWafByteMatchSet_disappears(t *testing.T) {
var v waf.ByteMatchSet
byteMatchSet := fmt.Sprintf("byteMatchSet-%s", acctest.RandString(5))
Expand Down Expand Up @@ -248,3 +334,36 @@ resource "aws_waf_byte_match_set" "byte_set" {
}
}`, name)
}

func testAccAWSWafByteMatchSetConfig_changeTuples(name string) string {
return fmt.Sprintf(`
resource "aws_waf_byte_match_set" "byte_set" {
name = "%s"
byte_match_tuples {
text_transformation = "NONE"
target_string = "badrefer1"
positional_constraint = "CONTAINS"
field_to_match {
type = "HEADER"
data = "referer"
}
}

byte_match_tuples {
text_transformation = "URL_DECODE"
target_string = "blah"
positional_constraint = "CONTAINS_WORD"
field_to_match {
type = "METHOD"
data = "GET"
}
}
}`, name)
}

func testAccAWSWafByteMatchSetConfig_noTuples(name string) string {
return fmt.Sprintf(`
resource "aws_waf_byte_match_set" "byte_set" {
name = "%s"
}`, name)
}