terraform/builtin/providers/aws/resource_aws_wafregional_by...

267 lines
7.5 KiB
Go

package aws
import (
"log"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/service/waf"
"github.com/aws/aws-sdk-go/service/wafregional"
"github.com/hashicorp/errwrap"
"github.com/hashicorp/terraform/helper/schema"
)
func resourceAwsWafRegionalByteMatchSet() *schema.Resource {
return &schema.Resource{
Create: resourceAwsWafRegionalByteMatchSetCreate,
Read: resourceAwsWafRegionalByteMatchSetRead,
Update: resourceAwsWafRegionalByteMatchSetUpdate,
Delete: resourceAwsWafRegionalByteMatchSetDelete,
Schema: map[string]*schema.Schema{
"name": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"byte_match_tuple": &schema.Schema{
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"field_to_match": {
Type: schema.TypeSet,
Required: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"data": {
Type: schema.TypeString,
Optional: true,
},
"type": {
Type: schema.TypeString,
Required: true,
},
},
},
},
"positional_constraint": &schema.Schema{
Type: schema.TypeString,
Required: true,
},
"target_string": &schema.Schema{
Type: schema.TypeString,
Optional: true,
},
"text_transformation": &schema.Schema{
Type: schema.TypeString,
Required: true,
},
},
},
},
},
}
}
func resourceAwsWafRegionalByteMatchSetCreate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).wafregionalconn
region := meta.(*AWSClient).region
log.Printf("[INFO] Creating ByteMatchSet: %s", d.Get("name").(string))
wr := newWafRegionalRetryer(conn, region)
out, err := wr.RetryWithToken(func(token *string) (interface{}, error) {
params := &waf.CreateByteMatchSetInput{
ChangeToken: token,
Name: aws.String(d.Get("name").(string)),
}
return conn.CreateByteMatchSet(params)
})
if err != nil {
return errwrap.Wrapf("[ERROR] Error creating ByteMatchSet: {{err}}", err)
}
resp := out.(*waf.CreateByteMatchSetOutput)
d.SetId(*resp.ByteMatchSet.ByteMatchSetId)
return resourceAwsWafRegionalByteMatchSetUpdate(d, meta)
}
func resourceAwsWafRegionalByteMatchSetRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).wafregionalconn
log.Printf("[INFO] Reading ByteMatchSet: %s", d.Get("name").(string))
params := &waf.GetByteMatchSetInput{
ByteMatchSetId: aws.String(d.Id()),
}
resp, err := conn.GetByteMatchSet(params)
if err != nil {
if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "WAFNonexistentItemException" {
log.Printf("[WARN] WAF IPSet (%s) not found, error code (404)", d.Id())
d.SetId("")
return nil
}
return err
}
d.Set("byte_match_tuple", flattenWafByteMatchTuplesWR(resp.ByteMatchSet.ByteMatchTuples))
d.Set("name", resp.ByteMatchSet.Name)
return nil
}
func flattenWafByteMatchTuplesWR(in []*waf.ByteMatchTuple) []interface{} {
tuples := make([]interface{}, len(in), len(in))
for i, tuple := range in {
field_to_match := tuple.FieldToMatch
m := map[string]interface{}{
"type": *field_to_match.Type,
}
if field_to_match.Data == nil {
m["data"] = ""
} else {
m["data"] = *field_to_match.Data
}
var ms []map[string]interface{}
ms = append(ms, m)
tuple := map[string]interface{}{
"field_to_match": ms,
"positional_constraint": *tuple.PositionalConstraint,
"target_string": tuple.TargetString,
"text_transformation": *tuple.TextTransformation,
}
tuples[i] = tuple
}
return tuples
}
func resourceAwsWafRegionalByteMatchSetUpdate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).wafregionalconn
region := meta.(*AWSClient).region
log.Printf("[INFO] Updating ByteMatchSet: %s", d.Get("name").(string))
if d.HasChange("byte_match_tuple") {
o, n := d.GetChange("byte_match_tuple")
oldT, newT := o.(*schema.Set).List(), n.(*schema.Set).List()
err := updateByteMatchSetResourceWR(d, oldT, newT, conn, region)
if err != nil {
return errwrap.Wrapf("[ERROR] Error updating ByteMatchSet: {{err}}", err)
}
}
return resourceAwsWafRegionalByteMatchSetRead(d, meta)
}
func resourceAwsWafRegionalByteMatchSetDelete(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).wafregionalconn
region := meta.(*AWSClient).region
log.Printf("[INFO] Deleting ByteMatchSet: %s", d.Get("name").(string))
oldT := d.Get("byte_match_tuple").(*schema.Set).List()
if len(oldT) > 0 {
var newT []interface{}
err := updateByteMatchSetResourceWR(d, oldT, newT, conn, region)
if err != nil {
return errwrap.Wrapf("[ERROR] Error deleting ByteMatchSet: {{err}}", err)
}
}
wr := newWafRegionalRetryer(conn, region)
_, err := wr.RetryWithToken(func(token *string) (interface{}, error) {
req := &waf.DeleteByteMatchSetInput{
ChangeToken: token,
ByteMatchSetId: aws.String(d.Id()),
}
return conn.DeleteByteMatchSet(req)
})
if err != nil {
return errwrap.Wrapf("[ERROR] Error deleting ByteMatchSet: {{err}}", err)
}
return nil
}
func updateByteMatchSetResourceWR(d *schema.ResourceData, oldT, newT []interface{}, conn *wafregional.WAFRegional, region string) error {
wr := newWafRegionalRetryer(conn, region)
_, err := wr.RetryWithToken(func(token *string) (interface{}, error) {
req := &waf.UpdateByteMatchSetInput{
ChangeToken: token,
ByteMatchSetId: aws.String(d.Id()),
Updates: diffByteMatchSetTuple(oldT, newT),
}
return conn.UpdateByteMatchSet(req)
})
if err != nil {
return errwrap.Wrapf("[ERROR] Error updating ByteMatchSet: {{err}}", err)
}
return nil
}
func expandFieldToMatchWR(d map[string]interface{}) *waf.FieldToMatch {
return &waf.FieldToMatch{
Type: aws.String(d["type"].(string)),
Data: aws.String(d["data"].(string)),
}
}
func flattenFieldToMatchWR(fm *waf.FieldToMatch) map[string]interface{} {
m := make(map[string]interface{})
m["data"] = *fm.Data
m["type"] = *fm.Type
return m
}
func diffByteMatchSetTuple(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
}