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

* provider/aws: Allow updating tuples in WAF ByteMatchSet

* provider/aws: Allow WAF ByteMatchSet with no tuples
This commit is contained in:
Radek Simko 2017-05-19 09:13:58 +02:00 committed by GitHub
parent fcdf494cff
commit afe45b62df
2 changed files with 211 additions and 35 deletions

View File

@ -1,6 +1,7 @@
package aws
import (
"fmt"
"log"
"github.com/aws/aws-sdk-go/aws"
@ -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 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)
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 errwrap.Wrapf("[ERROR] Error deleting ByteMatchSet: {{err}}", err)
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 {
@ -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)
@ -177,6 +175,23 @@ 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)),
@ -184,9 +199,51 @@ func expandFieldToMatch(d map[string]interface{}) *waf.FieldToMatch {
}
}
func flattenFieldToMatch(fm *waf.FieldToMatch) map[string]interface{} {
func flattenFieldToMatch(fm *waf.FieldToMatch) []interface{} {
m := make(map[string]interface{})
if fm.Data != nil {
m["data"] = *fm.Data
}
if fm.Type != nil {
m["type"] = *fm.Type
return m
}
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
}

View File

@ -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"),
),
},
},
@ -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))
@ -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)
}