diff --git a/builtin/providers/aws/resource_aws_waf_size_constraint_set.go b/builtin/providers/aws/resource_aws_waf_size_constraint_set.go index db9d5c516..5e9f46dd4 100644 --- a/builtin/providers/aws/resource_aws_waf_size_constraint_set.go +++ b/builtin/providers/aws/resource_aws_waf_size_constraint_set.go @@ -25,7 +25,7 @@ func resourceAwsWafSizeConstraintSet() *schema.Resource { }, "size_constraints": &schema.Schema{ Type: schema.TypeSet, - Required: true, + Optional: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "field_to_match": { @@ -107,30 +107,42 @@ func resourceAwsWafSizeConstraintSetRead(d *schema.ResourceData, meta interface{ } d.Set("name", resp.SizeConstraintSet.Name) + d.Set("size_constraints", flattenWafSizeConstraints(resp.SizeConstraintSet.SizeConstraints)) return nil } func resourceAwsWafSizeConstraintSetUpdate(d *schema.ResourceData, meta interface{}) error { - log.Printf("[INFO] Updating SizeConstraintSet: %s", d.Get("name").(string)) - err := updateSizeConstraintSetResource(d, meta, waf.ChangeActionInsert) - if err != nil { - return errwrap.Wrapf("[ERROR] Error updating SizeConstraintSet: {{err}}", err) + conn := meta.(*AWSClient).wafconn + + if d.HasChange("size_constraints") { + o, n := d.GetChange("size_constraints") + oldS, newS := o.(*schema.Set).List(), n.(*schema.Set).List() + + err := updateSizeConstraintSetResource(d.Id(), oldS, newS, conn) + if err != nil { + return errwrap.Wrapf("[ERROR] Error updating SizeConstraintSet: {{err}}", err) + } } + return resourceAwsWafSizeConstraintSetRead(d, meta) } func resourceAwsWafSizeConstraintSetDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).wafconn - log.Printf("[INFO] Deleting SizeConstraintSet: %s", d.Get("name").(string)) - err := updateSizeConstraintSetResource(d, meta, waf.ChangeActionDelete) - if err != nil { - return errwrap.Wrapf("[ERROR] Error deleting SizeConstraintSet: {{err}}", err) + oldConstraints := d.Get("size_constraints").(*schema.Set).List() + + if len(oldConstraints) > 0 { + noConstraints := []interface{}{} + err := updateSizeConstraintSetResource(d.Id(), oldConstraints, noConstraints, conn) + if err != nil { + return errwrap.Wrapf("[ERROR] Error deleting SizeConstraintSet: {{err}}", err) + } } wr := newWafRetryer(conn, "global") - _, err = wr.RetryWithToken(func(token *string) (interface{}, error) { + _, err := wr.RetryWithToken(func(token *string) (interface{}, error) { req := &waf.DeleteSizeConstraintSetInput{ ChangeToken: token, SizeConstraintSetId: aws.String(d.Id()), @@ -144,31 +156,16 @@ func resourceAwsWafSizeConstraintSetDelete(d *schema.ResourceData, meta interfac return nil } -func updateSizeConstraintSetResource(d *schema.ResourceData, meta interface{}, ChangeAction string) error { - conn := meta.(*AWSClient).wafconn - +func updateSizeConstraintSetResource(id string, oldS, newS []interface{}, conn *waf.WAF) error { wr := newWafRetryer(conn, "global") _, err := wr.RetryWithToken(func(token *string) (interface{}, error) { req := &waf.UpdateSizeConstraintSetInput{ ChangeToken: token, - SizeConstraintSetId: aws.String(d.Id()), - } - - sizeConstraints := d.Get("size_constraints").(*schema.Set) - for _, sizeConstraint := range sizeConstraints.List() { - sc := sizeConstraint.(map[string]interface{}) - sizeConstraintUpdate := &waf.SizeConstraintSetUpdate{ - Action: aws.String(ChangeAction), - SizeConstraint: &waf.SizeConstraint{ - FieldToMatch: expandFieldToMatch(sc["field_to_match"].(*schema.Set).List()[0].(map[string]interface{})), - ComparisonOperator: aws.String(sc["comparison_operator"].(string)), - Size: aws.Int64(int64(sc["size"].(int))), - TextTransformation: aws.String(sc["text_transformation"].(string)), - }, - } - req.Updates = append(req.Updates, sizeConstraintUpdate) + SizeConstraintSetId: aws.String(id), + Updates: diffWafSizeConstraints(oldS, newS), } + log.Printf("[INFO] Updating WAF Size Constraint constraints: %s", req) return conn.UpdateSizeConstraintSet(req) }) if err != nil { @@ -177,3 +174,56 @@ func updateSizeConstraintSetResource(d *schema.ResourceData, meta interface{}, C return nil } + +func flattenWafSizeConstraints(sc []*waf.SizeConstraint) []interface{} { + out := make([]interface{}, len(sc), len(sc)) + for i, c := range sc { + m := make(map[string]interface{}) + m["comparison_operator"] = *c.ComparisonOperator + if c.FieldToMatch != nil { + m["field_to_match"] = flattenFieldToMatch(c.FieldToMatch) + } + m["size"] = *c.Size + m["text_transformation"] = *c.TextTransformation + out[i] = m + } + return out +} + +func diffWafSizeConstraints(oldS, newS []interface{}) []*waf.SizeConstraintSetUpdate { + updates := make([]*waf.SizeConstraintSetUpdate, 0) + + for _, os := range oldS { + constraint := os.(map[string]interface{}) + + if idx, contains := sliceContainsMap(newS, constraint); contains { + newS = append(newS[:idx], newS[idx+1:]...) + continue + } + + updates = append(updates, &waf.SizeConstraintSetUpdate{ + Action: aws.String(waf.ChangeActionDelete), + SizeConstraint: &waf.SizeConstraint{ + FieldToMatch: expandFieldToMatch(constraint["field_to_match"].(*schema.Set).List()[0].(map[string]interface{})), + ComparisonOperator: aws.String(constraint["comparison_operator"].(string)), + Size: aws.Int64(int64(constraint["size"].(int))), + TextTransformation: aws.String(constraint["text_transformation"].(string)), + }, + }) + } + + for _, ns := range newS { + constraint := ns.(map[string]interface{}) + + updates = append(updates, &waf.SizeConstraintSetUpdate{ + Action: aws.String(waf.ChangeActionInsert), + SizeConstraint: &waf.SizeConstraint{ + FieldToMatch: expandFieldToMatch(constraint["field_to_match"].(*schema.Set).List()[0].(map[string]interface{})), + ComparisonOperator: aws.String(constraint["comparison_operator"].(string)), + Size: aws.Int64(int64(constraint["size"].(int))), + TextTransformation: aws.String(constraint["text_transformation"].(string)), + }, + }) + } + return updates +} diff --git a/builtin/providers/aws/resource_aws_waf_size_constraint_set_test.go b/builtin/providers/aws/resource_aws_waf_size_constraint_set_test.go index a6bd5156e..dcfac5d20 100644 --- a/builtin/providers/aws/resource_aws_waf_size_constraint_set_test.go +++ b/builtin/providers/aws/resource_aws_waf_size_constraint_set_test.go @@ -31,6 +31,18 @@ func TestAccAWSWafSizeConstraintSet_basic(t *testing.T) { "aws_waf_size_constraint_set.size_constraint_set", "name", sizeConstraintSet), resource.TestCheckResourceAttr( "aws_waf_size_constraint_set.size_constraint_set", "size_constraints.#", "1"), + resource.TestCheckResourceAttr( + "aws_waf_size_constraint_set.size_constraint_set", "size_constraints.2029852522.comparison_operator", "EQ"), + resource.TestCheckResourceAttr( + "aws_waf_size_constraint_set.size_constraint_set", "size_constraints.2029852522.field_to_match.#", "1"), + resource.TestCheckResourceAttr( + "aws_waf_size_constraint_set.size_constraint_set", "size_constraints.2029852522.field_to_match.281401076.data", ""), + resource.TestCheckResourceAttr( + "aws_waf_size_constraint_set.size_constraint_set", "size_constraints.2029852522.field_to_match.281401076.type", "BODY"), + resource.TestCheckResourceAttr( + "aws_waf_size_constraint_set.size_constraint_set", "size_constraints.2029852522.size", "4096"), + resource.TestCheckResourceAttr( + "aws_waf_size_constraint_set.size_constraint_set", "size_constraints.2029852522.text_transformation", "NONE"), ), }, }, @@ -92,6 +104,86 @@ func TestAccAWSWafSizeConstraintSet_disappears(t *testing.T) { }) } +func TestAccAWSWafSizeConstraintSet_changeConstraints(t *testing.T) { + var before, after waf.SizeConstraintSet + setName := fmt.Sprintf("sizeConstraintSet-%s", acctest.RandString(5)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSWafSizeConstraintSetDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSWafSizeConstraintSetConfig(setName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSWafSizeConstraintSetExists("aws_waf_size_constraint_set.size_constraint_set", &before), + resource.TestCheckResourceAttr( + "aws_waf_size_constraint_set.size_constraint_set", "name", setName), + resource.TestCheckResourceAttr( + "aws_waf_size_constraint_set.size_constraint_set", "size_constraints.#", "1"), + resource.TestCheckResourceAttr( + "aws_waf_size_constraint_set.size_constraint_set", "size_constraints.2029852522.comparison_operator", "EQ"), + resource.TestCheckResourceAttr( + "aws_waf_size_constraint_set.size_constraint_set", "size_constraints.2029852522.field_to_match.#", "1"), + resource.TestCheckResourceAttr( + "aws_waf_size_constraint_set.size_constraint_set", "size_constraints.2029852522.field_to_match.281401076.data", ""), + resource.TestCheckResourceAttr( + "aws_waf_size_constraint_set.size_constraint_set", "size_constraints.2029852522.field_to_match.281401076.type", "BODY"), + resource.TestCheckResourceAttr( + "aws_waf_size_constraint_set.size_constraint_set", "size_constraints.2029852522.size", "4096"), + resource.TestCheckResourceAttr( + "aws_waf_size_constraint_set.size_constraint_set", "size_constraints.2029852522.text_transformation", "NONE"), + ), + }, + { + Config: testAccAWSWafSizeConstraintSetConfig_changeConstraints(setName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSWafSizeConstraintSetExists("aws_waf_size_constraint_set.size_constraint_set", &after), + resource.TestCheckResourceAttr( + "aws_waf_size_constraint_set.size_constraint_set", "name", setName), + resource.TestCheckResourceAttr( + "aws_waf_size_constraint_set.size_constraint_set", "size_constraints.#", "1"), + resource.TestCheckResourceAttr( + "aws_waf_size_constraint_set.size_constraint_set", "size_constraints.3222308386.comparison_operator", "GE"), + resource.TestCheckResourceAttr( + "aws_waf_size_constraint_set.size_constraint_set", "size_constraints.3222308386.field_to_match.#", "1"), + resource.TestCheckResourceAttr( + "aws_waf_size_constraint_set.size_constraint_set", "size_constraints.3222308386.field_to_match.281401076.data", ""), + resource.TestCheckResourceAttr( + "aws_waf_size_constraint_set.size_constraint_set", "size_constraints.3222308386.field_to_match.281401076.type", "BODY"), + resource.TestCheckResourceAttr( + "aws_waf_size_constraint_set.size_constraint_set", "size_constraints.3222308386.size", "1024"), + resource.TestCheckResourceAttr( + "aws_waf_size_constraint_set.size_constraint_set", "size_constraints.3222308386.text_transformation", "NONE"), + ), + }, + }, + }) +} + +func TestAccAWSWafSizeConstraintSet_noConstraints(t *testing.T) { + var ipset waf.SizeConstraintSet + setName := fmt.Sprintf("sizeConstraintSet-%s", acctest.RandString(5)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSWafSizeConstraintSetDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSWafSizeConstraintSetConfig_noConstraints(setName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSWafSizeConstraintSetExists("aws_waf_size_constraint_set.size_constraint_set", &ipset), + resource.TestCheckResourceAttr( + "aws_waf_size_constraint_set.size_constraint_set", "name", setName), + resource.TestCheckResourceAttr( + "aws_waf_size_constraint_set.size_constraint_set", "size_constraints.#", "0"), + ), + }, + }, + }) +} + func testAccCheckAWSWafSizeConstraintSetDisappears(v *waf.SizeConstraintSet) resource.TestCheckFunc { return func(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).wafconn @@ -224,3 +316,25 @@ resource "aws_waf_size_constraint_set" "size_constraint_set" { } }`, name) } + +func testAccAWSWafSizeConstraintSetConfig_changeConstraints(name string) string { + return fmt.Sprintf(` +resource "aws_waf_size_constraint_set" "size_constraint_set" { + name = "%s" + size_constraints { + text_transformation = "NONE" + comparison_operator = "GE" + size = "1024" + field_to_match { + type = "BODY" + } + } +}`, name) +} + +func testAccAWSWafSizeConstraintSetConfig_noConstraints(name string) string { + return fmt.Sprintf(` +resource "aws_waf_size_constraint_set" "size_constraint_set" { + name = "%s" +}`, name) +}