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