provider/aws: Enhance Triggers for AWS CodeDeploy Event Notifications (#6168)

* Improve testing of CodeDeploy DeploymentGroup Trigger Configs

  - ensure updates to trigger_events are applied
  - assert changes to trigger_target_arn

* Retry CodeDeploy DeploymentGroup when Trigger Config SNS Topic is not available

  - increase retries from 2 => 5
This commit is contained in:
Raymond Fallon 2016-04-14 15:26:33 -04:00 committed by Paul Stack
parent cfbe11b126
commit eed8733ee3
2 changed files with 125 additions and 17 deletions

View File

@ -4,6 +4,8 @@ import (
"bytes"
"fmt"
"log"
"regexp"
"sort"
"time"
"github.com/hashicorp/terraform/helper/hashcode"
@ -191,14 +193,24 @@ func resourceAwsCodeDeployDeploymentGroupCreate(d *schema.ResourceData, meta int
// Retry to handle IAM role eventual consistency.
var resp *codedeploy.CreateDeploymentGroupOutput
var err error
err = resource.Retry(2*time.Minute, func() *resource.RetryError {
err = resource.Retry(5*time.Minute, func() *resource.RetryError {
resp, err = conn.CreateDeploymentGroup(&input)
if err != nil {
retry := false
codedeployErr, ok := err.(awserr.Error)
if !ok {
return resource.NonRetryableError(err)
}
if codedeployErr.Code() == "InvalidRoleException" {
retry = true
}
if codedeployErr.Code() == "InvalidTriggerConfigException" {
r := regexp.MustCompile("^Topic ARN .+ is not valid$")
if r.MatchString(codedeployErr.Message()) {
retry = true
}
}
if retry {
log.Printf("[DEBUG] Trying to create deployment group again: %q",
codedeployErr.Message())
return resource.RetryableError(err)
@ -439,6 +451,19 @@ func resourceAwsCodeDeployTriggerConfigHash(v interface{}) int {
m := v.(map[string]interface{})
buf.WriteString(fmt.Sprintf("%s-", m["trigger_name"].(string)))
buf.WriteString(fmt.Sprintf("%s-", m["trigger_target_arn"].(string)))
if triggerEvents, ok := m["trigger_events"]; ok {
names := triggerEvents.(*schema.Set).List()
strings := make([]string, len(names))
for i, raw := range names {
strings[i] = raw.(string)
}
sort.Strings(strings)
for _, s := range strings {
buf.WriteString(fmt.Sprintf("%s-", s))
}
}
return hashcode.String(buf.String())
}

View File

@ -3,6 +3,8 @@ package aws
import (
"fmt"
"reflect"
"regexp"
"sort"
"testing"
"github.com/aws/aws-sdk-go/aws"
@ -14,6 +16,8 @@ import (
)
func TestAccAWSCodeDeployDeploymentGroup_basic(t *testing.T) {
var group codedeploy.DeploymentGroupInfo
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
@ -22,7 +26,7 @@ func TestAccAWSCodeDeployDeploymentGroup_basic(t *testing.T) {
resource.TestStep{
Config: testAccAWSCodeDeployDeploymentGroup,
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSCodeDeployDeploymentGroupExists("aws_codedeploy_deployment_group.foo"),
testAccCheckAWSCodeDeployDeploymentGroupExists("aws_codedeploy_deployment_group.foo", &group),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo", "app_name", "foo_app"),
resource.TestCheckResourceAttr(
@ -43,7 +47,7 @@ func TestAccAWSCodeDeployDeploymentGroup_basic(t *testing.T) {
resource.TestStep{
Config: testAccAWSCodeDeployDeploymentGroupModified,
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSCodeDeployDeploymentGroupExists("aws_codedeploy_deployment_group.foo"),
testAccCheckAWSCodeDeployDeploymentGroupExists("aws_codedeploy_deployment_group.foo", &group),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo", "app_name", "foo_app"),
resource.TestCheckResourceAttr(
@ -66,6 +70,8 @@ func TestAccAWSCodeDeployDeploymentGroup_basic(t *testing.T) {
}
func TestAccAWSCodeDeployDeploymentGroup_triggerConfiguration_basic(t *testing.T) {
var group codedeploy.DeploymentGroupInfo
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
@ -74,25 +80,28 @@ func TestAccAWSCodeDeployDeploymentGroup_triggerConfiguration_basic(t *testing.T
resource.TestStep{
Config: testAccAWSCodeDeployDeploymentGroup_triggerConfiguration_create,
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSCodeDeployDeploymentGroupExists("aws_codedeploy_deployment_group.foo_group"),
testAccCheckAWSCodeDeployDeploymentGroupExists("aws_codedeploy_deployment_group.foo_group", &group),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "app_name", "foo-app"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "deployment_group_name", "foo-group"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "deployment_config_name", "CodeDeployDefault.OneAtATime"),
testAccCheckTriggerEvents(&group, "foo-trigger", []string{
"DeploymentFailure",
}),
),
},
resource.TestStep{
Config: testAccAWSCodeDeployDeploymentGroup_triggerConfiguration_update,
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSCodeDeployDeploymentGroupExists("aws_codedeploy_deployment_group.foo_group"),
testAccCheckAWSCodeDeployDeploymentGroupExists("aws_codedeploy_deployment_group.foo_group", &group),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "app_name", "foo-app"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "deployment_group_name", "foo-group"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "deployment_config_name", "CodeDeployDefault.OneAtATime"),
testAccCheckTriggerEvents(&group, "foo-trigger", []string{
"DeploymentFailure",
"DeploymentSuccess",
}),
),
},
},
@ -100,6 +109,8 @@ func TestAccAWSCodeDeployDeploymentGroup_triggerConfiguration_basic(t *testing.T
}
func TestAccAWSCodeDeployDeploymentGroup_triggerConfiguration_multiple(t *testing.T) {
var group codedeploy.DeploymentGroupInfo
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
@ -108,25 +119,40 @@ func TestAccAWSCodeDeployDeploymentGroup_triggerConfiguration_multiple(t *testin
resource.TestStep{
Config: testAccAWSCodeDeployDeploymentGroup_triggerConfiguration_createMultiple,
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSCodeDeployDeploymentGroupExists("aws_codedeploy_deployment_group.foo_group"),
testAccCheckAWSCodeDeployDeploymentGroupExists("aws_codedeploy_deployment_group.foo_group", &group),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "app_name", "foo-app"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "deployment_group_name", "foo-group"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "deployment_config_name", "CodeDeployDefault.OneAtATime"),
testAccCheckTriggerEvents(&group, "foo-trigger", []string{
"DeploymentFailure",
}),
testAccCheckTriggerEvents(&group, "bar-trigger", []string{
"InstanceFailure",
}),
testAccCheckTriggerTargetArn(&group, "bar-trigger",
regexp.MustCompile("^arn:aws:sns:[^:]+:[0-9]{12}:bar-topic$")),
),
},
resource.TestStep{
Config: testAccAWSCodeDeployDeploymentGroup_triggerConfiguration_updateMultiple,
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSCodeDeployDeploymentGroupExists("aws_codedeploy_deployment_group.foo_group"),
testAccCheckAWSCodeDeployDeploymentGroupExists("aws_codedeploy_deployment_group.foo_group", &group),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "app_name", "foo-app"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "deployment_group_name", "foo-group"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "deployment_config_name", "CodeDeployDefault.OneAtATime"),
testAccCheckTriggerEvents(&group, "foo-trigger", []string{
"DeploymentFailure",
"DeploymentStart",
"DeploymentStop",
"DeploymentSuccess",
}),
testAccCheckTriggerEvents(&group, "bar-trigger", []string{
"InstanceFailure",
}),
testAccCheckTriggerTargetArn(&group, "bar-trigger",
regexp.MustCompile("^arn:aws:sns:[^:]+:[0-9]{12}:baz-topic$")),
),
},
},
@ -266,6 +292,50 @@ func TestTriggerConfigsToMap(t *testing.T) {
}
}
func testAccCheckTriggerEvents(group *codedeploy.DeploymentGroupInfo, triggerName string, expectedEvents []string) resource.TestCheckFunc {
return func(s *terraform.State) error {
for _, actual := range group.TriggerConfigurations {
if *actual.TriggerName == triggerName {
numberOfEvents := len(actual.TriggerEvents)
if numberOfEvents != len(expectedEvents) {
return fmt.Errorf("Trigger events do not match. Expected: %d. Got: %d.",
len(expectedEvents), numberOfEvents)
}
actualEvents := make([]string, 0, numberOfEvents)
for _, event := range actual.TriggerEvents {
actualEvents = append(actualEvents, *event)
}
sort.Strings(actualEvents)
if !reflect.DeepEqual(actualEvents, expectedEvents) {
return fmt.Errorf("Trigger events do not match.\nExpected: %v\nGot: %v\n",
expectedEvents, actualEvents)
}
break
}
}
return nil
}
}
func testAccCheckTriggerTargetArn(group *codedeploy.DeploymentGroupInfo, triggerName string, r *regexp.Regexp) resource.TestCheckFunc {
return func(s *terraform.State) error {
for _, actual := range group.TriggerConfigurations {
if *actual.TriggerName == triggerName {
if !r.MatchString(*actual.TriggerTargetArn) {
return fmt.Errorf("Trigger target arn does not match regular expression.\nRegex: %v\nTriggerTargetArn: %v\n",
r, *actual.TriggerTargetArn)
}
break
}
}
return nil
}
}
func testAccCheckAWSCodeDeployDeploymentGroupDestroy(s *terraform.State) error {
conn := testAccProvider.Meta().(*AWSClient).codedeployconn
@ -295,13 +365,26 @@ func testAccCheckAWSCodeDeployDeploymentGroupDestroy(s *terraform.State) error {
return nil
}
func testAccCheckAWSCodeDeployDeploymentGroupExists(name string) resource.TestCheckFunc {
func testAccCheckAWSCodeDeployDeploymentGroupExists(name string, group *codedeploy.DeploymentGroupInfo) resource.TestCheckFunc {
return func(s *terraform.State) error {
_, ok := s.RootModule().Resources[name]
rs, ok := s.RootModule().Resources[name]
if !ok {
return fmt.Errorf("Not found: %s", name)
}
conn := testAccProvider.Meta().(*AWSClient).codedeployconn
resp, err := conn.GetDeploymentGroup(&codedeploy.GetDeploymentGroupInput{
ApplicationName: aws.String(rs.Primary.Attributes["app_name"]),
DeploymentGroupName: aws.String(rs.Primary.Attributes["deployment_group_name"]),
})
if err != nil {
return err
}
*group = *resp.DeploymentGroupInfo
return nil
}
}