github.com/jrperritt/terraform@v0.1.1-0.20170525065507-96f391dafc38/builtin/providers/aws/resource_aws_waf_byte_match_set.go (about)

     1  package aws
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  
     7  	"github.com/aws/aws-sdk-go/aws"
     8  	"github.com/aws/aws-sdk-go/aws/awserr"
     9  	"github.com/aws/aws-sdk-go/service/waf"
    10  	"github.com/hashicorp/errwrap"
    11  	"github.com/hashicorp/terraform/helper/schema"
    12  )
    13  
    14  func resourceAwsWafByteMatchSet() *schema.Resource {
    15  	return &schema.Resource{
    16  		Create: resourceAwsWafByteMatchSetCreate,
    17  		Read:   resourceAwsWafByteMatchSetRead,
    18  		Update: resourceAwsWafByteMatchSetUpdate,
    19  		Delete: resourceAwsWafByteMatchSetDelete,
    20  
    21  		Schema: map[string]*schema.Schema{
    22  			"name": &schema.Schema{
    23  				Type:     schema.TypeString,
    24  				Required: true,
    25  				ForceNew: true,
    26  			},
    27  			"byte_match_tuples": &schema.Schema{
    28  				Type:     schema.TypeSet,
    29  				Optional: true,
    30  				Elem: &schema.Resource{
    31  					Schema: map[string]*schema.Schema{
    32  						"field_to_match": {
    33  							Type:     schema.TypeSet,
    34  							Required: true,
    35  							MaxItems: 1,
    36  							Elem: &schema.Resource{
    37  								Schema: map[string]*schema.Schema{
    38  									"data": {
    39  										Type:     schema.TypeString,
    40  										Optional: true,
    41  									},
    42  									"type": {
    43  										Type:     schema.TypeString,
    44  										Required: true,
    45  									},
    46  								},
    47  							},
    48  						},
    49  						"positional_constraint": &schema.Schema{
    50  							Type:     schema.TypeString,
    51  							Required: true,
    52  						},
    53  						"target_string": &schema.Schema{
    54  							Type:     schema.TypeString,
    55  							Optional: true,
    56  						},
    57  						"text_transformation": &schema.Schema{
    58  							Type:     schema.TypeString,
    59  							Required: true,
    60  						},
    61  					},
    62  				},
    63  			},
    64  		},
    65  	}
    66  }
    67  
    68  func resourceAwsWafByteMatchSetCreate(d *schema.ResourceData, meta interface{}) error {
    69  	conn := meta.(*AWSClient).wafconn
    70  
    71  	log.Printf("[INFO] Creating ByteMatchSet: %s", d.Get("name").(string))
    72  
    73  	wr := newWafRetryer(conn, "global")
    74  	out, err := wr.RetryWithToken(func(token *string) (interface{}, error) {
    75  		params := &waf.CreateByteMatchSetInput{
    76  			ChangeToken: token,
    77  			Name:        aws.String(d.Get("name").(string)),
    78  		}
    79  		return conn.CreateByteMatchSet(params)
    80  	})
    81  	if err != nil {
    82  		return errwrap.Wrapf("[ERROR] Error creating ByteMatchSet: {{err}}", err)
    83  	}
    84  	resp := out.(*waf.CreateByteMatchSetOutput)
    85  
    86  	d.SetId(*resp.ByteMatchSet.ByteMatchSetId)
    87  
    88  	return resourceAwsWafByteMatchSetUpdate(d, meta)
    89  }
    90  
    91  func resourceAwsWafByteMatchSetRead(d *schema.ResourceData, meta interface{}) error {
    92  	conn := meta.(*AWSClient).wafconn
    93  	log.Printf("[INFO] Reading ByteMatchSet: %s", d.Get("name").(string))
    94  	params := &waf.GetByteMatchSetInput{
    95  		ByteMatchSetId: aws.String(d.Id()),
    96  	}
    97  
    98  	resp, err := conn.GetByteMatchSet(params)
    99  	if err != nil {
   100  		if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "WAFNonexistentItemException" {
   101  			log.Printf("[WARN] WAF IPSet (%s) not found, error code (404)", d.Id())
   102  			d.SetId("")
   103  			return nil
   104  		}
   105  
   106  		return err
   107  	}
   108  
   109  	d.Set("name", resp.ByteMatchSet.Name)
   110  	d.Set("byte_match_tuples", flattenWafByteMatchTuples(resp.ByteMatchSet.ByteMatchTuples))
   111  
   112  	return nil
   113  }
   114  
   115  func resourceAwsWafByteMatchSetUpdate(d *schema.ResourceData, meta interface{}) error {
   116  	conn := meta.(*AWSClient).wafconn
   117  
   118  	log.Printf("[INFO] Updating ByteMatchSet: %s", d.Get("name").(string))
   119  
   120  	if d.HasChange("byte_match_tuples") {
   121  		o, n := d.GetChange("byte_match_tuples")
   122  		oldT, newT := o.(*schema.Set).List(), n.(*schema.Set).List()
   123  		err := updateByteMatchSetResource(d.Id(), oldT, newT, conn)
   124  		if err != nil {
   125  			return errwrap.Wrapf("[ERROR] Error updating ByteMatchSet: {{err}}", err)
   126  		}
   127  	}
   128  
   129  	return resourceAwsWafByteMatchSetRead(d, meta)
   130  }
   131  
   132  func resourceAwsWafByteMatchSetDelete(d *schema.ResourceData, meta interface{}) error {
   133  	conn := meta.(*AWSClient).wafconn
   134  
   135  	oldTuples := d.Get("byte_match_tuples").(*schema.Set).List()
   136  	if len(oldTuples) > 0 {
   137  		noTuples := []interface{}{}
   138  		err := updateByteMatchSetResource(d.Id(), oldTuples, noTuples, conn)
   139  		if err != nil {
   140  			return fmt.Errorf("Error updating ByteMatchSet: %s", err)
   141  		}
   142  	}
   143  
   144  	wr := newWafRetryer(conn, "global")
   145  	_, err := wr.RetryWithToken(func(token *string) (interface{}, error) {
   146  		req := &waf.DeleteByteMatchSetInput{
   147  			ChangeToken:    token,
   148  			ByteMatchSetId: aws.String(d.Id()),
   149  		}
   150  		log.Printf("[INFO] Deleting WAF ByteMatchSet: %s", req)
   151  		return conn.DeleteByteMatchSet(req)
   152  	})
   153  	if err != nil {
   154  		return errwrap.Wrapf("[ERROR] Error deleting ByteMatchSet: {{err}}", err)
   155  	}
   156  
   157  	return nil
   158  }
   159  
   160  func updateByteMatchSetResource(id string, oldT, newT []interface{}, conn *waf.WAF) error {
   161  	wr := newWafRetryer(conn, "global")
   162  	_, err := wr.RetryWithToken(func(token *string) (interface{}, error) {
   163  		req := &waf.UpdateByteMatchSetInput{
   164  			ChangeToken:    token,
   165  			ByteMatchSetId: aws.String(id),
   166  			Updates:        diffWafByteMatchSetTuples(oldT, newT),
   167  		}
   168  
   169  		return conn.UpdateByteMatchSet(req)
   170  	})
   171  	if err != nil {
   172  		return errwrap.Wrapf("[ERROR] Error updating ByteMatchSet: {{err}}", err)
   173  	}
   174  
   175  	return nil
   176  }
   177  
   178  func flattenWafByteMatchTuples(bmt []*waf.ByteMatchTuple) []interface{} {
   179  	out := make([]interface{}, len(bmt), len(bmt))
   180  	for i, t := range bmt {
   181  		m := make(map[string]interface{})
   182  
   183  		if t.FieldToMatch != nil {
   184  			m["field_to_match"] = flattenFieldToMatch(t.FieldToMatch)
   185  		}
   186  		m["positional_constraint"] = *t.PositionalConstraint
   187  		m["target_string"] = string(t.TargetString)
   188  		m["text_transformation"] = *t.TextTransformation
   189  
   190  		out[i] = m
   191  	}
   192  	return out
   193  }
   194  
   195  func expandFieldToMatch(d map[string]interface{}) *waf.FieldToMatch {
   196  	return &waf.FieldToMatch{
   197  		Type: aws.String(d["type"].(string)),
   198  		Data: aws.String(d["data"].(string)),
   199  	}
   200  }
   201  
   202  func flattenFieldToMatch(fm *waf.FieldToMatch) []interface{} {
   203  	m := make(map[string]interface{})
   204  	if fm.Data != nil {
   205  		m["data"] = *fm.Data
   206  	}
   207  	if fm.Type != nil {
   208  		m["type"] = *fm.Type
   209  	}
   210  	return []interface{}{m}
   211  }
   212  
   213  func diffWafByteMatchSetTuples(oldT, newT []interface{}) []*waf.ByteMatchSetUpdate {
   214  	updates := make([]*waf.ByteMatchSetUpdate, 0)
   215  
   216  	for _, ot := range oldT {
   217  		tuple := ot.(map[string]interface{})
   218  
   219  		if idx, contains := sliceContainsMap(newT, tuple); contains {
   220  			newT = append(newT[:idx], newT[idx+1:]...)
   221  			continue
   222  		}
   223  
   224  		updates = append(updates, &waf.ByteMatchSetUpdate{
   225  			Action: aws.String(waf.ChangeActionDelete),
   226  			ByteMatchTuple: &waf.ByteMatchTuple{
   227  				FieldToMatch:         expandFieldToMatch(tuple["field_to_match"].(*schema.Set).List()[0].(map[string]interface{})),
   228  				PositionalConstraint: aws.String(tuple["positional_constraint"].(string)),
   229  				TargetString:         []byte(tuple["target_string"].(string)),
   230  				TextTransformation:   aws.String(tuple["text_transformation"].(string)),
   231  			},
   232  		})
   233  	}
   234  
   235  	for _, nt := range newT {
   236  		tuple := nt.(map[string]interface{})
   237  
   238  		updates = append(updates, &waf.ByteMatchSetUpdate{
   239  			Action: aws.String(waf.ChangeActionInsert),
   240  			ByteMatchTuple: &waf.ByteMatchTuple{
   241  				FieldToMatch:         expandFieldToMatch(tuple["field_to_match"].(*schema.Set).List()[0].(map[string]interface{})),
   242  				PositionalConstraint: aws.String(tuple["positional_constraint"].(string)),
   243  				TargetString:         []byte(tuple["target_string"].(string)),
   244  				TextTransformation:   aws.String(tuple["text_transformation"].(string)),
   245  			},
   246  		})
   247  	}
   248  	return updates
   249  }