provider/aws: Add support for treat_missing_data to cloudwatch_metric_alarm (#13358)

* provider/aws: Add support for treat_missing_data to cloudwatch_metric_alarm

Fixes: #13263

```
% make testacc TEST=./builtin/providers/aws TESTARGS='-run=TestAccAWSCloudWatchMetricAlarm'
==> Checking that code complies with gofmt requirements...
go generate $(go list ./... | grep -v /terraform/vendor/)
2017/04/05 08:51:06 Generated command/internal_plugin_list.go
TF_ACC=1 go test ./builtin/providers/aws -v -run=TestAccAWSCloudWatchMetricAlarm -timeout 120m
=== RUN   TestAccAWSCloudWatchMetricAlarm_importBasic
--- PASS: TestAccAWSCloudWatchMetricAlarm_importBasic (23.93s)
=== RUN   TestAccAWSCloudWatchMetricAlarm_basic
--- PASS: TestAccAWSCloudWatchMetricAlarm_basic (27.81s)
=== RUN   TestAccAWSCloudWatchMetricAlarm_treatMissingData
--- PASS: TestAccAWSCloudWatchMetricAlarm_treatMissingData (43.39s)
=== RUN   TestAccAWSCloudWatchMetricAlarm_extendedStatistic
--- PASS: TestAccAWSCloudWatchMetricAlarm_extendedStatistic (26.80s)
=== RUN   TestAccAWSCloudWatchMetricAlarm_missingStatistic
--- PASS: TestAccAWSCloudWatchMetricAlarm_missingStatistic (5.95s)
PASS
ok  	github.com/hashicorp/terraform/builtin/providers/aws	127.899s
```

* provider/aws: Set cloudwatch_metric_alarm treamt_missing_data to missing

This follows what the AWS API does. We had to add a state migration for
this to make sure that the user doesn't see any unexpected activity on
their Terraform plans

```
% make testacc TEST=./builtin/providers/aws TESTARGS='-run=TestAWSCloudWatchMetricAlarmMigrateState'
==> Checking that code complies with gofmt requirements...
go generate $(go list ./... | grep -v /terraform/vendor/)
2017/04/05 14:51:32 Generated command/internal_plugin_list.go
TF_ACC=1 go test ./builtin/providers/aws -v -run=TestAWSCloudWatchMetricAlarmMigrateState -timeout 120m
=== RUN   TestAWSCloudWatchMetricAlarmMigrateState
2017/04/05 14:52:13 [INFO] Found AWS CloudWatch Metric Alarm State v0; migrating to v1
2017/04/05 14:52:13 [DEBUG] Attributes before migration: map[string]string{}
2017/04/05 14:52:13 [DEBUG] Attributes after migration: map[string]string{"treat_missing_data":"missing"}
--- PASS: TestAWSCloudWatchMetricAlarmMigrateState (0.00s)
PASS
ok  	github.com/hashicorp/terraform/builtin/providers/aws	0.018s
```
This commit is contained in:
Paul Stack 2017-04-05 13:17:47 +01:00 committed by GitHub
parent 2dbde462fe
commit d938d263f6
6 changed files with 183 additions and 21 deletions

View File

@ -3,10 +3,12 @@ package aws
import (
"testing"
"github.com/hashicorp/terraform/helper/acctest"
"github.com/hashicorp/terraform/helper/resource"
)
func TestAccAWSCloudWatchMetricAlarm_importBasic(t *testing.T) {
rInt := acctest.RandInt()
resourceName := "aws_cloudwatch_metric_alarm.foobar"
resource.Test(t, resource.TestCase{
@ -14,11 +16,11 @@ func TestAccAWSCloudWatchMetricAlarm_importBasic(t *testing.T) {
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSCloudWatchMetricAlarmDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccAWSCloudWatchMetricAlarmConfig,
{
Config: testAccAWSCloudWatchMetricAlarmConfig(rInt),
},
resource.TestStep{
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,

View File

@ -8,14 +8,18 @@ import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/cloudwatch"
"github.com/hashicorp/terraform/helper/validation"
)
func resourceAwsCloudWatchMetricAlarm() *schema.Resource {
return &schema.Resource{
Create: resourceAwsCloudWatchMetricAlarmCreate,
Read: resourceAwsCloudWatchMetricAlarmRead,
Update: resourceAwsCloudWatchMetricAlarmUpdate,
Delete: resourceAwsCloudWatchMetricAlarmDelete,
Create: resourceAwsCloudWatchMetricAlarmCreate,
Read: resourceAwsCloudWatchMetricAlarmRead,
Update: resourceAwsCloudWatchMetricAlarmUpdate,
Delete: resourceAwsCloudWatchMetricAlarmDelete,
SchemaVersion: 1,
MigrateState: resourceAwsCloudWatchMetricAlarmMigrateState,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},
@ -95,6 +99,12 @@ func resourceAwsCloudWatchMetricAlarm() *schema.Resource {
Optional: true,
ConflictsWith: []string{"statistic"},
},
"treat_missing_data": {
Type: schema.TypeString,
Optional: true,
Default: "missing",
ValidateFunc: validation.StringInSlice([]string{"breaching", "notBreaching", "ignore", "missing"}, true),
},
},
}
}
@ -161,6 +171,7 @@ func resourceAwsCloudWatchMetricAlarmRead(d *schema.ResourceData, meta interface
d.Set("threshold", a.Threshold)
d.Set("unit", a.Unit)
d.Set("extended_statistic", a.ExtendedStatistic)
d.Set("treat_missing_data", a.TreatMissingData)
return nil
}
@ -214,6 +225,7 @@ func getAwsCloudWatchPutMetricAlarmInput(d *schema.ResourceData) cloudwatch.PutM
Namespace: aws.String(d.Get("namespace").(string)),
Period: aws.Int64(int64(d.Get("period").(int))),
Threshold: aws.Float64(d.Get("threshold").(float64)),
TreatMissingData: aws.String(d.Get("treat_missing_data").(string)),
}
if v := d.Get("actions_enabled"); v != nil {

View File

@ -0,0 +1,33 @@
package aws
import (
"fmt"
"log"
"github.com/hashicorp/terraform/terraform"
)
func resourceAwsCloudWatchMetricAlarmMigrateState(
v int, is *terraform.InstanceState, meta interface{}) (*terraform.InstanceState, error) {
switch v {
case 0:
log.Println("[INFO] Found AWS CloudWatch Metric Alarm State v0; migrating to v1")
return migrateCloudWatchMetricAlarmStateV0toV1(is)
default:
return is, fmt.Errorf("Unexpected schema version: %d", v)
}
}
func migrateCloudWatchMetricAlarmStateV0toV1(is *terraform.InstanceState) (*terraform.InstanceState, error) {
if is.Empty() {
log.Println("[DEBUG] Empty InstanceState; nothing to migrate.")
return is, nil
}
log.Printf("[DEBUG] Attributes before migration: %#v", is.Attributes)
is.Attributes["treat_missing_data"] = "missing"
log.Printf("[DEBUG] Attributes after migration: %#v", is.Attributes)
return is, nil
}

View File

@ -0,0 +1,41 @@
package aws
import (
"testing"
"github.com/hashicorp/terraform/terraform"
)
func TestAWSCloudWatchMetricAlarmMigrateState(t *testing.T) {
cases := map[string]struct {
StateVersion int
ID string
Attributes map[string]string
Expected string
Meta interface{}
}{
"v0_1": {
StateVersion: 0,
ID: "some_id",
Attributes: map[string]string{},
Expected: "missing",
},
}
for tn, tc := range cases {
is := &terraform.InstanceState{
ID: tc.ID,
Attributes: tc.Attributes,
}
is, err := resourceAwsCloudWatchMetricAlarmMigrateState(
tc.StateVersion, is, tc.Meta)
if err != nil {
t.Fatalf("bad: %s, err: %#v", tn, err)
}
if is.Attributes["treat_missing_data"] != tc.Expected {
t.Fatalf("bad Cloudwatch Metric Alarm Migrate: %s\n\n expected: %s", is.Attributes["treat_missing_data"], tc.Expected)
}
}
}

View File

@ -7,20 +7,21 @@ import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/cloudwatch"
"github.com/hashicorp/terraform/helper/acctest"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
)
func TestAccAWSCloudWatchMetricAlarm_basic(t *testing.T) {
var alarm cloudwatch.MetricAlarm
rInt := acctest.RandInt()
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSCloudWatchMetricAlarmDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSCloudWatchMetricAlarmConfig,
Config: testAccAWSCloudWatchMetricAlarmConfig(rInt),
Check: resource.ComposeTestCheckFunc(
testAccCheckCloudWatchMetricAlarmExists("aws_cloudwatch_metric_alarm.foobar", &alarm),
resource.TestCheckResourceAttr("aws_cloudwatch_metric_alarm.foobar", "metric_name", "CPUUtilization"),
@ -33,8 +34,9 @@ func TestAccAWSCloudWatchMetricAlarm_basic(t *testing.T) {
})
}
func TestAccAWSCloudWatchMetricAlarm_extendedStatistic(t *testing.T) {
func TestAccAWSCloudWatchMetricAlarm_treatMissingData(t *testing.T) {
var alarm cloudwatch.MetricAlarm
rInt := acctest.RandInt()
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
@ -42,7 +44,34 @@ func TestAccAWSCloudWatchMetricAlarm_extendedStatistic(t *testing.T) {
CheckDestroy: testAccCheckAWSCloudWatchMetricAlarmDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSCloudWatchMetricAlarmConfigExtendedStatistic,
Config: testAccAWSCloudWatchMetricAlarmConfigTreatMissingData(rInt),
Check: resource.ComposeTestCheckFunc(
testAccCheckCloudWatchMetricAlarmExists("aws_cloudwatch_metric_alarm.foobar", &alarm),
resource.TestCheckResourceAttr("aws_cloudwatch_metric_alarm.foobar", "treat_missing_data", "missing"),
),
},
{
Config: testAccAWSCloudWatchMetricAlarmConfigTreatMissingDataUpdate(rInt),
Check: resource.ComposeTestCheckFunc(
testAccCheckCloudWatchMetricAlarmExists("aws_cloudwatch_metric_alarm.foobar", &alarm),
resource.TestCheckResourceAttr("aws_cloudwatch_metric_alarm.foobar", "treat_missing_data", "breaching"),
),
},
},
})
}
func TestAccAWSCloudWatchMetricAlarm_extendedStatistic(t *testing.T) {
var alarm cloudwatch.MetricAlarm
rInt := acctest.RandInt()
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSCloudWatchMetricAlarmDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSCloudWatchMetricAlarmConfigExtendedStatistic(rInt),
Check: resource.ComposeTestCheckFunc(
testAccCheckCloudWatchMetricAlarmExists("aws_cloudwatch_metric_alarm.foobar", &alarm),
resource.TestCheckResourceAttr("aws_cloudwatch_metric_alarm.foobar", "extended_statistic", "p88.0"),
@ -53,13 +82,14 @@ func TestAccAWSCloudWatchMetricAlarm_extendedStatistic(t *testing.T) {
}
func TestAccAWSCloudWatchMetricAlarm_missingStatistic(t *testing.T) {
rInt := acctest.RandInt()
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSCloudWatchMetricAlarmDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSCloudWatchMetricAlarmConfigMissingStatistic,
Config: testAccAWSCloudWatchMetricAlarmConfigMissingStatistic(rInt),
ExpectError: regexp.MustCompile("One of `statistic` or `extended_statistic` must be set for a cloudwatch metric alarm"),
},
},
@ -133,9 +163,10 @@ func testAccCheckAWSCloudWatchMetricAlarmDestroy(s *terraform.State) error {
return nil
}
var testAccAWSCloudWatchMetricAlarmConfig = fmt.Sprintf(`
func testAccAWSCloudWatchMetricAlarmConfig(rInt int) string {
return fmt.Sprintf(`
resource "aws_cloudwatch_metric_alarm" "foobar" {
alarm_name = "terraform-test-foobar5"
alarm_name = "terraform-test-foobar%d"
comparison_operator = "GreaterThanOrEqualToThreshold"
evaluation_periods = "2"
metric_name = "CPUUtilization"
@ -148,12 +179,53 @@ resource "aws_cloudwatch_metric_alarm" "foobar" {
dimensions {
InstanceId = "i-abc123"
}
}`, rInt)
}
`)
var testAccAWSCloudWatchMetricAlarmConfigExtendedStatistic = fmt.Sprintf(`
func testAccAWSCloudWatchMetricAlarmConfigTreatMissingData(rInt int) string {
return fmt.Sprintf(`
resource "aws_cloudwatch_metric_alarm" "foobar" {
alarm_name = "terraform-test-foobar6"
alarm_name = "terraform-test-foobar%d"
comparison_operator = "GreaterThanOrEqualToThreshold"
evaluation_periods = "2"
metric_name = "CPUUtilization"
namespace = "AWS/EC2"
period = "120"
statistic = "Average"
threshold = "80"
alarm_description = "This metric monitors ec2 cpu utilization"
treat_missing_data = "missing"
insufficient_data_actions = []
dimensions {
InstanceId = "i-abc123"
}
}`, rInt)
}
func testAccAWSCloudWatchMetricAlarmConfigTreatMissingDataUpdate(rInt int) string {
return fmt.Sprintf(`
resource "aws_cloudwatch_metric_alarm" "foobar" {
alarm_name = "terraform-test-foobar%d"
comparison_operator = "GreaterThanOrEqualToThreshold"
evaluation_periods = "2"
metric_name = "CPUUtilization"
namespace = "AWS/EC2"
period = "120"
statistic = "Average"
threshold = "80"
alarm_description = "This metric monitors ec2 cpu utilization"
treat_missing_data = "breaching"
insufficient_data_actions = []
dimensions {
InstanceId = "i-abc123"
}
}`, rInt)
}
func testAccAWSCloudWatchMetricAlarmConfigExtendedStatistic(rInt int) string {
return fmt.Sprintf(`
resource "aws_cloudwatch_metric_alarm" "foobar" {
alarm_name = "terraform-test-foobar%d"
comparison_operator = "GreaterThanOrEqualToThreshold"
evaluation_periods = "2"
metric_name = "CPUUtilization"
@ -166,12 +238,13 @@ resource "aws_cloudwatch_metric_alarm" "foobar" {
dimensions {
InstanceId = "i-abc123"
}
}`, rInt)
}
`)
var testAccAWSCloudWatchMetricAlarmConfigMissingStatistic = fmt.Sprintf(`
func testAccAWSCloudWatchMetricAlarmConfigMissingStatistic(rInt int) string {
return fmt.Sprintf(`
resource "aws_cloudwatch_metric_alarm" "foobar" {
alarm_name = "terraform-test-foobar6"
alarm_name = "terraform-test-foobar%d"
comparison_operator = "GreaterThanOrEqualToThreshold"
evaluation_periods = "2"
metric_name = "CPUUtilization"
@ -183,5 +256,5 @@ resource "aws_cloudwatch_metric_alarm" "foobar" {
dimensions {
InstanceId = "i-abc123"
}
}`, rInt)
}
`)

View File

@ -84,6 +84,7 @@ The following arguments are supported:
* `ok_actions` - (Optional) The list of actions to execute when this alarm transitions into an OK state from any other state. Each action is specified as an Amazon Resource Number (ARN).
* `unit` - (Optional) The unit for the alarm's associated metric.
* `extended_statistic` - (Optional) The percentile statistic for the metric associated with the alarm. Specify a value between p0.0 and p100.
* `treat_missing_data` - (Optional) Sets how this alarm is to handle missing data points. The following values are supported: `missing`, `ignore`, `breaching` and `notBreaching`. Defaults to `missing`.
## Attributes Reference