github.com/minamijoyo/terraform@v0.7.8-0.20161029001309-18b3736ba44b/builtin/providers/aws/resource_aws_ses_receipt_rule.go (about)

     1  package aws
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"log"
     7  	"sort"
     8  
     9  	"github.com/aws/aws-sdk-go/aws"
    10  	"github.com/aws/aws-sdk-go/aws/awserr"
    11  	"github.com/aws/aws-sdk-go/service/ses"
    12  	"github.com/hashicorp/terraform/helper/hashcode"
    13  	"github.com/hashicorp/terraform/helper/schema"
    14  )
    15  
    16  func resourceAwsSesReceiptRule() *schema.Resource {
    17  	return &schema.Resource{
    18  		Create: resourceAwsSesReceiptRuleCreate,
    19  		Update: resourceAwsSesReceiptRuleUpdate,
    20  		Read:   resourceAwsSesReceiptRuleRead,
    21  		Delete: resourceAwsSesReceiptRuleDelete,
    22  
    23  		Schema: map[string]*schema.Schema{
    24  			"name": &schema.Schema{
    25  				Type:     schema.TypeString,
    26  				Required: true,
    27  				ForceNew: true,
    28  			},
    29  
    30  			"rule_set_name": &schema.Schema{
    31  				Type:     schema.TypeString,
    32  				Required: true,
    33  				ForceNew: true,
    34  			},
    35  
    36  			"after": &schema.Schema{
    37  				Type:     schema.TypeString,
    38  				Optional: true,
    39  			},
    40  
    41  			"enabled": &schema.Schema{
    42  				Type:     schema.TypeBool,
    43  				Optional: true,
    44  				Computed: true,
    45  			},
    46  
    47  			"recipients": &schema.Schema{
    48  				Type:     schema.TypeSet,
    49  				Elem:     &schema.Schema{Type: schema.TypeString},
    50  				Optional: true,
    51  				Set:      schema.HashString,
    52  			},
    53  
    54  			"scan_enabled": &schema.Schema{
    55  				Type:     schema.TypeBool,
    56  				Optional: true,
    57  				Computed: true,
    58  			},
    59  
    60  			"tls_policy": &schema.Schema{
    61  				Type:     schema.TypeString,
    62  				Optional: true,
    63  				Computed: true,
    64  			},
    65  
    66  			"add_header_action": &schema.Schema{
    67  				Type:     schema.TypeSet,
    68  				Optional: true,
    69  				Elem: &schema.Resource{
    70  					Schema: map[string]*schema.Schema{
    71  						"header_name": &schema.Schema{
    72  							Type:     schema.TypeString,
    73  							Required: true,
    74  						},
    75  
    76  						"header_value": &schema.Schema{
    77  							Type:     schema.TypeString,
    78  							Required: true,
    79  						},
    80  
    81  						"position": &schema.Schema{
    82  							Type:     schema.TypeInt,
    83  							Required: true,
    84  						},
    85  					},
    86  				},
    87  				Set: func(v interface{}) int {
    88  					var buf bytes.Buffer
    89  					m := v.(map[string]interface{})
    90  					buf.WriteString(fmt.Sprintf("%s-", m["header_name"].(string)))
    91  					buf.WriteString(fmt.Sprintf("%s-", m["header_value"].(string)))
    92  					buf.WriteString(fmt.Sprintf("%d-", m["position"].(int)))
    93  
    94  					return hashcode.String(buf.String())
    95  				},
    96  			},
    97  
    98  			"bounce_action": &schema.Schema{
    99  				Type:     schema.TypeSet,
   100  				Optional: true,
   101  				Elem: &schema.Resource{
   102  					Schema: map[string]*schema.Schema{
   103  						"message": &schema.Schema{
   104  							Type:     schema.TypeString,
   105  							Required: true,
   106  						},
   107  
   108  						"sender": &schema.Schema{
   109  							Type:     schema.TypeString,
   110  							Required: true,
   111  						},
   112  
   113  						"smtp_reply_code": &schema.Schema{
   114  							Type:     schema.TypeString,
   115  							Required: true,
   116  						},
   117  
   118  						"status_code": &schema.Schema{
   119  							Type:     schema.TypeString,
   120  							Optional: true,
   121  						},
   122  
   123  						"topic_arn": &schema.Schema{
   124  							Type:     schema.TypeString,
   125  							Optional: true,
   126  						},
   127  
   128  						"position": &schema.Schema{
   129  							Type:     schema.TypeInt,
   130  							Required: true,
   131  						},
   132  					},
   133  				},
   134  				Set: func(v interface{}) int {
   135  					var buf bytes.Buffer
   136  					m := v.(map[string]interface{})
   137  					buf.WriteString(fmt.Sprintf("%s-", m["message"].(string)))
   138  					buf.WriteString(fmt.Sprintf("%s-", m["sender"].(string)))
   139  					buf.WriteString(fmt.Sprintf("%s-", m["smtp_reply_code"].(string)))
   140  
   141  					if _, ok := m["status_code"]; ok {
   142  						buf.WriteString(fmt.Sprintf("%s-", m["status_code"].(string)))
   143  					}
   144  
   145  					if _, ok := m["topic_arn"]; ok {
   146  						buf.WriteString(fmt.Sprintf("%s-", m["topic_arn"].(string)))
   147  					}
   148  
   149  					buf.WriteString(fmt.Sprintf("%d-", m["position"].(int)))
   150  
   151  					return hashcode.String(buf.String())
   152  				},
   153  			},
   154  
   155  			"lambda_action": &schema.Schema{
   156  				Type:     schema.TypeSet,
   157  				Optional: true,
   158  				Elem: &schema.Resource{
   159  					Schema: map[string]*schema.Schema{
   160  						"function_arn": &schema.Schema{
   161  							Type:     schema.TypeString,
   162  							Required: true,
   163  						},
   164  
   165  						"invocation_type": &schema.Schema{
   166  							Type:     schema.TypeString,
   167  							Optional: true,
   168  							Computed: true,
   169  						},
   170  
   171  						"topic_arn": &schema.Schema{
   172  							Type:     schema.TypeString,
   173  							Optional: true,
   174  						},
   175  
   176  						"position": &schema.Schema{
   177  							Type:     schema.TypeInt,
   178  							Required: true,
   179  						},
   180  					},
   181  				},
   182  				Set: func(v interface{}) int {
   183  					var buf bytes.Buffer
   184  					m := v.(map[string]interface{})
   185  					buf.WriteString(fmt.Sprintf("%s-", m["function_arn"].(string)))
   186  
   187  					if _, ok := m["invocation_type"]; ok {
   188  						buf.WriteString(fmt.Sprintf("%s-", m["invocation_type"].(string)))
   189  					}
   190  
   191  					if _, ok := m["topic_arn"]; ok {
   192  						buf.WriteString(fmt.Sprintf("%s-", m["topic_arn"].(string)))
   193  					}
   194  
   195  					buf.WriteString(fmt.Sprintf("%d-", m["position"].(int)))
   196  
   197  					return hashcode.String(buf.String())
   198  				},
   199  			},
   200  
   201  			"s3_action": &schema.Schema{
   202  				Type:     schema.TypeSet,
   203  				Optional: true,
   204  				Elem: &schema.Resource{
   205  					Schema: map[string]*schema.Schema{
   206  						"bucket_name": &schema.Schema{
   207  							Type:     schema.TypeString,
   208  							Required: true,
   209  						},
   210  
   211  						"kms_key_arn": &schema.Schema{
   212  							Type:     schema.TypeString,
   213  							Optional: true,
   214  						},
   215  
   216  						"object_key_prefix": &schema.Schema{
   217  							Type:     schema.TypeString,
   218  							Optional: true,
   219  						},
   220  
   221  						"topic_arn": &schema.Schema{
   222  							Type:     schema.TypeString,
   223  							Optional: true,
   224  						},
   225  
   226  						"position": &schema.Schema{
   227  							Type:     schema.TypeInt,
   228  							Required: true,
   229  						},
   230  					},
   231  				},
   232  				Set: func(v interface{}) int {
   233  					var buf bytes.Buffer
   234  					m := v.(map[string]interface{})
   235  					buf.WriteString(fmt.Sprintf("%s-", m["bucket_name"].(string)))
   236  
   237  					if _, ok := m["kms_key_arn"]; ok {
   238  						buf.WriteString(fmt.Sprintf("%s-", m["kms_key_arn"].(string)))
   239  					}
   240  
   241  					if _, ok := m["object_key_prefix"]; ok {
   242  						buf.WriteString(fmt.Sprintf("%s-", m["object_key_prefix"].(string)))
   243  					}
   244  
   245  					if _, ok := m["topic_arn"]; ok {
   246  						buf.WriteString(fmt.Sprintf("%s-", m["topic_arn"].(string)))
   247  					}
   248  
   249  					buf.WriteString(fmt.Sprintf("%d-", m["position"].(int)))
   250  
   251  					return hashcode.String(buf.String())
   252  				},
   253  			},
   254  
   255  			"sns_action": &schema.Schema{
   256  				Type:     schema.TypeSet,
   257  				Optional: true,
   258  				Elem: &schema.Resource{
   259  					Schema: map[string]*schema.Schema{
   260  						"topic_arn": &schema.Schema{
   261  							Type:     schema.TypeString,
   262  							Required: true,
   263  						},
   264  
   265  						"position": &schema.Schema{
   266  							Type:     schema.TypeInt,
   267  							Required: true,
   268  						},
   269  					},
   270  				},
   271  				Set: func(v interface{}) int {
   272  					var buf bytes.Buffer
   273  					m := v.(map[string]interface{})
   274  					buf.WriteString(fmt.Sprintf("%s-", m["topic_arn"].(string)))
   275  					buf.WriteString(fmt.Sprintf("%d-", m["position"].(int)))
   276  
   277  					return hashcode.String(buf.String())
   278  				},
   279  			},
   280  
   281  			"stop_action": &schema.Schema{
   282  				Type:     schema.TypeSet,
   283  				Optional: true,
   284  				Elem: &schema.Resource{
   285  					Schema: map[string]*schema.Schema{
   286  						"scope": &schema.Schema{
   287  							Type:     schema.TypeString,
   288  							Required: true,
   289  						},
   290  
   291  						"topic_arn": &schema.Schema{
   292  							Type:     schema.TypeString,
   293  							Optional: true,
   294  						},
   295  
   296  						"position": &schema.Schema{
   297  							Type:     schema.TypeInt,
   298  							Required: true,
   299  						},
   300  					},
   301  				},
   302  				Set: func(v interface{}) int {
   303  					var buf bytes.Buffer
   304  					m := v.(map[string]interface{})
   305  					buf.WriteString(fmt.Sprintf("%s-", m["scope"].(string)))
   306  
   307  					if _, ok := m["topic_arn"]; ok {
   308  						buf.WriteString(fmt.Sprintf("%s-", m["topic_arn"].(string)))
   309  					}
   310  
   311  					buf.WriteString(fmt.Sprintf("%d-", m["position"].(int)))
   312  
   313  					return hashcode.String(buf.String())
   314  				},
   315  			},
   316  
   317  			"workmail_action": &schema.Schema{
   318  				Type:     schema.TypeSet,
   319  				Optional: true,
   320  				Elem: &schema.Resource{
   321  					Schema: map[string]*schema.Schema{
   322  						"organization_arn": &schema.Schema{
   323  							Type:     schema.TypeString,
   324  							Required: true,
   325  						},
   326  
   327  						"topic_arn": &schema.Schema{
   328  							Type:     schema.TypeString,
   329  							Optional: true,
   330  						},
   331  
   332  						"position": &schema.Schema{
   333  							Type:     schema.TypeInt,
   334  							Required: true,
   335  						},
   336  					},
   337  				},
   338  				Set: func(v interface{}) int {
   339  					var buf bytes.Buffer
   340  					m := v.(map[string]interface{})
   341  					buf.WriteString(fmt.Sprintf("%s-", m["organization_arn"].(string)))
   342  
   343  					if _, ok := m["topic_arn"]; ok {
   344  						buf.WriteString(fmt.Sprintf("%s-", m["topic_arn"].(string)))
   345  					}
   346  
   347  					buf.WriteString(fmt.Sprintf("%d-", m["position"].(int)))
   348  
   349  					return hashcode.String(buf.String())
   350  				},
   351  			},
   352  		},
   353  	}
   354  }
   355  
   356  func resourceAwsSesReceiptRuleCreate(d *schema.ResourceData, meta interface{}) error {
   357  	conn := meta.(*AWSClient).sesConn
   358  
   359  	createOpts := &ses.CreateReceiptRuleInput{
   360  		Rule:        buildReceiptRule(d, meta),
   361  		RuleSetName: aws.String(d.Get("rule_set_name").(string)),
   362  	}
   363  
   364  	if v, ok := d.GetOk("after"); ok {
   365  		createOpts.After = aws.String(v.(string))
   366  	}
   367  
   368  	_, err := conn.CreateReceiptRule(createOpts)
   369  	if err != nil {
   370  		return fmt.Errorf("Error creating SES rule: %s", err)
   371  	}
   372  
   373  	d.SetId(d.Get("name").(string))
   374  
   375  	return resourceAwsSesReceiptRuleUpdate(d, meta)
   376  }
   377  
   378  func resourceAwsSesReceiptRuleUpdate(d *schema.ResourceData, meta interface{}) error {
   379  	conn := meta.(*AWSClient).sesConn
   380  
   381  	updateOpts := &ses.UpdateReceiptRuleInput{
   382  		Rule:        buildReceiptRule(d, meta),
   383  		RuleSetName: aws.String(d.Get("rule_set_name").(string)),
   384  	}
   385  
   386  	_, err := conn.UpdateReceiptRule(updateOpts)
   387  	if err != nil {
   388  		return fmt.Errorf("Error updating SES rule: %s", err)
   389  	}
   390  
   391  	if d.HasChange("after") {
   392  		changePosOpts := &ses.SetReceiptRulePositionInput{
   393  			After:       aws.String(d.Get("after").(string)),
   394  			RuleName:    aws.String(d.Get("name").(string)),
   395  			RuleSetName: aws.String(d.Get("rule_set_name").(string)),
   396  		}
   397  
   398  		_, err := conn.SetReceiptRulePosition(changePosOpts)
   399  		if err != nil {
   400  			return fmt.Errorf("Error updating SES rule: %s", err)
   401  		}
   402  	}
   403  
   404  	return resourceAwsSesReceiptRuleRead(d, meta)
   405  }
   406  
   407  func resourceAwsSesReceiptRuleRead(d *schema.ResourceData, meta interface{}) error {
   408  	conn := meta.(*AWSClient).sesConn
   409  
   410  	describeOpts := &ses.DescribeReceiptRuleInput{
   411  		RuleName:    aws.String(d.Id()),
   412  		RuleSetName: aws.String(d.Get("rule_set_name").(string)),
   413  	}
   414  
   415  	response, err := conn.DescribeReceiptRule(describeOpts)
   416  	if err != nil {
   417  		_, ok := err.(awserr.Error)
   418  		if ok && err.(awserr.Error).Code() == "RuleDoesNotExist" {
   419  			log.Printf("[WARN] SES Receipt Rule (%s) not found", d.Id())
   420  			d.SetId("")
   421  			return nil
   422  		} else {
   423  			return err
   424  		}
   425  	}
   426  
   427  	d.Set("enabled", *response.Rule.Enabled)
   428  	d.Set("recipients", flattenStringList(response.Rule.Recipients))
   429  	d.Set("scan_enabled", *response.Rule.ScanEnabled)
   430  	d.Set("tls_policy", *response.Rule.TlsPolicy)
   431  
   432  	addHeaderActionList := []map[string]interface{}{}
   433  	bounceActionList := []map[string]interface{}{}
   434  	lambdaActionList := []map[string]interface{}{}
   435  	s3ActionList := []map[string]interface{}{}
   436  	snsActionList := []map[string]interface{}{}
   437  	stopActionList := []map[string]interface{}{}
   438  	workmailActionList := []map[string]interface{}{}
   439  
   440  	for i, element := range response.Rule.Actions {
   441  		if element.AddHeaderAction != nil {
   442  			addHeaderAction := map[string]interface{}{
   443  				"header_name":  *element.AddHeaderAction.HeaderName,
   444  				"header_value": *element.AddHeaderAction.HeaderValue,
   445  				"position":     i,
   446  			}
   447  			addHeaderActionList = append(addHeaderActionList, addHeaderAction)
   448  		}
   449  
   450  		if element.BounceAction != nil {
   451  			bounceAction := map[string]interface{}{
   452  				"message":         *element.BounceAction.Message,
   453  				"sender":          *element.BounceAction.Sender,
   454  				"smtp_reply_code": *element.BounceAction.SmtpReplyCode,
   455  				"position":        i,
   456  			}
   457  
   458  			if element.BounceAction.StatusCode != nil {
   459  				bounceAction["status_code"] = *element.BounceAction.StatusCode
   460  			}
   461  
   462  			if element.BounceAction.TopicArn != nil {
   463  				bounceAction["topic_arn"] = *element.BounceAction.TopicArn
   464  			}
   465  
   466  			bounceActionList = append(bounceActionList, bounceAction)
   467  		}
   468  
   469  		if element.LambdaAction != nil {
   470  			lambdaAction := map[string]interface{}{
   471  				"function_arn": *element.LambdaAction.FunctionArn,
   472  				"position":     i,
   473  			}
   474  
   475  			if element.LambdaAction.InvocationType != nil {
   476  				lambdaAction["invocation_type"] = *element.LambdaAction.InvocationType
   477  			}
   478  
   479  			if element.LambdaAction.TopicArn != nil {
   480  				lambdaAction["topic_arn"] = *element.LambdaAction.TopicArn
   481  			}
   482  
   483  			lambdaActionList = append(lambdaActionList, lambdaAction)
   484  		}
   485  
   486  		if element.S3Action != nil {
   487  			s3Action := map[string]interface{}{
   488  				"bucket_name": *element.S3Action.BucketName,
   489  				"position":    i,
   490  			}
   491  
   492  			if element.S3Action.KmsKeyArn != nil {
   493  				s3Action["kms_key_arn"] = *element.S3Action.KmsKeyArn
   494  			}
   495  
   496  			if element.S3Action.ObjectKeyPrefix != nil {
   497  				s3Action["object_key_prefix"] = *element.S3Action.ObjectKeyPrefix
   498  			}
   499  
   500  			if element.S3Action.TopicArn != nil {
   501  				s3Action["topic_arn"] = *element.S3Action.TopicArn
   502  			}
   503  
   504  			s3ActionList = append(s3ActionList, s3Action)
   505  		}
   506  
   507  		if element.SNSAction != nil {
   508  			snsAction := map[string]interface{}{
   509  				"topic_arn": *element.SNSAction.TopicArn,
   510  				"position":  i,
   511  			}
   512  
   513  			snsActionList = append(snsActionList, snsAction)
   514  		}
   515  
   516  		if element.StopAction != nil {
   517  			stopAction := map[string]interface{}{
   518  				"scope":    *element.StopAction.Scope,
   519  				"position": i,
   520  			}
   521  
   522  			if element.StopAction.TopicArn != nil {
   523  				stopAction["topic_arn"] = *element.StopAction.TopicArn
   524  			}
   525  
   526  			stopActionList = append(stopActionList, stopAction)
   527  		}
   528  
   529  		if element.WorkmailAction != nil {
   530  			workmailAction := map[string]interface{}{
   531  				"organization_arn": *element.WorkmailAction.OrganizationArn,
   532  				"position":         i,
   533  			}
   534  
   535  			if element.WorkmailAction.TopicArn != nil {
   536  				workmailAction["topic_arn"] = *element.WorkmailAction.TopicArn
   537  			}
   538  
   539  			workmailActionList = append(workmailActionList, workmailAction)
   540  		}
   541  
   542  	}
   543  
   544  	err = d.Set("add_header_action", addHeaderActionList)
   545  	if err != nil {
   546  		return err
   547  	}
   548  
   549  	err = d.Set("bounce_action", bounceActionList)
   550  	if err != nil {
   551  		return err
   552  	}
   553  
   554  	err = d.Set("lambda_action", lambdaActionList)
   555  	if err != nil {
   556  		return err
   557  	}
   558  
   559  	err = d.Set("s3_action", s3ActionList)
   560  	if err != nil {
   561  		return err
   562  	}
   563  
   564  	err = d.Set("sns_action", snsActionList)
   565  	if err != nil {
   566  		return err
   567  	}
   568  
   569  	err = d.Set("stop_action", stopActionList)
   570  	if err != nil {
   571  		return err
   572  	}
   573  
   574  	err = d.Set("workmail_action", workmailActionList)
   575  	if err != nil {
   576  		return err
   577  	}
   578  
   579  	return nil
   580  }
   581  
   582  func resourceAwsSesReceiptRuleDelete(d *schema.ResourceData, meta interface{}) error {
   583  	conn := meta.(*AWSClient).sesConn
   584  
   585  	deleteOpts := &ses.DeleteReceiptRuleInput{
   586  		RuleName:    aws.String(d.Id()),
   587  		RuleSetName: aws.String(d.Get("rule_set_name").(string)),
   588  	}
   589  
   590  	_, err := conn.DeleteReceiptRule(deleteOpts)
   591  	if err != nil {
   592  		return fmt.Errorf("Error deleting SES receipt rule: %s", err)
   593  	}
   594  
   595  	return nil
   596  }
   597  
   598  func buildReceiptRule(d *schema.ResourceData, meta interface{}) *ses.ReceiptRule {
   599  	receiptRule := &ses.ReceiptRule{
   600  		Name: aws.String(d.Get("name").(string)),
   601  	}
   602  
   603  	if v, ok := d.GetOk("enabled"); ok {
   604  		receiptRule.Enabled = aws.Bool(v.(bool))
   605  	}
   606  
   607  	if v, ok := d.GetOk("recipients"); ok {
   608  		receiptRule.Recipients = expandStringList(v.(*schema.Set).List())
   609  	}
   610  
   611  	if v, ok := d.GetOk("scan_enabled"); ok {
   612  		receiptRule.ScanEnabled = aws.Bool(v.(bool))
   613  	}
   614  
   615  	if v, ok := d.GetOk("tls_policy"); ok {
   616  		receiptRule.TlsPolicy = aws.String(v.(string))
   617  	}
   618  
   619  	actions := make(map[int]*ses.ReceiptAction)
   620  
   621  	if v, ok := d.GetOk("add_header_action"); ok {
   622  		for _, element := range v.(*schema.Set).List() {
   623  			elem := element.(map[string]interface{})
   624  
   625  			actions[elem["position"].(int)] = &ses.ReceiptAction{
   626  				AddHeaderAction: &ses.AddHeaderAction{
   627  					HeaderName:  aws.String(elem["header_name"].(string)),
   628  					HeaderValue: aws.String(elem["header_value"].(string)),
   629  				},
   630  			}
   631  		}
   632  	}
   633  
   634  	if v, ok := d.GetOk("bounce_action"); ok {
   635  		for _, element := range v.(*schema.Set).List() {
   636  			elem := element.(map[string]interface{})
   637  
   638  			bounceAction := &ses.BounceAction{
   639  				Message:       aws.String(elem["message"].(string)),
   640  				Sender:        aws.String(elem["sender"].(string)),
   641  				SmtpReplyCode: aws.String(elem["smtp_reply_code"].(string)),
   642  			}
   643  
   644  			if elem["status_code"] != "" {
   645  				bounceAction.StatusCode = aws.String(elem["status_code"].(string))
   646  			}
   647  
   648  			if elem["topic_arn"] != "" {
   649  				bounceAction.TopicArn = aws.String(elem["topic_arn"].(string))
   650  			}
   651  
   652  			actions[elem["position"].(int)] = &ses.ReceiptAction{
   653  				BounceAction: bounceAction,
   654  			}
   655  		}
   656  	}
   657  
   658  	if v, ok := d.GetOk("lambda_action"); ok {
   659  		for _, element := range v.(*schema.Set).List() {
   660  			elem := element.(map[string]interface{})
   661  
   662  			lambdaAction := &ses.LambdaAction{
   663  				FunctionArn: aws.String(elem["function_arn"].(string)),
   664  			}
   665  
   666  			if elem["invocation_type"] != "" {
   667  				lambdaAction.InvocationType = aws.String(elem["invocation_type"].(string))
   668  			}
   669  
   670  			if elem["topic_arn"] != "" {
   671  				lambdaAction.TopicArn = aws.String(elem["topic_arn"].(string))
   672  			}
   673  
   674  			actions[elem["position"].(int)] = &ses.ReceiptAction{
   675  				LambdaAction: lambdaAction,
   676  			}
   677  		}
   678  	}
   679  
   680  	if v, ok := d.GetOk("s3_action"); ok {
   681  		for _, element := range v.(*schema.Set).List() {
   682  			elem := element.(map[string]interface{})
   683  
   684  			s3Action := &ses.S3Action{
   685  				BucketName:      aws.String(elem["bucket_name"].(string)),
   686  				KmsKeyArn:       aws.String(elem["kms_key_arn"].(string)),
   687  				ObjectKeyPrefix: aws.String(elem["object_key_prefix"].(string)),
   688  			}
   689  
   690  			if elem["topic_arn"] != "" {
   691  				s3Action.TopicArn = aws.String(elem["topic_arn"].(string))
   692  			}
   693  
   694  			actions[elem["position"].(int)] = &ses.ReceiptAction{
   695  				S3Action: s3Action,
   696  			}
   697  		}
   698  	}
   699  
   700  	if v, ok := d.GetOk("sns_action"); ok {
   701  		for _, element := range v.(*schema.Set).List() {
   702  			elem := element.(map[string]interface{})
   703  
   704  			snsAction := &ses.SNSAction{
   705  				TopicArn: aws.String(elem["topic_arn"].(string)),
   706  			}
   707  
   708  			actions[elem["position"].(int)] = &ses.ReceiptAction{
   709  				SNSAction: snsAction,
   710  			}
   711  		}
   712  	}
   713  
   714  	if v, ok := d.GetOk("stop_action"); ok {
   715  		for _, element := range v.(*schema.Set).List() {
   716  			elem := element.(map[string]interface{})
   717  
   718  			stopAction := &ses.StopAction{
   719  				Scope: aws.String(elem["scope"].(string)),
   720  			}
   721  
   722  			if elem["topic_arn"] != "" {
   723  				stopAction.TopicArn = aws.String(elem["topic_arn"].(string))
   724  			}
   725  
   726  			actions[elem["position"].(int)] = &ses.ReceiptAction{
   727  				StopAction: stopAction,
   728  			}
   729  		}
   730  	}
   731  
   732  	if v, ok := d.GetOk("workmail_action"); ok {
   733  		for _, element := range v.(*schema.Set).List() {
   734  			elem := element.(map[string]interface{})
   735  
   736  			workmailAction := &ses.WorkmailAction{
   737  				OrganizationArn: aws.String(elem["organization_arn"].(string)),
   738  			}
   739  
   740  			if elem["topic_arn"] != "" {
   741  				workmailAction.TopicArn = aws.String(elem["topic_arn"].(string))
   742  			}
   743  
   744  			actions[elem["position"].(int)] = &ses.ReceiptAction{
   745  				WorkmailAction: workmailAction,
   746  			}
   747  		}
   748  	}
   749  
   750  	var keys []int
   751  	for k := range actions {
   752  		keys = append(keys, k)
   753  	}
   754  	sort.Ints(keys)
   755  
   756  	sortedActions := []*ses.ReceiptAction{}
   757  	for _, k := range keys {
   758  		sortedActions = append(sortedActions, actions[k])
   759  	}
   760  
   761  	receiptRule.Actions = sortedActions
   762  
   763  	return receiptRule
   764  }