Automatic Rollback of CodeDeploy deployments and CloudWatch Alarms for a Deployment Group (#9039)

* provider/aws: Add DeploymentRollback as a valid TriggerEvent type

* provider/aws: Add auto_rollback_configuration to aws_codedeploy_deployment_group

* provider/aws: Document auto_rollback_configuration

  - part of aws_codedeploy_deployment_group

* provider/aws: Support removing and disabling auto_rollback_configuration

  - part of aws_codedeploy_deployment_group resource
  - when removing configuration, ensure events are removed
  - when disabling configuration, preserve events in case configuration is re-enabled

* provider/aws: Add alarm_configuration to aws_codedeploy_deployment_group

* provider/aws: Document alarm_configuration

  - part of aws_codedeploy_deployment_group

* provider/aws: Support removing alarm_configuration

  - part of aws_codedeploy_deployment_group resource
  - disabling configuration doesn't appear to work...

* provider/aws: Refactor auto_rollback_configuration tests

  - Add create test
  - SKIP failing test for now
  - Add tests for build & map functions

* provider/aws: Refactor new aws_code_deploy_deployment_group tests

  - alarm_configuration and auto_rollback_configuration only
  - add assertions to deployment_group basic test
  - rename config funcs to be more easy to read
  - group public tests together

* provider/aws: A max of 10 alarms can be added to a deployment group.

  - aws_code_deploy_deployment_group.alarm_configuration.alarms
  - verified this causes test failure with expected exception

* provider/aws: Test disabling alarm_configuration and auto_rollback_configuration

  - the tests now pass after rebasing the latest master branch
This commit is contained in:
Raymond Fallon 2016-12-01 09:12:14 -05:00 committed by Paul Stack
parent 3eb4f16eaa
commit 7b672d4656
3 changed files with 810 additions and 11 deletions

View File

@ -57,6 +57,55 @@ func resourceAwsCodeDeployDeploymentGroup() *schema.Resource {
Required: true, Required: true,
}, },
"alarm_configuration": &schema.Schema{
Type: schema.TypeList,
Optional: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"alarms": &schema.Schema{
Type: schema.TypeSet,
MaxItems: 10,
Optional: true,
Set: schema.HashString,
Elem: &schema.Schema{Type: schema.TypeString},
},
"enabled": &schema.Schema{
Type: schema.TypeBool,
Optional: true,
},
"ignore_poll_alarm_failure": &schema.Schema{
Type: schema.TypeBool,
Optional: true,
Default: false,
},
},
},
},
"auto_rollback_configuration": &schema.Schema{
Type: schema.TypeList,
Optional: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"enabled": &schema.Schema{
Type: schema.TypeBool,
Optional: true,
},
"events": &schema.Schema{
Type: schema.TypeSet,
Optional: true,
Set: schema.HashString,
Elem: &schema.Schema{Type: schema.TypeString},
},
},
},
},
"autoscaling_groups": &schema.Schema{ "autoscaling_groups": &schema.Schema{
Type: schema.TypeSet, Type: schema.TypeSet,
Optional: true, Optional: true,
@ -190,6 +239,14 @@ func resourceAwsCodeDeployDeploymentGroupCreate(d *schema.ResourceData, meta int
input.TriggerConfigurations = triggerConfigs input.TriggerConfigurations = triggerConfigs
} }
if attr, ok := d.GetOk("auto_rollback_configuration"); ok {
input.AutoRollbackConfiguration = buildAutoRollbackConfig(attr.([]interface{}))
}
if attr, ok := d.GetOk("alarm_configuration"); ok {
input.AlarmConfiguration = buildAlarmConfig(attr.([]interface{}))
}
// Retry to handle IAM role eventual consistency. // Retry to handle IAM role eventual consistency.
var resp *codedeploy.CreateDeploymentGroupOutput var resp *codedeploy.CreateDeploymentGroupOutput
var err error var err error
@ -262,6 +319,14 @@ func resourceAwsCodeDeployDeploymentGroupRead(d *schema.ResourceData, meta inter
return err return err
} }
if err := d.Set("auto_rollback_configuration", autoRollbackConfigToMap(resp.DeploymentGroupInfo.AutoRollbackConfiguration)); err != nil {
return err
}
if err := d.Set("alarm_configuration", alarmConfigToMap(resp.DeploymentGroupInfo.AlarmConfiguration)); err != nil {
return err
}
return nil return nil
} }
@ -303,6 +368,16 @@ func resourceAwsCodeDeployDeploymentGroupUpdate(d *schema.ResourceData, meta int
input.TriggerConfigurations = triggerConfigs input.TriggerConfigurations = triggerConfigs
} }
if d.HasChange("auto_rollback_configuration") {
_, n := d.GetChange("auto_rollback_configuration")
input.AutoRollbackConfiguration = buildAutoRollbackConfig(n.([]interface{}))
}
if d.HasChange("alarm_configuration") {
_, n := d.GetChange("alarm_configuration")
input.AlarmConfiguration = buildAlarmConfig(n.([]interface{}))
}
log.Printf("[DEBUG] Updating CodeDeploy DeploymentGroup %s", d.Id()) log.Printf("[DEBUG] Updating CodeDeploy DeploymentGroup %s", d.Id())
// Retry to handle IAM role eventual consistency. // Retry to handle IAM role eventual consistency.
err := resource.Retry(5*time.Minute, func() *resource.RetryError { err := resource.Retry(5*time.Minute, func() *resource.RetryError {
@ -416,6 +491,52 @@ func buildTriggerConfigs(configured []interface{}) []*codedeploy.TriggerConfig {
return configs return configs
} }
// buildAutoRollbackConfig converts a raw schema list containing a map[string]interface{}
// into a single codedeploy.AutoRollbackConfiguration
func buildAutoRollbackConfig(configured []interface{}) *codedeploy.AutoRollbackConfiguration {
result := &codedeploy.AutoRollbackConfiguration{}
if len(configured) == 1 {
config := configured[0].(map[string]interface{})
result.Enabled = aws.Bool(config["enabled"].(bool))
result.Events = expandStringSet(config["events"].(*schema.Set))
} else { // delete the configuration
result.Enabled = aws.Bool(false)
result.Events = make([]*string, 0)
}
return result
}
// buildAlarmConfig converts a raw schema list containing a map[string]interface{}
// into a single codedeploy.AlarmConfiguration
func buildAlarmConfig(configured []interface{}) *codedeploy.AlarmConfiguration {
result := &codedeploy.AlarmConfiguration{}
if len(configured) == 1 {
config := configured[0].(map[string]interface{})
names := expandStringSet(config["alarms"].(*schema.Set))
alarms := make([]*codedeploy.Alarm, 0, len(names))
for _, name := range names {
alarm := &codedeploy.Alarm{
Name: name,
}
alarms = append(alarms, alarm)
}
result.Alarms = alarms
result.Enabled = aws.Bool(config["enabled"].(bool))
result.IgnorePollAlarmFailure = aws.Bool(config["ignore_poll_alarm_failure"].(bool))
} else { // delete the configuration
result.Alarms = make([]*codedeploy.Alarm, 0)
result.Enabled = aws.Bool(false)
result.IgnorePollAlarmFailure = aws.Bool(false)
}
return result
}
// ec2TagFiltersToMap converts lists of tag filters into a []map[string]string. // ec2TagFiltersToMap converts lists of tag filters into a []map[string]string.
func ec2TagFiltersToMap(list []*codedeploy.EC2TagFilter) []map[string]string { func ec2TagFiltersToMap(list []*codedeploy.EC2TagFilter) []map[string]string {
result := make([]map[string]string, 0, len(list)) result := make([]map[string]string, 0, len(list))
@ -467,6 +588,47 @@ func triggerConfigsToMap(list []*codedeploy.TriggerConfig) []map[string]interfac
return result return result
} }
// autoRollbackConfigToMap converts a codedeploy.AutoRollbackConfiguration
// into a []map[string]interface{} list containing a single item
func autoRollbackConfigToMap(config *codedeploy.AutoRollbackConfiguration) []map[string]interface{} {
result := make([]map[string]interface{}, 0, 1)
// only create configurations that are enabled or temporarily disabled (retaining events)
// otherwise empty configurations will be created
if config != nil && (*config.Enabled == true || len(config.Events) > 0) {
item := make(map[string]interface{})
item["enabled"] = *config.Enabled
item["events"] = schema.NewSet(schema.HashString, flattenStringList(config.Events))
result = append(result, item)
}
return result
}
// alarmConfigToMap converts a codedeploy.AlarmConfiguration
// into a []map[string]interface{} list containing a single item
func alarmConfigToMap(config *codedeploy.AlarmConfiguration) []map[string]interface{} {
result := make([]map[string]interface{}, 0, 1)
// only create configurations that are enabled or temporarily disabled (retaining alarms)
// otherwise empty configurations will be created
if config != nil && (*config.Enabled == true || len(config.Alarms) > 0) {
names := make([]*string, 0, len(config.Alarms))
for _, alarm := range config.Alarms {
names = append(names, alarm.Name)
}
item := make(map[string]interface{})
item["alarms"] = schema.NewSet(schema.HashString, flattenStringList(names))
item["enabled"] = *config.Enabled
item["ignore_poll_alarm_failure"] = *config.IgnorePollAlarmFailure
result = append(result, item)
}
return result
}
func resourceAwsCodeDeployTagFilterHash(v interface{}) int { func resourceAwsCodeDeployTagFilterHash(v interface{}) int {
var buf bytes.Buffer var buf bytes.Buffer
m := v.(map[string]interface{}) m := v.(map[string]interface{})
@ -510,13 +672,14 @@ func resourceAwsCodeDeployTriggerConfigHash(v interface{}) int {
func validateTriggerEvent(v interface{}, k string) (ws []string, errors []error) { func validateTriggerEvent(v interface{}, k string) (ws []string, errors []error) {
value := v.(string) value := v.(string)
triggerEvents := map[string]bool{ triggerEvents := map[string]bool{
"DeploymentStart": true, "DeploymentStart": true,
"DeploymentStop": true, "DeploymentStop": true,
"DeploymentSuccess": true, "DeploymentSuccess": true,
"DeploymentFailure": true, "DeploymentFailure": true,
"InstanceStart": true, "DeploymentRollback": true,
"InstanceSuccess": true, "InstanceStart": true,
"InstanceFailure": true, "InstanceSuccess": true,
"InstanceFailure": true,
} }
if !triggerEvents[value] { if !triggerEvents[value] {

View File

@ -46,6 +46,13 @@ func TestAccAWSCodeDeployDeploymentGroup_basic(t *testing.T) {
"aws_codedeploy_deployment_group.foo", "ec2_tag_filter.2916377465.type", "KEY_AND_VALUE"), "aws_codedeploy_deployment_group.foo", "ec2_tag_filter.2916377465.type", "KEY_AND_VALUE"),
resource.TestCheckResourceAttr( resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo", "ec2_tag_filter.2916377465.value", "filtervalue"), "aws_codedeploy_deployment_group.foo", "ec2_tag_filter.2916377465.value", "filtervalue"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo", "alarm_configuration.#", "0"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo", "auto_rollback_configuration.#", "0"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo", "trigger_configuration.#", "0"),
), ),
}, },
resource.TestStep{ resource.TestStep{
@ -67,6 +74,13 @@ func TestAccAWSCodeDeployDeploymentGroup_basic(t *testing.T) {
"aws_codedeploy_deployment_group.foo", "ec2_tag_filter.2369538975.type", "KEY_AND_VALUE"), "aws_codedeploy_deployment_group.foo", "ec2_tag_filter.2369538975.type", "KEY_AND_VALUE"),
resource.TestCheckResourceAttr( resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo", "ec2_tag_filter.2369538975.value", "anotherfiltervalue"), "aws_codedeploy_deployment_group.foo", "ec2_tag_filter.2369538975.value", "anotherfiltervalue"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo", "alarm_configuration.#", "0"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo", "auto_rollback_configuration.#", "0"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo", "trigger_configuration.#", "0"),
), ),
}, },
}, },
@ -223,6 +237,334 @@ func TestAccAWSCodeDeployDeploymentGroup_triggerConfiguration_multiple(t *testin
}) })
} }
func TestAccAWSCodeDeployDeploymentGroup_autoRollbackConfiguration_create(t *testing.T) {
var group codedeploy.DeploymentGroupInfo
rName := acctest.RandString(5)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSCodeDeployDeploymentGroupDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: test_config_auto_rollback_configuration_delete(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSCodeDeployDeploymentGroupExists("aws_codedeploy_deployment_group.foo_group", &group),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "auto_rollback_configuration.#", "0"),
),
},
resource.TestStep{
Config: test_config_auto_rollback_configuration_create(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSCodeDeployDeploymentGroupExists("aws_codedeploy_deployment_group.foo_group", &group),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "auto_rollback_configuration.#", "1"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "auto_rollback_configuration.0.enabled", "true"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "auto_rollback_configuration.0.events.#", "1"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "auto_rollback_configuration.0.events.135881253", "DEPLOYMENT_FAILURE"),
),
},
},
})
}
func TestAccAWSCodeDeployDeploymentGroup_autoRollbackConfiguration_update(t *testing.T) {
var group codedeploy.DeploymentGroupInfo
rName := acctest.RandString(5)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSCodeDeployDeploymentGroupDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: test_config_auto_rollback_configuration_create(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSCodeDeployDeploymentGroupExists("aws_codedeploy_deployment_group.foo_group", &group),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "auto_rollback_configuration.#", "1"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "auto_rollback_configuration.0.enabled", "true"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "auto_rollback_configuration.0.events.#", "1"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "auto_rollback_configuration.0.events.135881253", "DEPLOYMENT_FAILURE"),
),
},
resource.TestStep{
Config: test_config_auto_rollback_configuration_update(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSCodeDeployDeploymentGroupExists("aws_codedeploy_deployment_group.foo_group", &group),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "auto_rollback_configuration.#", "1"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "auto_rollback_configuration.0.enabled", "true"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "auto_rollback_configuration.0.events.#", "2"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "auto_rollback_configuration.0.events.104943466", "DEPLOYMENT_STOP_ON_ALARM"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "auto_rollback_configuration.0.events.135881253", "DEPLOYMENT_FAILURE"),
),
},
},
})
}
func TestAccAWSCodeDeployDeploymentGroup_autoRollbackConfiguration_delete(t *testing.T) {
var group codedeploy.DeploymentGroupInfo
rName := acctest.RandString(5)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSCodeDeployDeploymentGroupDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: test_config_auto_rollback_configuration_create(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSCodeDeployDeploymentGroupExists("aws_codedeploy_deployment_group.foo_group", &group),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "auto_rollback_configuration.#", "1"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "auto_rollback_configuration.0.enabled", "true"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "auto_rollback_configuration.0.events.#", "1"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "auto_rollback_configuration.0.events.135881253", "DEPLOYMENT_FAILURE"),
),
},
resource.TestStep{
Config: test_config_auto_rollback_configuration_delete(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSCodeDeployDeploymentGroupExists("aws_codedeploy_deployment_group.foo_group", &group),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "auto_rollback_configuration.#", "0"),
),
},
},
})
}
func TestAccAWSCodeDeployDeploymentGroup_autoRollbackConfiguration_disable(t *testing.T) {
var group codedeploy.DeploymentGroupInfo
rName := acctest.RandString(5)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSCodeDeployDeploymentGroupDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: test_config_auto_rollback_configuration_create(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSCodeDeployDeploymentGroupExists("aws_codedeploy_deployment_group.foo_group", &group),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "auto_rollback_configuration.#", "1"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "auto_rollback_configuration.0.enabled", "true"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "auto_rollback_configuration.0.events.#", "1"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "auto_rollback_configuration.0.events.135881253", "DEPLOYMENT_FAILURE"),
),
},
resource.TestStep{
Config: test_config_auto_rollback_configuration_disable(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSCodeDeployDeploymentGroupExists("aws_codedeploy_deployment_group.foo_group", &group),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "auto_rollback_configuration.#", "1"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "auto_rollback_configuration.0.enabled", "false"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "auto_rollback_configuration.0.events.#", "1"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "auto_rollback_configuration.0.events.135881253", "DEPLOYMENT_FAILURE"),
),
},
},
})
}
func TestAccAWSCodeDeployDeploymentGroup_alarmConfiguration_create(t *testing.T) {
var group codedeploy.DeploymentGroupInfo
rName := acctest.RandString(5)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSCodeDeployDeploymentGroupDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: test_config_alarm_configuration_delete(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSCodeDeployDeploymentGroupExists("aws_codedeploy_deployment_group.foo_group", &group),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "alarm_configuration.#", "0"),
),
},
resource.TestStep{
Config: test_config_alarm_configuration_create(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSCodeDeployDeploymentGroupExists("aws_codedeploy_deployment_group.foo_group", &group),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "alarm_configuration.#", "1"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "alarm_configuration.0.enabled", "true"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "alarm_configuration.0.alarms.#", "1"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "alarm_configuration.0.alarms.2356372769", "foo"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "alarm_configuration.0.ignore_poll_alarm_failure", "false"),
),
},
},
})
}
func TestAccAWSCodeDeployDeploymentGroup_alarmConfiguration_update(t *testing.T) {
var group codedeploy.DeploymentGroupInfo
rName := acctest.RandString(5)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSCodeDeployDeploymentGroupDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: test_config_alarm_configuration_create(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSCodeDeployDeploymentGroupExists("aws_codedeploy_deployment_group.foo_group", &group),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "alarm_configuration.#", "1"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "alarm_configuration.0.enabled", "true"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "alarm_configuration.0.alarms.#", "1"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "alarm_configuration.0.alarms.2356372769", "foo"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "alarm_configuration.0.ignore_poll_alarm_failure", "false"),
),
},
resource.TestStep{
Config: test_config_alarm_configuration_update(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSCodeDeployDeploymentGroupExists("aws_codedeploy_deployment_group.foo_group", &group),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "alarm_configuration.#", "1"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "alarm_configuration.0.enabled", "true"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "alarm_configuration.0.alarms.#", "2"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "alarm_configuration.0.alarms.1996459178", "bar"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "alarm_configuration.0.alarms.2356372769", "foo"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "alarm_configuration.0.ignore_poll_alarm_failure", "true"),
),
},
},
})
}
func TestAccAWSCodeDeployDeploymentGroup_alarmConfiguration_delete(t *testing.T) {
var group codedeploy.DeploymentGroupInfo
rName := acctest.RandString(5)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSCodeDeployDeploymentGroupDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: test_config_alarm_configuration_create(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSCodeDeployDeploymentGroupExists("aws_codedeploy_deployment_group.foo_group", &group),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "alarm_configuration.#", "1"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "alarm_configuration.0.enabled", "true"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "alarm_configuration.0.alarms.#", "1"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "alarm_configuration.0.alarms.2356372769", "foo"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "alarm_configuration.0.ignore_poll_alarm_failure", "false"),
),
},
resource.TestStep{
Config: test_config_alarm_configuration_delete(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSCodeDeployDeploymentGroupExists("aws_codedeploy_deployment_group.foo_group", &group),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "alarm_configuration.#", "0"),
),
},
},
})
}
func TestAccAWSCodeDeployDeploymentGroup_alarmConfiguration_disable(t *testing.T) {
var group codedeploy.DeploymentGroupInfo
rName := acctest.RandString(5)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSCodeDeployDeploymentGroupDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: test_config_alarm_configuration_create(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSCodeDeployDeploymentGroupExists("aws_codedeploy_deployment_group.foo_group", &group),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "alarm_configuration.#", "1"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "alarm_configuration.0.enabled", "true"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "alarm_configuration.0.alarms.#", "1"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "alarm_configuration.0.alarms.2356372769", "foo"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "alarm_configuration.0.ignore_poll_alarm_failure", "false"),
),
},
resource.TestStep{
Config: test_config_alarm_configuration_disable(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSCodeDeployDeploymentGroupExists("aws_codedeploy_deployment_group.foo_group", &group),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "alarm_configuration.#", "1"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "alarm_configuration.0.enabled", "false"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "alarm_configuration.0.alarms.#", "1"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "alarm_configuration.0.alarms.2356372769", "foo"),
resource.TestCheckResourceAttr(
"aws_codedeploy_deployment_group.foo_group", "alarm_configuration.0.ignore_poll_alarm_failure", "false"),
),
},
},
})
}
func TestValidateAWSCodeDeployTriggerEvent(t *testing.T) { func TestValidateAWSCodeDeployTriggerEvent(t *testing.T) {
cases := []struct { cases := []struct {
Value string Value string
@ -244,6 +586,10 @@ func TestValidateAWSCodeDeployTriggerEvent(t *testing.T) {
Value: "DeploymentFailure", Value: "DeploymentFailure",
ErrCount: 0, ErrCount: 0,
}, },
{
Value: "DeploymentRollback",
ErrCount: 0,
},
{ {
Value: "InstanceStart", Value: "InstanceStart",
ErrCount: 0, ErrCount: 0,
@ -356,6 +702,144 @@ func TestTriggerConfigsToMap(t *testing.T) {
} }
} }
func TestBuildAutoRollbackConfig(t *testing.T) {
input := []interface{}{
map[string]interface{}{
"events": schema.NewSet(schema.HashString, []interface{}{
"DEPLOYMENT_FAILURE",
}),
"enabled": true,
},
}
expected := &codedeploy.AutoRollbackConfiguration{
Events: []*string{
aws.String("DEPLOYMENT_FAILURE"),
},
Enabled: aws.Bool(true),
}
actual := buildAutoRollbackConfig(input)
if !reflect.DeepEqual(actual, expected) {
t.Fatalf("buildAutoRollbackConfig output is not correct.\nGot:\n%#v\nExpected:\n%#v\n",
actual, expected)
}
}
func TestAutoRollbackConfigToMap(t *testing.T) {
input := &codedeploy.AutoRollbackConfiguration{
Events: []*string{
aws.String("DEPLOYMENT_FAILURE"),
aws.String("DEPLOYMENT_STOP_ON_ALARM"),
},
Enabled: aws.Bool(false),
}
expected := map[string]interface{}{
"events": schema.NewSet(schema.HashString, []interface{}{
"DEPLOYMENT_FAILURE",
"DEPLOYMENT_STOP_ON_ALARM",
}),
"enabled": false,
}
actual := autoRollbackConfigToMap(input)[0]
fatal := false
if actual["enabled"] != expected["enabled"] {
fatal = true
}
actualEvents := actual["events"].(*schema.Set)
expectedEvents := expected["events"].(*schema.Set)
if !actualEvents.Equal(expectedEvents) {
fatal = true
}
if fatal {
t.Fatalf("autoRollbackConfigToMap output is not correct.\nGot:\n%#v\nExpected:\n%#v\n",
actual, expected)
}
}
func TestBuildAlarmConfig(t *testing.T) {
input := []interface{}{
map[string]interface{}{
"alarms": schema.NewSet(schema.HashString, []interface{}{
"foo-alarm",
}),
"enabled": true,
"ignore_poll_alarm_failure": false,
},
}
expected := &codedeploy.AlarmConfiguration{
Alarms: []*codedeploy.Alarm{
{
Name: aws.String("foo-alarm"),
},
},
Enabled: aws.Bool(true),
IgnorePollAlarmFailure: aws.Bool(false),
}
actual := buildAlarmConfig(input)
if !reflect.DeepEqual(actual, expected) {
t.Fatalf("buildAlarmConfig output is not correct.\nGot:\n%#v\nExpected:\n%#v\n",
actual, expected)
}
}
func TestAlarmConfigToMap(t *testing.T) {
input := &codedeploy.AlarmConfiguration{
Alarms: []*codedeploy.Alarm{
{
Name: aws.String("bar-alarm"),
},
{
Name: aws.String("foo-alarm"),
},
},
Enabled: aws.Bool(false),
IgnorePollAlarmFailure: aws.Bool(true),
}
expected := map[string]interface{}{
"alarms": schema.NewSet(schema.HashString, []interface{}{
"bar-alarm",
"foo-alarm",
}),
"enabled": false,
"ignore_poll_alarm_failure": true,
}
actual := alarmConfigToMap(input)[0]
fatal := false
if actual["enabled"] != expected["enabled"] {
fatal = true
}
if actual["ignore_poll_alarm_failure"] != expected["ignore_poll_alarm_failure"] {
fatal = true
}
actualAlarms := actual["alarms"].(*schema.Set)
expectedAlarms := expected["alarms"].(*schema.Set)
if !actualAlarms.Equal(expectedAlarms) {
fatal = true
}
if fatal {
t.Fatalf("alarmConfigToMap output is not correct.\nGot:\n%#v\nExpected:\n%#v\n",
actual, expected)
}
}
func testAccCheckTriggerEvents(group *codedeploy.DeploymentGroupInfo, triggerName string, expectedEvents []string) resource.TestCheckFunc { func testAccCheckTriggerEvents(group *codedeploy.DeploymentGroupInfo, triggerName string, expectedEvents []string) resource.TestCheckFunc {
return func(s *terraform.State) error { return func(s *terraform.State) error {
@ -748,7 +1232,7 @@ func testAccAWSCodeDeployDeploymentGroup_triggerConfiguration_create(rName strin
return fmt.Sprintf(` return fmt.Sprintf(`
%s %s
resource "aws_codedeploy_deployment_group" "foo_group" { resource "aws_codedeploy_deployment_group" "foo_group" {
app_name = "${aws_codedeploy_app.foo_app.name}" app_name = "${aws_codedeploy_app.foo_app.name}"
deployment_group_name = "foo-group-%s" deployment_group_name = "foo-group-%s"
@ -766,7 +1250,7 @@ func testAccAWSCodeDeployDeploymentGroup_triggerConfiguration_update(rName strin
return fmt.Sprintf(` return fmt.Sprintf(`
%s %s
resource "aws_codedeploy_deployment_group" "foo_group" { resource "aws_codedeploy_deployment_group" "foo_group" {
app_name = "${aws_codedeploy_app.foo_app.name}" app_name = "${aws_codedeploy_app.foo_app.name}"
deployment_group_name = "foo-group-%s" deployment_group_name = "foo-group-%s"
@ -784,7 +1268,7 @@ func testAccAWSCodeDeployDeploymentGroup_triggerConfiguration_createMultiple(rNa
return fmt.Sprintf(` return fmt.Sprintf(`
%s %s
resource "aws_sns_topic" "bar_topic" { resource "aws_sns_topic" "bar_topic" {
name = "bar-topic-%s" name = "bar-topic-%s"
} }
@ -812,7 +1296,7 @@ func testAccAWSCodeDeployDeploymentGroup_triggerConfiguration_updateMultiple(rNa
return fmt.Sprintf(` return fmt.Sprintf(`
%s %s
resource "aws_sns_topic" "bar_topic" { resource "aws_sns_topic" "bar_topic" {
name = "bar-topic-%s" name = "bar-topic-%s"
} }
@ -839,3 +1323,130 @@ resource "aws_codedeploy_deployment_group" "foo_group" {
} }
}`, baseCodeDeployConfig(rName), rName, rName, rName) }`, baseCodeDeployConfig(rName), rName, rName, rName)
} }
func test_config_auto_rollback_configuration_create(rName string) string {
return fmt.Sprintf(`
%s
resource "aws_codedeploy_deployment_group" "foo_group" {
app_name = "${aws_codedeploy_app.foo_app.name}"
deployment_group_name = "foo-group-%s"
service_role_arn = "${aws_iam_role.foo_role.arn}"
auto_rollback_configuration {
enabled = true
events = ["DEPLOYMENT_FAILURE"]
}
}`, baseCodeDeployConfig(rName), rName)
}
func test_config_auto_rollback_configuration_update(rName string) string {
return fmt.Sprintf(`
%s
resource "aws_codedeploy_deployment_group" "foo_group" {
app_name = "${aws_codedeploy_app.foo_app.name}"
deployment_group_name = "foo-group-%s"
service_role_arn = "${aws_iam_role.foo_role.arn}"
auto_rollback_configuration {
enabled = true
events = ["DEPLOYMENT_FAILURE", "DEPLOYMENT_STOP_ON_ALARM"]
}
}`, baseCodeDeployConfig(rName), rName)
}
func test_config_auto_rollback_configuration_delete(rName string) string {
return fmt.Sprintf(`
%s
resource "aws_codedeploy_deployment_group" "foo_group" {
app_name = "${aws_codedeploy_app.foo_app.name}"
deployment_group_name = "foo-group-%s"
service_role_arn = "${aws_iam_role.foo_role.arn}"
}`, baseCodeDeployConfig(rName), rName)
}
func test_config_auto_rollback_configuration_disable(rName string) string {
return fmt.Sprintf(`
%s
resource "aws_codedeploy_deployment_group" "foo_group" {
app_name = "${aws_codedeploy_app.foo_app.name}"
deployment_group_name = "foo-group-%s"
service_role_arn = "${aws_iam_role.foo_role.arn}"
auto_rollback_configuration {
enabled = false
events = ["DEPLOYMENT_FAILURE"]
}
}`, baseCodeDeployConfig(rName), rName)
}
func test_config_alarm_configuration_create(rName string) string {
return fmt.Sprintf(`
%s
resource "aws_codedeploy_deployment_group" "foo_group" {
app_name = "${aws_codedeploy_app.foo_app.name}"
deployment_group_name = "foo-group-%s"
service_role_arn = "${aws_iam_role.foo_role.arn}"
alarm_configuration {
alarms = ["foo"]
enabled = true
}
}`, baseCodeDeployConfig(rName), rName)
}
func test_config_alarm_configuration_update(rName string) string {
return fmt.Sprintf(`
%s
resource "aws_codedeploy_deployment_group" "foo_group" {
app_name = "${aws_codedeploy_app.foo_app.name}"
deployment_group_name = "foo-group-%s"
service_role_arn = "${aws_iam_role.foo_role.arn}"
alarm_configuration {
alarms = ["foo", "bar"]
enabled = true
ignore_poll_alarm_failure = true
}
}`, baseCodeDeployConfig(rName), rName)
}
func test_config_alarm_configuration_delete(rName string) string {
return fmt.Sprintf(`
%s
resource "aws_codedeploy_deployment_group" "foo_group" {
app_name = "${aws_codedeploy_app.foo_app.name}"
deployment_group_name = "foo-group-%s"
service_role_arn = "${aws_iam_role.foo_role.arn}"
}`, baseCodeDeployConfig(rName), rName)
}
func test_config_alarm_configuration_disable(rName string) string {
return fmt.Sprintf(`
%s
resource "aws_codedeploy_deployment_group" "foo_group" {
app_name = "${aws_codedeploy_app.foo_app.name}"
deployment_group_name = "foo-group-%s"
service_role_arn = "${aws_iam_role.foo_role.arn}"
alarm_configuration {
alarms = ["foo"]
enabled = false
}
}`, baseCodeDeployConfig(rName), rName)
}

View File

@ -82,6 +82,16 @@ resource "aws_codedeploy_deployment_group" "foo" {
trigger_name = "foo-trigger" trigger_name = "foo-trigger"
trigger_target_arn = "foo-topic-arn" trigger_target_arn = "foo-topic-arn"
} }
auto_rollback_configuration {
enabled = true
events = ["DEPLOYMENT_FAILURE"]
}
alarm_configuration {
alarms = ["my-alarm-name"]
enabled = true
}
} }
``` ```
@ -97,6 +107,8 @@ The following arguments are supported:
* `ec2_tag_filter` - (Optional) Tag filters associated with the group. See the AWS docs for details. * `ec2_tag_filter` - (Optional) Tag filters associated with the group. See the AWS docs for details.
* `on_premises_instance_tag_filter` - (Optional) On premise tag filters associated with the group. See the AWS docs for details. * `on_premises_instance_tag_filter` - (Optional) On premise tag filters associated with the group. See the AWS docs for details.
* `trigger_configuration` - (Optional) A Trigger Configuration block. Trigger Configurations are documented below. * `trigger_configuration` - (Optional) A Trigger Configuration block. Trigger Configurations are documented below.
* `auto_rollback_configuration` - (Optional) The automatic rollback configuration associated with the deployment group, documented below.
* `alarm_configuration` - (Optional) A list of alarms associated with the deployment group, documented below.
Both ec2_tag_filter and on_premises_tag_filter blocks support the following: Both ec2_tag_filter and on_premises_tag_filter blocks support the following:
@ -110,6 +122,19 @@ Add triggers to a Deployment Group to receive notifications about events related
* `trigger_name` - (Required) The name of the notification trigger. * `trigger_name` - (Required) The name of the notification trigger.
* `trigger_target_arn` - (Required) The ARN of the SNS topic through which notifications are sent. * `trigger_target_arn` - (Required) The ARN of the SNS topic through which notifications are sent.
You can configure a deployment group to automatically rollback when a deployment fails or when a monitoring threshold you specify is met. In this case, the last known good version of an application revision is deployed. Only one rollback configuration block is allowed.
* `enabled` - (Optional) Indicates whether a defined automatic rollback configuration is currently enabled for this Deployment Group. If you enable automatic rollback, you must specify at least one event type.
* `events` - (Optional) The event type or types that trigger a rollback. Supported types are `DEPLOYMENT_FAILURE` and `DEPLOYMENT_STOP_ON_ALARM`.
You can configure a deployment to stop when a CloudWatch alarm detects that a metric has fallen below or exceeded a defined threshold. Only one alarm configuration block is allowed.
* `alarms` - (Optional) A list of alarms configured for the deployment group. A maximum of 10 alarms can be added to a deployment group.
* `enabled` - (Optional) Indicates whether the alarm configuration is enabled. This option is useful when you want to temporarily deactivate alarm monitoring for a deployment group without having to add the same alarms again later.
* `ignore_poll_alarm_failure` - (Optional) Indicates whether a deployment should continue if information about the current state of alarms cannot be retrieved from CloudWatch. The default value is `false`.
* `true`: The deployment will proceed even if alarm status information can't be retrieved.
* `false`: The deployment will stop if alarm status information can't be retrieved.
## Attributes Reference ## Attributes Reference
The following attributes are exported: The following attributes are exported: