Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New Resource: aws_sns_sms_preferences #3858

Merged
merged 3 commits into from
May 11, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions aws/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,7 @@ func Provider() terraform.ResourceProvider {
"aws_sqs_queue_policy": resourceAwsSqsQueuePolicy(),
"aws_snapshot_create_volume_permission": resourceAwsSnapshotCreateVolumePermission(),
"aws_sns_platform_application": resourceAwsSnsPlatformApplication(),
"aws_sns_sms_preferences": resourceAwsSnsSmsPreferences(),
"aws_sns_topic": resourceAwsSnsTopic(),
"aws_sns_topic_policy": resourceAwsSnsTopicPolicy(),
"aws_sns_topic_subscription": resourceAwsSnsTopicSubscription(),
Expand Down
159 changes: 159 additions & 0 deletions aws/resource_aws_sns_sms_preferences.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
package aws

import (
"fmt"
"log"
"strconv"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/sns"
"github.com/hashicorp/terraform/helper/schema"
)

func resourceAwsSnsSmsPreferences() *schema.Resource {
return &schema.Resource{
Create: resourceAwsSnsSmsPreferencesSet,
Read: resourceAwsSnsSmsPreferencesGet,
Update: resourceAwsSnsSmsPreferencesSet,
Delete: resourceAwsSnsSmsPreferencesDelete,

Schema: map[string]*schema.Schema{
"monthly_spend_limit": {
Type: schema.TypeString,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This probably should be a TypeInt string so TF can do the proper type validation

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is tricky because the AWS API treats all those attributes as Strings, including monthly spend limit and delivery sampling rate, and an empty string "" (not defined) is not the same as a "0" (explicit 0).
Using int values in TF won't allow us to distinguish between the 2 cases and will always set those values as "0" when retrieved as "", which would be incorrect.

Optional: true,
},

"delivery_status_iam_role_arn": {
Type: schema.TypeString,
Optional: true,
},

"delivery_status_success_sampling_rate": {
Type: schema.TypeString,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This probably should be a TypeInt string so TF can do the proper type validation

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above comment

Optional: true,
},

"default_sender_id": {
Type: schema.TypeString,
Optional: true,
},

"default_sms_type": {
Type: schema.TypeString,
Optional: true,
},

"usage_report_s3_bucket": {
Type: schema.TypeString,
Optional: true,
},
},
}
}

const resourceId = "aws_sns_sms_id"

var SMSAttributeMap = map[string]string{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need to export this I don't think? (same with the var below as well)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, corrected

"monthly_spend_limit": "MonthlySpendLimit",
"delivery_status_iam_role_arn": "DeliveryStatusIAMRole",
"delivery_status_success_sampling_rate": "DeliveryStatusSuccessSamplingRate",
"default_sender_id": "DefaultSenderID",
"default_sms_type": "DefaultSMSType",
"usage_report_s3_bucket": "UsageReportS3Bucket",
}

var SMSAttributeDefaultValues = map[string]string{
"monthly_spend_limit": "",
"delivery_status_iam_role_arn": "",
"delivery_status_success_sampling_rate": "",
"default_sender_id": "",
"default_sms_type": "",
"usage_report_s3_bucket": "",
}

func resourceAwsSnsSmsPreferencesSet(d *schema.ResourceData, meta interface{}) error {
snsconn := meta.(*AWSClient).snsconn

log.Printf("[DEBUG] SNS Set SMS preferences")

monthlySpendLimit := d.Get("monthly_spend_limit").(string)
monthlySpendLimitInt, _ := strconv.Atoi(monthlySpendLimit)
deliveryStatusIamRoleArn := d.Get("delivery_status_iam_role_arn").(string)
deliveryStatusSuccessSamplingRate := d.Get("delivery_status_success_sampling_rate").(string)
deliveryStatusSuccessSamplingRateInt, _ := strconv.Atoi(deliveryStatusSuccessSamplingRate)
defaultSenderId := d.Get("default_sender_id").(string)
defaultSmsType := d.Get("default_sms_type").(string)
usageReportS3Bucket := d.Get("usage_report_s3_bucket").(string)

// Validation
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please move validation in to ValidateFunc in the schema above like this: https://github.com/terraform-providers/terraform-provider-aws/blob/3f9a830038f20f819ba947e90770c50d470d164b/aws/resource_aws_s3_bucket.go#L249

(for these other validations as well, more validations available in the validation package, int ranges, string in slice, etc)

if monthlySpendLimitInt < 0 {
return fmt.Errorf("Error setting SMS preferences: monthly spend limit value [%d] must be >= 0!", monthlySpendLimitInt)
}
if deliveryStatusSuccessSamplingRateInt < 0 || deliveryStatusSuccessSamplingRateInt > 100 {
return fmt.Errorf("Error setting SMS preferences: default percentage of success to sample value [%d] must be between 0 and 100!", deliveryStatusSuccessSamplingRateInt)
}
if defaultSmsType != "" && defaultSmsType != "Promotional" && defaultSmsType != "Transactional" {
return fmt.Errorf("Error setting SMS preferences: default SMS type value [%s] is invalid!", defaultSmsType)
}

// Set preferences
params := &sns.SetSMSAttributesInput{
Attributes: map[string]*string{
"MonthlySpendLimit": aws.String(monthlySpendLimit),
"DeliveryStatusIAMRole": aws.String(deliveryStatusIamRoleArn),
"DeliveryStatusSuccessSamplingRate": aws.String(deliveryStatusSuccessSamplingRate),
"DefaultSenderID": aws.String(defaultSenderId),
"DefaultSMSType": aws.String(defaultSmsType),
"UsageReportS3Bucket": aws.String(usageReportS3Bucket),
},
}

if _, err := snsconn.SetSMSAttributes(params); err != nil {
return fmt.Errorf("Error setting SMS preferences: %s", err)
}

d.SetId(resourceId)
return nil
}

func resourceAwsSnsSmsPreferencesGet(d *schema.ResourceData, meta interface{}) error {
snsconn := meta.(*AWSClient).snsconn

// Fetch ALL attributes
attrs, err := snsconn.GetSMSAttributes(&sns.GetSMSAttributesInput{})
if err != nil {
return err
}

// Reset with default values first
for tfAttrName, defValue := range SMSAttributeDefaultValues {
d.Set(tfAttrName, defValue)
}

// Apply existing settings
if attrs.Attributes != nil && len(attrs.Attributes) > 0 {
attrmap := attrs.Attributes
for tfAttrName, snsAttrName := range SMSAttributeMap {
d.Set(tfAttrName, attrmap[snsAttrName])
}
}

return nil
}

func resourceAwsSnsSmsPreferencesDelete(d *schema.ResourceData, meta interface{}) error {
snsconn := meta.(*AWSClient).snsconn

// Reset the attributes to their default value
attrs := map[string]*string{}
for tfAttrName, defValue := range SMSAttributeDefaultValues {
attrs[SMSAttributeMap[tfAttrName]] = &defValue
}

params := &sns.SetSMSAttributesInput{Attributes: attrs}
if _, err := snsconn.SetSMSAttributes(params); err != nil {
return fmt.Errorf("Error resetting SMS preferences: %s", err)
}

return nil
}
160 changes: 160 additions & 0 deletions aws/resource_aws_sns_sms_preferences_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
package aws

import (
"fmt"
"regexp"
"testing"

"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
)

func TestAccAWSSNSSMSPreferences_empty(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSSNSSMSPrefsDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccAWSSNSSMSPreferences_empty,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckNoResourceAttr("aws_sns_sms_preferences.test_pref", "monthly_spend_limit"),
resource.TestCheckNoResourceAttr("aws_sns_sms_preferences.test_pref", "delivery_status_iam_role_arn"),
resource.TestCheckNoResourceAttr("aws_sns_sms_preferences.test_pref", "delivery_status_success_sampling_rate"),
resource.TestCheckNoResourceAttr("aws_sns_sms_preferences.test_pref", "default_sender_id"),
resource.TestCheckNoResourceAttr("aws_sns_sms_preferences.test_pref", "default_sms_type"),
resource.TestCheckNoResourceAttr("aws_sns_sms_preferences.test_pref", "usage_report_s3_bucket"),
),
},
},
})
}

func TestAccAWSSNSSMSPreferences_defaultSMSType(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSSNSSMSPrefsDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccAWSSNSSMSPreferences_defSMSType,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckNoResourceAttr("aws_sns_sms_preferences.test_pref", "monthly_spend_limit"),
resource.TestCheckNoResourceAttr("aws_sns_sms_preferences.test_pref", "delivery_status_iam_role_arn"),
resource.TestCheckNoResourceAttr("aws_sns_sms_preferences.test_pref", "delivery_status_success_sampling_rate"),
resource.TestCheckNoResourceAttr("aws_sns_sms_preferences.test_pref", "default_sender_id"),
resource.TestCheckResourceAttr("aws_sns_sms_preferences.test_pref", "default_sms_type", "Transactional"),
resource.TestCheckNoResourceAttr("aws_sns_sms_preferences.test_pref", "usage_report_s3_bucket"),
),
},
},
})
}

func TestAccAWSSNSSMSPreferences_almostAll(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSSNSSMSPrefsDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccAWSSNSSMSPreferences_almostAll,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("aws_sns_sms_preferences.test_pref", "monthly_spend_limit", "1"),
resource.TestCheckResourceAttr("aws_sns_sms_preferences.test_pref", "default_sms_type", "Transactional"),
resource.TestCheckResourceAttr("aws_sns_sms_preferences.test_pref", "usage_report_s3_bucket", "some-bucket"),
),
},
},
})
}

func TestAccAWSSNSSMSPreferences_deliveryRole(t *testing.T) {
arnRole := regexp.MustCompile(`^arn:aws:iam::\d+:role/test_smsdelivery_role$`)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSSNSSMSPrefsDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccAWSSNSSMSPreferences_deliveryRole,
Check: resource.ComposeTestCheckFunc(
resource.TestMatchResourceAttr("aws_sns_sms_preferences.test_pref", "delivery_status_iam_role_arn", arnRole),
resource.TestCheckResourceAttr("aws_sns_sms_preferences.test_pref", "delivery_status_success_sampling_rate", "75"),
),
},
},
})
}

func testAccCheckAWSSNSSMSPrefsDestroy(s *terraform.State) error {
for _, rs := range s.RootModule().Resources {
if rs.Type != "aws_sns_sms_preferences" {
continue
}

return fmt.Errorf("SNS SMS Preferences resource exists when it should be destroyed!")
}

return nil
}

const testAccAWSSNSSMSPreferences_empty = `
resource "aws_sns_sms_preferences" "test_pref" {}
`
const testAccAWSSNSSMSPreferences_defSMSType = `
resource "aws_sns_sms_preferences" "test_pref" {
default_sms_type = "Transactional"
}
`
const testAccAWSSNSSMSPreferences_almostAll = `
resource "aws_sns_sms_preferences" "test_pref" {
monthly_spend_limit = "1",
default_sms_type = "Transactional",
usage_report_s3_bucket = "some-bucket",
}
`
const testAccAWSSNSSMSPreferences_deliveryRole = `
resource "aws_iam_role" "test_smsdelivery_role" {
name = "test_smsdelivery_role"
path = "/"
assume_role_policy = <<POLICY
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "sns.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
POLICY
}

resource "aws_iam_role_policy" "test_smsdelivery_role_policy" {
name = "test_smsdelivery_role_policy"
role = "${aws_iam_role.test_smsdelivery_role.id}"
policy = <<POLICY
{
"Version": "2012-10-17",
"Statement": [
{
"Action": ["logs:CreateLogGroup","logs:CreateLogStream","logs:PutLogEvents","logs:PutMetricFilter","logs:PutRetentionPolicy"],
"Resource": "*",
"Effect": "Allow",
"Sid": ""
}
]
}
POLICY
}

resource "aws_sns_sms_preferences" "test_pref" {
delivery_status_iam_role_arn = "${aws_iam_role.test_smsdelivery_role.arn}",
delivery_status_success_sampling_rate = "75",
}
`
30 changes: 30 additions & 0 deletions website/docs/r/sns_sms_peferences.html.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
layout: "aws"
page_title: "AWS: sns_sms_preferences"
sidebar_current: "docs-aws-resource-sns-sms-preferences"
description: |-
Provides a way to set SNS SMS preferences.
---

# aws_sns_sms_preferences

Provides a way to set SNS SMS preferences.

## Example Usage

```hcl
resource "aws_sns_sms_preferences" "update_sms_prefs" {

}
```

## Argument Reference

The following arguments are supported:

* `monthly_spend_limit` - (Optional) The maximum amount in USD that you are willing to spend each month to send SMS messages.
* `delivery_status_iam_role_arn` - (Optional) The ARN of the IAM role that allows Amazon SNS to write logs about SMS deliveries in CloudWatch Logs.
* `delivery_status_success_sampling_rate` - (Optional) The percentage of successful SMS deliveries for which Amazon SNS will write logs in CloudWatch Logs. The value must be between 0 and 100.
* `default_sender_id` - (Optional) A string, such as your business brand, that is displayed as the sender on the receiving device.
* `default_sms_type` - (Optional) The type of SMS message that you will send by default. Possible values are: Promotional, Transactional
* `usage_report_s3_bucket` - (Optional) The name of the Amazon S3 bucket to receive daily SMS usage reports from Amazon SNS.