Merge remote-tracking branch 'upstream/master' into f-aws-volume-attachment
* upstream/master: (21 commits) fix typo fix typo, use awslabs/aws-sdk-go Update CHANGELOG.md More internal links in template documentation. providers/aws: Requires ttl and records attributes if there isn't an ALIAS block. Condense switch fallthroughs into expr lists Fix docs for aws_route53_record params Update CHANGELOG.md provider/aws: Add IAM Server Certificate resource aws_db_instance docs updated per #2070 providers/aws: Adds link to AWS docs about RDS parameters. Downgrade middleman to 3.3.12 as 3.3.13 does not exist providers/aws: Clarifies db_security_group usage. "More more" no more! Indentation issue Export ARN in SQS queue and SNS topic / subscription; updated tests for new AWS SDK errors; updated documentation. Changed Required: false to Optional: true in the SNS topic schema Initial SNS support correct resource name in example added attributes reference section for AWS_EBS_VOLUME ...
This commit is contained in:
commit
3f68ea7d0e
|
@ -2,7 +2,10 @@
|
||||||
|
|
||||||
IMPROVEMENTS:
|
IMPROVEMENTS:
|
||||||
|
|
||||||
|
* **New resource: `aws_iam_server_certificate`** [GH-2086]
|
||||||
* **New resource: `aws_sqs_queue`** [GH-1939]
|
* **New resource: `aws_sqs_queue`** [GH-1939]
|
||||||
|
* **New resource: `aws_sns_topic`** [GH-1974]
|
||||||
|
* **New resource: `aws_sns_topic_subscription`** [GH-1974]
|
||||||
* provider/aws: support ec2 termination protection [GH-1988]
|
* provider/aws: support ec2 termination protection [GH-1988]
|
||||||
* provider/aws: support for RDS Read Replicas [GH-1946]
|
* provider/aws: support for RDS Read Replicas [GH-1946]
|
||||||
* provider/aws: `aws_s3_bucket` add support for `policy` [GH-1992]
|
* provider/aws: `aws_s3_bucket` add support for `policy` [GH-1992]
|
||||||
|
|
|
@ -18,6 +18,7 @@ import (
|
||||||
"github.com/awslabs/aws-sdk-go/service/route53"
|
"github.com/awslabs/aws-sdk-go/service/route53"
|
||||||
"github.com/awslabs/aws-sdk-go/service/s3"
|
"github.com/awslabs/aws-sdk-go/service/s3"
|
||||||
"github.com/awslabs/aws-sdk-go/service/sqs"
|
"github.com/awslabs/aws-sdk-go/service/sqs"
|
||||||
|
"github.com/awslabs/aws-sdk-go/service/sns"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
|
@ -37,6 +38,7 @@ type AWSClient struct {
|
||||||
autoscalingconn *autoscaling.AutoScaling
|
autoscalingconn *autoscaling.AutoScaling
|
||||||
s3conn *s3.S3
|
s3conn *s3.S3
|
||||||
sqsconn *sqs.SQS
|
sqsconn *sqs.SQS
|
||||||
|
snsconn *sns.SNS
|
||||||
r53conn *route53.Route53
|
r53conn *route53.Route53
|
||||||
region string
|
region string
|
||||||
rdsconn *rds.RDS
|
rdsconn *rds.RDS
|
||||||
|
@ -89,6 +91,9 @@ func (c *Config) Client() (interface{}, error) {
|
||||||
log.Println("[INFO] Initializing SQS connection")
|
log.Println("[INFO] Initializing SQS connection")
|
||||||
client.sqsconn = sqs.New(awsConfig)
|
client.sqsconn = sqs.New(awsConfig)
|
||||||
|
|
||||||
|
log.Println("[INFO] Initializing SNS connection")
|
||||||
|
client.snsconn = sns.New(awsConfig)
|
||||||
|
|
||||||
log.Println("[INFO] Initializing RDS Connection")
|
log.Println("[INFO] Initializing RDS Connection")
|
||||||
client.rdsconn = rds.New(awsConfig)
|
client.rdsconn = rds.New(awsConfig)
|
||||||
|
|
||||||
|
|
|
@ -103,6 +103,7 @@ func Provider() terraform.ResourceProvider {
|
||||||
"aws_iam_policy": resourceAwsIamPolicy(),
|
"aws_iam_policy": resourceAwsIamPolicy(),
|
||||||
"aws_iam_role_policy": resourceAwsIamRolePolicy(),
|
"aws_iam_role_policy": resourceAwsIamRolePolicy(),
|
||||||
"aws_iam_role": resourceAwsIamRole(),
|
"aws_iam_role": resourceAwsIamRole(),
|
||||||
|
"aws_iam_server_certificate": resourceAwsIAMServerCertificate(),
|
||||||
"aws_iam_user_policy": resourceAwsIamUserPolicy(),
|
"aws_iam_user_policy": resourceAwsIamUserPolicy(),
|
||||||
"aws_iam_user": resourceAwsIamUser(),
|
"aws_iam_user": resourceAwsIamUser(),
|
||||||
"aws_instance": resourceAwsInstance(),
|
"aws_instance": resourceAwsInstance(),
|
||||||
|
@ -123,6 +124,8 @@ func Provider() terraform.ResourceProvider {
|
||||||
"aws_security_group": resourceAwsSecurityGroup(),
|
"aws_security_group": resourceAwsSecurityGroup(),
|
||||||
"aws_security_group_rule": resourceAwsSecurityGroupRule(),
|
"aws_security_group_rule": resourceAwsSecurityGroupRule(),
|
||||||
"aws_sqs_queue": resourceAwsSqsQueue(),
|
"aws_sqs_queue": resourceAwsSqsQueue(),
|
||||||
|
"aws_sns_topic": resourceAwsSnsTopic(),
|
||||||
|
"aws_sns_topic_subscription": resourceAwsSnsTopicSubscription(),
|
||||||
"aws_subnet": resourceAwsSubnet(),
|
"aws_subnet": resourceAwsSubnet(),
|
||||||
"aws_volume_attachment": resourceAwsVolumeAttachment(),
|
"aws_volume_attachment": resourceAwsVolumeAttachment(),
|
||||||
"aws_vpc_dhcp_options_association": resourceAwsVpcDhcpOptionsAssociation(),
|
"aws_vpc_dhcp_options_association": resourceAwsVpcDhcpOptionsAssociation(),
|
||||||
|
|
|
@ -5,9 +5,9 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/awslabs/aws-sdk-go/aws"
|
||||||
"github.com/awslabs/aws-sdk-go/aws/awserr"
|
"github.com/awslabs/aws-sdk-go/aws/awserr"
|
||||||
"github.com/awslabs/aws-sdk-go/service/elasticache"
|
"github.com/awslabs/aws-sdk-go/service/elasticache"
|
||||||
"github.com/hashicorp/aws-sdk-go/aws"
|
|
||||||
"github.com/hashicorp/terraform/helper/hashcode"
|
"github.com/hashicorp/terraform/helper/hashcode"
|
||||||
"github.com/hashicorp/terraform/helper/resource"
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
"github.com/hashicorp/terraform/helper/schema"
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
|
|
|
@ -0,0 +1,147 @@
|
||||||
|
package aws
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/sha1"
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/awslabs/aws-sdk-go/aws"
|
||||||
|
"github.com/awslabs/aws-sdk-go/aws/awserr"
|
||||||
|
"github.com/awslabs/aws-sdk-go/service/iam"
|
||||||
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resourceAwsIAMServerCertificate() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
Create: resourceAwsIAMServerCertificateCreate,
|
||||||
|
Read: resourceAwsIAMServerCertificateRead,
|
||||||
|
Delete: resourceAwsIAMServerCertificateDelete,
|
||||||
|
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"certificate_body": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
StateFunc: normalizeCert,
|
||||||
|
},
|
||||||
|
|
||||||
|
"certificate_chain": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"path": &schema.Schema{
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"private_key": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
StateFunc: normalizeCert,
|
||||||
|
},
|
||||||
|
|
||||||
|
"name": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"arn": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceAwsIAMServerCertificateCreate(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
conn := meta.(*AWSClient).iamconn
|
||||||
|
|
||||||
|
createOpts := &iam.UploadServerCertificateInput{
|
||||||
|
CertificateBody: aws.String(d.Get("certificate_body").(string)),
|
||||||
|
PrivateKey: aws.String(d.Get("private_key").(string)),
|
||||||
|
ServerCertificateName: aws.String(d.Get("name").(string)),
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, ok := d.GetOk("certificate_chain"); ok {
|
||||||
|
createOpts.CertificateChain = aws.String(v.(string))
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, ok := d.GetOk("Path"); ok {
|
||||||
|
createOpts.Path = aws.String(v.(string))
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := conn.UploadServerCertificate(createOpts)
|
||||||
|
if err != nil {
|
||||||
|
if awsErr, ok := err.(awserr.Error); ok {
|
||||||
|
return fmt.Errorf("[WARN] Error uploading server certificate, error: %s: %s", awsErr.Code(), awsErr.Message())
|
||||||
|
}
|
||||||
|
return fmt.Errorf("[WARN] Error uploading server certificate, error: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetId(*resp.ServerCertificateMetadata.ServerCertificateID)
|
||||||
|
|
||||||
|
return resourceAwsIAMServerCertificateRead(d, meta)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceAwsIAMServerCertificateRead(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
conn := meta.(*AWSClient).iamconn
|
||||||
|
resp, err := conn.GetServerCertificate(&iam.GetServerCertificateInput{
|
||||||
|
ServerCertificateName: aws.String(d.Get("name").(string)),
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
if awsErr, ok := err.(awserr.Error); ok {
|
||||||
|
return fmt.Errorf("[WARN] Error reading IAM Server Certificate: %s: %s", awsErr.Code(), awsErr.Message())
|
||||||
|
}
|
||||||
|
return fmt.Errorf("[WARN] Error reading IAM Server Certificate: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// these values should always be present, and have a default if not set in
|
||||||
|
// configuration, and so safe to reference with nil checks
|
||||||
|
d.Set("certificate_body", normalizeCert(resp.ServerCertificate.CertificateBody))
|
||||||
|
d.Set("certificate_chain", resp.ServerCertificate.CertificateChain)
|
||||||
|
d.Set("path", resp.ServerCertificate.ServerCertificateMetadata.Path)
|
||||||
|
d.Set("arn", resp.ServerCertificate.ServerCertificateMetadata.ARN)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceAwsIAMServerCertificateDelete(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
conn := meta.(*AWSClient).iamconn
|
||||||
|
_, err := conn.DeleteServerCertificate(&iam.DeleteServerCertificateInput{
|
||||||
|
ServerCertificateName: aws.String(d.Get("name").(string)),
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
if awsErr, ok := err.(awserr.Error); ok {
|
||||||
|
return fmt.Errorf("[WARN] Error deleting server certificate: %s: %s", awsErr.Code(), awsErr.Message())
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetId("")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func normalizeCert(cert interface{}) string {
|
||||||
|
if cert == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
switch cert.(type) {
|
||||||
|
case string:
|
||||||
|
hash := sha1.Sum([]byte(strings.TrimSpace(cert.(string))))
|
||||||
|
return hex.EncodeToString(hash[:])
|
||||||
|
case *string:
|
||||||
|
hash := sha1.Sum([]byte(strings.TrimSpace(*cert.(*string))))
|
||||||
|
return hex.EncodeToString(hash[:])
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,194 @@
|
||||||
|
package aws
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/awslabs/aws-sdk-go/aws"
|
||||||
|
"github.com/awslabs/aws-sdk-go/service/iam"
|
||||||
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
|
"github.com/hashicorp/terraform/terraform"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAccIAMServerCertificate_basic(t *testing.T) {
|
||||||
|
var cert iam.ServerCertificate
|
||||||
|
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccCheckIAMServerCertificateDestroy,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccIAMServerCertConfig,
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckCertExists("aws_iam_server_certificate.test_cert", &cert),
|
||||||
|
testAccCheckAWSServerCertAttributes(&cert),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckCertExists(n string, cert *iam.ServerCertificate) resource.TestCheckFunc {
|
||||||
|
return func(s *terraform.State) error {
|
||||||
|
rs, ok := s.RootModule().Resources[n]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Not found: %s", n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if rs.Primary.ID == "" {
|
||||||
|
return fmt.Errorf("No Server Cert ID is set")
|
||||||
|
}
|
||||||
|
|
||||||
|
conn := testAccProvider.Meta().(*AWSClient).iamconn
|
||||||
|
describeOpts := &iam.GetServerCertificateInput{
|
||||||
|
ServerCertificateName: aws.String(rs.Primary.Attributes["name"]),
|
||||||
|
}
|
||||||
|
resp, err := conn.GetServerCertificate(describeOpts)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
*cert = *resp.ServerCertificate
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckAWSServerCertAttributes(cert *iam.ServerCertificate) resource.TestCheckFunc {
|
||||||
|
return func(s *terraform.State) error {
|
||||||
|
if !strings.HasPrefix(*cert.ServerCertificateMetadata.ServerCertificateName, "terraform-test-cert") {
|
||||||
|
return fmt.Errorf("Bad Server Cert Name: %s", *cert.ServerCertificateMetadata.ServerCertificateName)
|
||||||
|
}
|
||||||
|
|
||||||
|
if *cert.CertificateBody != strings.TrimSpace(certBody) {
|
||||||
|
return fmt.Errorf("Bad Server Cert body\n\t expected: %s\n\tgot: %s\n", certBody, *cert.CertificateBody)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckIAMServerCertificateDestroy(s *terraform.State) error {
|
||||||
|
conn := testAccProvider.Meta().(*AWSClient).iamconn
|
||||||
|
|
||||||
|
for _, rs := range s.RootModule().Resources {
|
||||||
|
if rs.Type != "aws_iam_server_certificate" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to find the Cert
|
||||||
|
opts := &iam.GetServerCertificateInput{
|
||||||
|
ServerCertificateName: aws.String(rs.Primary.Attributes["name"]),
|
||||||
|
}
|
||||||
|
resp, err := conn.GetServerCertificate(opts)
|
||||||
|
if err == nil {
|
||||||
|
if resp.ServerCertificate != nil {
|
||||||
|
return fmt.Errorf("Error: Server Cert still exists")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var certBody = fmt.Sprintf(`
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIExDCCA6ygAwIBAgIJALX7Jt7ddT3eMA0GCSqGSIb3DQEBBQUAMIGcMQswCQYD
|
||||||
|
VQQGEwJVUzERMA8GA1UECBMITWlzc291cmkxETAPBgNVBAcTCENvbHVtYmlhMRIw
|
||||||
|
EAYDVQQKEwlIYXNoaUNvcnAxEjAQBgNVBAsTCVRlcnJhZm9ybTEbMBkGA1UEAxMS
|
||||||
|
d3d3Lm5vdGV4YW1wbGUuY29tMSIwIAYJKoZIhvcNAQkBFhNjbGludEBoYXNoaWNv
|
||||||
|
cnAuY29tMB4XDTE1MDUyNjE0MzA1MloXDTE4MDUyNTE0MzA1MlowgZwxCzAJBgNV
|
||||||
|
BAYTAlVTMREwDwYDVQQIEwhNaXNzb3VyaTERMA8GA1UEBxMIQ29sdW1iaWExEjAQ
|
||||||
|
BgNVBAoTCUhhc2hpQ29ycDESMBAGA1UECxMJVGVycmFmb3JtMRswGQYDVQQDExJ3
|
||||||
|
d3cubm90ZXhhbXBsZS5jb20xIjAgBgkqhkiG9w0BCQEWE2NsaW50QGhhc2hpY29y
|
||||||
|
cC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCownyOIKXBbYxh
|
||||||
|
PynVAw30eaJj2OmilFJagwGeFHMT0rErCodY8lAQsPz6gj83NC9D4MzDt1H+GmoR
|
||||||
|
MSDphJEUxxTxvaNWTTN5sZ9WvE+sbw5YkkTXc4DmVsVMoa3urQO20f0tcHXyULj0
|
||||||
|
sXbtG+q/QhKxqeFjYON46Z6l7x32d/cj4mIcXwLpIf+W2wpvXCKAc8851skJ+O9W
|
||||||
|
UW0/h/ivwwkKfzGfiObL16IUaq+fxwnkYt3fUI2Z4rSKAULMEcquzfKr3JR6wkeI
|
||||||
|
J66ZSb6fMNlCPGPcINDhzwSgGRpqRqeuRl4Z9m2fZaaYVltHqjwDH1tKr+3qXFnv
|
||||||
|
nZmq7pzJAgMBAAGjggEFMIIBATAdBgNVHQ4EFgQUO8bEvPq+V/rtnlhTxQDusR7o
|
||||||
|
n6QwgdEGA1UdIwSByTCBxoAUO8bEvPq+V/rtnlhTxQDusR7on6ShgaKkgZ8wgZwx
|
||||||
|
CzAJBgNVBAYTAlVTMREwDwYDVQQIEwhNaXNzb3VyaTERMA8GA1UEBxMIQ29sdW1i
|
||||||
|
aWExEjAQBgNVBAoTCUhhc2hpQ29ycDESMBAGA1UECxMJVGVycmFmb3JtMRswGQYD
|
||||||
|
VQQDExJ3d3cubm90ZXhhbXBsZS5jb20xIjAgBgkqhkiG9w0BCQEWE2NsaW50QGhh
|
||||||
|
c2hpY29ycC5jb22CCQC1+ybe3XU93jAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEB
|
||||||
|
BQUAA4IBAQBsJ/NP1uBYm+8ejrpUu2mipT5JfBahpiUxef5BeubSrSM3zmdrtLLA
|
||||||
|
+DdDkrt0AfOaasBXMTEwrR3NunBAmn/6PX0r/PAjlqk/tOVBnASC9t3cmi88fO10
|
||||||
|
gQw+se86MiCr/hTavq2YTQZ652+ksjxeQwyHIzKrYS/rRGPKKHX70H5Asb1CY44p
|
||||||
|
/GRyLvAckzZ1Gp64ym6XCLTS53wOur6wLX1/lqshBo2utUmm/2a/XF4psSDx/k2J
|
||||||
|
E2oHzGoJ2F/+QkiXHzvPcUXRFVhXkQnZDocCv/nhcEwNkN9Z1OxCNqsZw+FiJm2E
|
||||||
|
FVSdVaOstOHOVllblhWxvjm55a44feFX
|
||||||
|
-----END CERTIFICATE-----`)
|
||||||
|
|
||||||
|
var testAccIAMServerCertConfig = fmt.Sprintf(`
|
||||||
|
resource "aws_iam_server_certificate" "test_cert" {
|
||||||
|
name = "terraform-test-cert-%d"
|
||||||
|
certificate_body = <<EOF
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIExDCCA6ygAwIBAgIJALX7Jt7ddT3eMA0GCSqGSIb3DQEBBQUAMIGcMQswCQYD
|
||||||
|
VQQGEwJVUzERMA8GA1UECBMITWlzc291cmkxETAPBgNVBAcTCENvbHVtYmlhMRIw
|
||||||
|
EAYDVQQKEwlIYXNoaUNvcnAxEjAQBgNVBAsTCVRlcnJhZm9ybTEbMBkGA1UEAxMS
|
||||||
|
d3d3Lm5vdGV4YW1wbGUuY29tMSIwIAYJKoZIhvcNAQkBFhNjbGludEBoYXNoaWNv
|
||||||
|
cnAuY29tMB4XDTE1MDUyNjE0MzA1MloXDTE4MDUyNTE0MzA1MlowgZwxCzAJBgNV
|
||||||
|
BAYTAlVTMREwDwYDVQQIEwhNaXNzb3VyaTERMA8GA1UEBxMIQ29sdW1iaWExEjAQ
|
||||||
|
BgNVBAoTCUhhc2hpQ29ycDESMBAGA1UECxMJVGVycmFmb3JtMRswGQYDVQQDExJ3
|
||||||
|
d3cubm90ZXhhbXBsZS5jb20xIjAgBgkqhkiG9w0BCQEWE2NsaW50QGhhc2hpY29y
|
||||||
|
cC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCownyOIKXBbYxh
|
||||||
|
PynVAw30eaJj2OmilFJagwGeFHMT0rErCodY8lAQsPz6gj83NC9D4MzDt1H+GmoR
|
||||||
|
MSDphJEUxxTxvaNWTTN5sZ9WvE+sbw5YkkTXc4DmVsVMoa3urQO20f0tcHXyULj0
|
||||||
|
sXbtG+q/QhKxqeFjYON46Z6l7x32d/cj4mIcXwLpIf+W2wpvXCKAc8851skJ+O9W
|
||||||
|
UW0/h/ivwwkKfzGfiObL16IUaq+fxwnkYt3fUI2Z4rSKAULMEcquzfKr3JR6wkeI
|
||||||
|
J66ZSb6fMNlCPGPcINDhzwSgGRpqRqeuRl4Z9m2fZaaYVltHqjwDH1tKr+3qXFnv
|
||||||
|
nZmq7pzJAgMBAAGjggEFMIIBATAdBgNVHQ4EFgQUO8bEvPq+V/rtnlhTxQDusR7o
|
||||||
|
n6QwgdEGA1UdIwSByTCBxoAUO8bEvPq+V/rtnlhTxQDusR7on6ShgaKkgZ8wgZwx
|
||||||
|
CzAJBgNVBAYTAlVTMREwDwYDVQQIEwhNaXNzb3VyaTERMA8GA1UEBxMIQ29sdW1i
|
||||||
|
aWExEjAQBgNVBAoTCUhhc2hpQ29ycDESMBAGA1UECxMJVGVycmFmb3JtMRswGQYD
|
||||||
|
VQQDExJ3d3cubm90ZXhhbXBsZS5jb20xIjAgBgkqhkiG9w0BCQEWE2NsaW50QGhh
|
||||||
|
c2hpY29ycC5jb22CCQC1+ybe3XU93jAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEB
|
||||||
|
BQUAA4IBAQBsJ/NP1uBYm+8ejrpUu2mipT5JfBahpiUxef5BeubSrSM3zmdrtLLA
|
||||||
|
+DdDkrt0AfOaasBXMTEwrR3NunBAmn/6PX0r/PAjlqk/tOVBnASC9t3cmi88fO10
|
||||||
|
gQw+se86MiCr/hTavq2YTQZ652+ksjxeQwyHIzKrYS/rRGPKKHX70H5Asb1CY44p
|
||||||
|
/GRyLvAckzZ1Gp64ym6XCLTS53wOur6wLX1/lqshBo2utUmm/2a/XF4psSDx/k2J
|
||||||
|
E2oHzGoJ2F/+QkiXHzvPcUXRFVhXkQnZDocCv/nhcEwNkN9Z1OxCNqsZw+FiJm2E
|
||||||
|
FVSdVaOstOHOVllblhWxvjm55a44feFX
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
EOF
|
||||||
|
|
||||||
|
private_key = <<EOF
|
||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIEowIBAAKCAQEAqMJ8jiClwW2MYT8p1QMN9HmiY9jpopRSWoMBnhRzE9KxKwqH
|
||||||
|
WPJQELD8+oI/NzQvQ+DMw7dR/hpqETEg6YSRFMcU8b2jVk0zebGfVrxPrG8OWJJE
|
||||||
|
13OA5lbFTKGt7q0DttH9LXB18lC49LF27Rvqv0ISsanhY2DjeOmepe8d9nf3I+Ji
|
||||||
|
HF8C6SH/ltsKb1wigHPPOdbJCfjvVlFtP4f4r8MJCn8xn4jmy9eiFGqvn8cJ5GLd
|
||||||
|
31CNmeK0igFCzBHKrs3yq9yUesJHiCeumUm+nzDZQjxj3CDQ4c8EoBkaakanrkZe
|
||||||
|
GfZtn2WmmFZbR6o8Ax9bSq/t6lxZ752Zqu6cyQIDAQABAoIBAFq2kHVlnzPmSvtL
|
||||||
|
FJVn2ux7JYs+Yff+enYkzY3HuEQDkTBtrGtndRpDyPhvYsOtzWpTQD5EIFLSqAkt
|
||||||
|
u19K3yGoEd4P7ejJ/s1/aQMankk2OSPrHA4kDDnEkrGqhvAxGDoBjnIKbZwfQAxo
|
||||||
|
CGFUDE9amOnfQ0REJIIuMhVH/3coDbsLUQstf43xU0Hl8C7vEPZ0WjX0LKZJsQEg
|
||||||
|
TVp4kF/ohxCsl/rtasrrCTIEWLgsqzYoIs5EivxZR6FwudaM3C/Dlcad3rISHXCe
|
||||||
|
w+dBWhIKqr7c695wkbtKb9x44hAKYAZdPG2eupy+SlQhm1mkl3aV3g6ylwEwhMJW
|
||||||
|
8nV3WcECgYEA0phtwHvXhRuSaCjTHAMf3DBqi8GDg+x9oKDPpFNROjot/rUqkfX8
|
||||||
|
vpHR7roN5bqX/4nDe/CfJE5UmJBbGcKXburRkwRqteT30N3qx9X+Yla9lPXbKo2F
|
||||||
|
TE+jQO5oZ7IdKdycyPOoFvlB0RB8c7pLwXlwWaybvb/2sqEcL0a3zW0CgYEAzST7
|
||||||
|
6YXMKKNvbw9vivm+LenpV6BVk5SOLXbMWtKmOjKLmc2dlD38jL2ZTlWzTbbAncta
|
||||||
|
Kkd4hDwH7rnXueMWwJjhRXKweNG5BsNhSl0NyQeujzHmxT54wGS8nYk48xGZuMNa
|
||||||
|
F0tfodJ2OA2IzyQHHzZ7YJPt85533Wj9CPt4P00CgYBi6T7bIg9msD2CeHI2/Oyw
|
||||||
|
4XiZbWlUw/V5RS5hUtSa0Yqa0AJPjcaIxzpfsrkmRg5v8geDpc9JIRUwltSC89dm
|
||||||
|
PBn0wCVSi1ktm51TAJo7G9xtI1At20xZPCpEK/WThp+V8s0cwPwY1jdodyLMxBoi
|
||||||
|
o+P16lE3vPqkiXEQb1mSvQKBgQCRLddJkHLHX8KA6n+Z7tx0SdHlPYbShpOIAUbm
|
||||||
|
D6WsEhFRq34VZzjPsW5JTcUy/l6aTUtmGGZlzsYeYE8XMmrrqkXijCPvnRxAeQzl
|
||||||
|
P619033pwPr8JBX4slH5ex9ehdowM7ASRDlNoFAhoxJq5ahUoo317zq66i8R9jb8
|
||||||
|
oFqdEQKBgCKhmR2NCfeVuklmnGGKOqpHD5IUnirmsm6/AtIk4HOR7NO+YOEmw9QN
|
||||||
|
0bOSNJPRbWAAZtvWT9/eJi61cAm2UhGN8iTSEWM+ixAn8v+9G+KzcNjccZu39ZCf
|
||||||
|
GWrW9VPbefh6Bhfdh34IQexYbivSxvi4ZZB4lJ8ce0rPJihQILBl
|
||||||
|
-----END RSA PRIVATE KEY-----
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
`, rand.New(rand.NewSource(time.Now().UnixNano())).Int())
|
|
@ -380,6 +380,14 @@ func resourceAwsRoute53RecordBuildSet(d *schema.ResourceData, zoneName string) (
|
||||||
HostedZoneID: aws.String(alias["zone_id"].(string)),
|
HostedZoneID: aws.String(alias["zone_id"].(string)),
|
||||||
}
|
}
|
||||||
log.Printf("[DEBUG] Creating alias: %#v", alias)
|
log.Printf("[DEBUG] Creating alias: %#v", alias)
|
||||||
|
} else {
|
||||||
|
if _, ok := d.GetOk("ttl"); !ok {
|
||||||
|
return nil, fmt.Errorf(`provider.aws: aws_route53_record: %s: "ttl": required field is not set`, d.Get("name").(string))
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := d.GetOk("records"); !ok {
|
||||||
|
return nil, fmt.Errorf(`provider.aws: aws_route53_record: %s: "records": required field is not set`, d.Get("name").(string))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if v, ok := d.GetOk("weight"); ok {
|
if v, ok := d.GetOk("weight"); ok {
|
||||||
|
|
|
@ -0,0 +1,153 @@
|
||||||
|
package aws
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
|
|
||||||
|
"github.com/awslabs/aws-sdk-go/aws"
|
||||||
|
"github.com/awslabs/aws-sdk-go/service/sns"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Mutable attributes
|
||||||
|
var SNSAttributeMap = map[string]string{
|
||||||
|
"display_name" : "DisplayName",
|
||||||
|
"policy" : "Policy",
|
||||||
|
"delivery_policy": "DeliveryPolicy",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func resourceAwsSnsTopic() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
Create: resourceAwsSnsTopicCreate,
|
||||||
|
Read: resourceAwsSnsTopicRead,
|
||||||
|
Update: resourceAwsSnsTopicUpdate,
|
||||||
|
Delete: resourceAwsSnsTopicDelete,
|
||||||
|
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"name": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
"display_name": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: false,
|
||||||
|
},
|
||||||
|
"policy": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: false,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"delivery_policy": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: false,
|
||||||
|
},
|
||||||
|
"arn": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceAwsSnsTopicCreate(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
snsconn := meta.(*AWSClient).snsconn
|
||||||
|
|
||||||
|
name := d.Get("name").(string)
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] SNS create topic: %s", name)
|
||||||
|
|
||||||
|
req := &sns.CreateTopicInput{
|
||||||
|
Name: aws.String(name),
|
||||||
|
}
|
||||||
|
|
||||||
|
output, err := snsconn.CreateTopic(req)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error creating SNS topic: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetId(*output.TopicARN)
|
||||||
|
|
||||||
|
// Write the ARN to the 'arn' field for export
|
||||||
|
d.Set("arn", *output.TopicARN)
|
||||||
|
|
||||||
|
return resourceAwsSnsTopicUpdate(d, meta)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceAwsSnsTopicUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
snsconn := meta.(*AWSClient).snsconn
|
||||||
|
|
||||||
|
resource := *resourceAwsSnsTopic()
|
||||||
|
|
||||||
|
for k, _ := range resource.Schema {
|
||||||
|
if attrKey, ok := SNSAttributeMap[k]; ok {
|
||||||
|
if d.HasChange(k) {
|
||||||
|
log.Printf("[DEBUG] Updating %s", attrKey)
|
||||||
|
_, n := d.GetChange(k)
|
||||||
|
// Ignore an empty policy
|
||||||
|
if !(k == "policy" && n == "") {
|
||||||
|
// Make API call to update attributes
|
||||||
|
req := &sns.SetTopicAttributesInput{
|
||||||
|
TopicARN: aws.String(d.Id()),
|
||||||
|
AttributeName: aws.String(attrKey),
|
||||||
|
AttributeValue: aws.String(n.(string)),
|
||||||
|
}
|
||||||
|
snsconn.SetTopicAttributes(req)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resourceAwsSnsTopicRead(d, meta)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceAwsSnsTopicRead(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
snsconn := meta.(*AWSClient).snsconn
|
||||||
|
|
||||||
|
attributeOutput, err := snsconn.GetTopicAttributes(&sns.GetTopicAttributesInput{
|
||||||
|
TopicARN: aws.String(d.Id()),
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if attributeOutput.Attributes != nil && len(*attributeOutput.Attributes) > 0 {
|
||||||
|
attrmap := *attributeOutput.Attributes
|
||||||
|
resource := *resourceAwsSnsTopic()
|
||||||
|
// iKey = internal struct key, oKey = AWS Attribute Map key
|
||||||
|
for iKey, oKey := range SNSAttributeMap {
|
||||||
|
log.Printf("[DEBUG] Updating %s => %s", iKey, oKey)
|
||||||
|
|
||||||
|
if attrmap[oKey] != nil {
|
||||||
|
// Some of the fetched attributes are stateful properties such as
|
||||||
|
// the number of subscriptions, the owner, etc. skip those
|
||||||
|
if resource.Schema[iKey] != nil {
|
||||||
|
value := *attrmap[oKey]
|
||||||
|
log.Printf("[DEBUG] Updating %s => %s -> %s", iKey, oKey, value)
|
||||||
|
d.Set(iKey, *attrmap[oKey])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceAwsSnsTopicDelete(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
snsconn := meta.(*AWSClient).snsconn
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] SNS Delete Topic: %s", d.Id())
|
||||||
|
_, err := snsconn.DeleteTopic(&sns.DeleteTopicInput{
|
||||||
|
TopicARN: aws.String(d.Id()),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,181 @@
|
||||||
|
package aws
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
|
|
||||||
|
"github.com/awslabs/aws-sdk-go/aws"
|
||||||
|
"github.com/awslabs/aws-sdk-go/service/sns"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
func resourceAwsSnsTopicSubscription() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
Create: resourceAwsSnsTopicSubscriptionCreate,
|
||||||
|
Read: resourceAwsSnsTopicSubscriptionRead,
|
||||||
|
Update: resourceAwsSnsTopicSubscriptionUpdate,
|
||||||
|
Delete: resourceAwsSnsTopicSubscriptionDelete,
|
||||||
|
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"protocol": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: false,
|
||||||
|
},
|
||||||
|
"endpoint": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: false,
|
||||||
|
},
|
||||||
|
"topic_arn": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: false,
|
||||||
|
},
|
||||||
|
"delivery_policy": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: false,
|
||||||
|
},
|
||||||
|
"raw_message_delivery": &schema.Schema{
|
||||||
|
Type: schema.TypeBool,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: false,
|
||||||
|
Default: false,
|
||||||
|
},
|
||||||
|
"arn": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceAwsSnsTopicSubscriptionCreate(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
snsconn := meta.(*AWSClient).snsconn
|
||||||
|
|
||||||
|
if(d.Get("protocol") == "email") {
|
||||||
|
return fmt.Errorf("Email endpoints are not supported!")
|
||||||
|
}
|
||||||
|
|
||||||
|
output, err := subscribeToSNSTopic(d, snsconn)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("New subscription ARN: %s", *output.SubscriptionARN)
|
||||||
|
d.SetId(*output.SubscriptionARN)
|
||||||
|
|
||||||
|
// Write the ARN to the 'arn' field for export
|
||||||
|
d.Set("arn", *output.SubscriptionARN)
|
||||||
|
|
||||||
|
return resourceAwsSnsTopicSubscriptionUpdate(d, meta)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceAwsSnsTopicSubscriptionUpdate(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
snsconn := meta.(*AWSClient).snsconn
|
||||||
|
|
||||||
|
// If any changes happened, un-subscribe and re-subscribe
|
||||||
|
if d.HasChange("protocol") || d.HasChange("endpoint") || d.HasChange("topic_arn") {
|
||||||
|
log.Printf("[DEBUG] Updating subscription %s", d.Id())
|
||||||
|
// Unsubscribe
|
||||||
|
_, err := snsconn.Unsubscribe(&sns.UnsubscribeInput{
|
||||||
|
SubscriptionARN: aws.String(d.Id()),
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error unsubscribing from SNS topic: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Re-subscribe and set id
|
||||||
|
output, err := subscribeToSNSTopic(d, snsconn)
|
||||||
|
d.SetId(*output.SubscriptionARN)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if d.HasChange("raw_message_delivery") {
|
||||||
|
_, n := d.GetChange("raw_message_delivery")
|
||||||
|
|
||||||
|
attrValue := "false"
|
||||||
|
|
||||||
|
if n.(bool) {
|
||||||
|
attrValue = "true"
|
||||||
|
}
|
||||||
|
|
||||||
|
req := &sns.SetSubscriptionAttributesInput{
|
||||||
|
SubscriptionARN: aws.String(d.Id()),
|
||||||
|
AttributeName: aws.String("RawMessageDelivery"),
|
||||||
|
AttributeValue: aws.String(attrValue),
|
||||||
|
}
|
||||||
|
_, err := snsconn.SetSubscriptionAttributes(req)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Unable to set raw message delivery attribute on subscription")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resourceAwsSnsTopicSubscriptionRead(d, meta)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceAwsSnsTopicSubscriptionRead(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
snsconn := meta.(*AWSClient).snsconn
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] Loading subscription %s", d.Id())
|
||||||
|
|
||||||
|
attributeOutput, err := snsconn.GetSubscriptionAttributes(&sns.GetSubscriptionAttributesInput{
|
||||||
|
SubscriptionARN: aws.String(d.Id()),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if attributeOutput.Attributes != nil && len(*attributeOutput.Attributes) > 0 {
|
||||||
|
attrHash := *attributeOutput.Attributes
|
||||||
|
log.Printf("[DEBUG] raw message delivery: %s", *attrHash["RawMessageDelivery"])
|
||||||
|
if *attrHash["RawMessageDelivery"] == "true" {
|
||||||
|
d.Set("raw_message_delivery", true)
|
||||||
|
} else {
|
||||||
|
d.Set("raw_message_delivery", false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceAwsSnsTopicSubscriptionDelete(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
snsconn := meta.(*AWSClient).snsconn
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] SNS delete topic subscription: %s", d.Id())
|
||||||
|
_, err := snsconn.Unsubscribe(&sns.UnsubscribeInput{
|
||||||
|
SubscriptionARN: aws.String(d.Id()),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func subscribeToSNSTopic(d *schema.ResourceData, snsconn *sns.SNS) (output *sns.SubscribeOutput, err error) {
|
||||||
|
protocol := d.Get("protocol").(string)
|
||||||
|
endpoint := d.Get("endpoint").(string)
|
||||||
|
topic_arn := d.Get("topic_arn").(string)
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] SNS create topic subscription: %s (%s) @ '%s'", endpoint, protocol, topic_arn)
|
||||||
|
|
||||||
|
req := &sns.SubscribeInput{
|
||||||
|
Protocol: aws.String(protocol),
|
||||||
|
Endpoint: aws.String(endpoint),
|
||||||
|
TopicARN: aws.String(topic_arn),
|
||||||
|
}
|
||||||
|
|
||||||
|
output, err = snsconn.Subscribe(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Error creating SNS topic: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] Created new subscription!")
|
||||||
|
return output, nil
|
||||||
|
}
|
|
@ -0,0 +1,103 @@
|
||||||
|
package aws
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/awslabs/aws-sdk-go/aws"
|
||||||
|
"github.com/awslabs/aws-sdk-go/service/sns"
|
||||||
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
|
"github.com/hashicorp/terraform/terraform"
|
||||||
|
"github.com/awslabs/aws-sdk-go/aws/awserr"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAccAWSSNSTopicSubscription(t *testing.T) {
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccCheckAWSSNSTopicSubscriptionDestroy,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccAWSSNSTopicSubscriptionConfig,
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckAWSSNSTopicExists("aws_sns_topic.test_topic"),
|
||||||
|
testAccCheckAWSSNSTopicSubscriptionExists("aws_sns_topic_subscription.test_subscription"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func testAccCheckAWSSNSTopicSubscriptionDestroy(s *terraform.State) error {
|
||||||
|
conn := testAccProvider.Meta().(*AWSClient).snsconn
|
||||||
|
|
||||||
|
for _, rs := range s.RootModule().Resources {
|
||||||
|
if rs.Type != "aws_sns_topic" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to find key pair
|
||||||
|
req := &sns.GetSubscriptionAttributesInput{
|
||||||
|
SubscriptionARN: aws.String(rs.Primary.ID),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
_, err := conn.GetSubscriptionAttributes(req)
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
return fmt.Errorf("Subscription still exists, can't continue.")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify the error is an API error, not something else
|
||||||
|
_, ok := err.(awserr.Error)
|
||||||
|
if !ok {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func testAccCheckAWSSNSTopicSubscriptionExists(n string) resource.TestCheckFunc {
|
||||||
|
return func(s *terraform.State) error {
|
||||||
|
rs, ok := s.RootModule().Resources[n]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Not found: %s", n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if rs.Primary.ID == "" {
|
||||||
|
return fmt.Errorf("No SNS subscription with that ARN exists")
|
||||||
|
}
|
||||||
|
|
||||||
|
conn := testAccProvider.Meta().(*AWSClient).snsconn
|
||||||
|
|
||||||
|
params := &sns.GetSubscriptionAttributesInput{
|
||||||
|
SubscriptionARN: aws.String(rs.Primary.ID),
|
||||||
|
}
|
||||||
|
_, err := conn.GetSubscriptionAttributes(params)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const testAccAWSSNSTopicSubscriptionConfig = `
|
||||||
|
resource "aws_sns_topic" "test_topic" {
|
||||||
|
name = "terraform-test-topic"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_sqs_queue" "test_queue" {
|
||||||
|
name = "terraform-subscription-test-queue"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_sns_topic_subscription" "test_subscription" {
|
||||||
|
topic_arn = "${aws_sns_topic.test_topic.arn}"
|
||||||
|
protocol = "sqs"
|
||||||
|
endpoint = "${aws_sqs_queue.test_queue.arn}"
|
||||||
|
}
|
||||||
|
`
|
|
@ -0,0 +1,89 @@
|
||||||
|
package aws
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/awslabs/aws-sdk-go/aws"
|
||||||
|
"github.com/awslabs/aws-sdk-go/service/sns"
|
||||||
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
|
"github.com/hashicorp/terraform/terraform"
|
||||||
|
"github.com/awslabs/aws-sdk-go/aws/awserr"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAccAWSSNSTopic(t *testing.T) {
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccCheckAWSSNSTopicDestroy,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccAWSSNSTopicConfig,
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckAWSSNSTopicExists("aws_sns_topic.test_topic"),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func testAccCheckAWSSNSTopicDestroy(s *terraform.State) error {
|
||||||
|
conn := testAccProvider.Meta().(*AWSClient).snsconn
|
||||||
|
|
||||||
|
for _, rs := range s.RootModule().Resources {
|
||||||
|
if rs.Type != "aws_sns_topic" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the topic exists by fetching its attributes
|
||||||
|
params := &sns.GetTopicAttributesInput{
|
||||||
|
TopicARN: aws.String(rs.Primary.ID),
|
||||||
|
}
|
||||||
|
_, err := conn.GetTopicAttributes(params)
|
||||||
|
if err == nil {
|
||||||
|
return fmt.Errorf("Topic exists when it should be destroyed!")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify the error is an API error, not something else
|
||||||
|
_, ok := err.(awserr.Error)
|
||||||
|
if !ok {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func testAccCheckAWSSNSTopicExists(n string) resource.TestCheckFunc {
|
||||||
|
return func(s *terraform.State) error {
|
||||||
|
rs, ok := s.RootModule().Resources[n]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("Not found: %s", n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if rs.Primary.ID == "" {
|
||||||
|
return fmt.Errorf("No SNS topic with that ARN exists")
|
||||||
|
}
|
||||||
|
|
||||||
|
conn := testAccProvider.Meta().(*AWSClient).snsconn
|
||||||
|
|
||||||
|
params := &sns.GetTopicAttributesInput{
|
||||||
|
TopicARN: aws.String(rs.Primary.ID),
|
||||||
|
}
|
||||||
|
_, err := conn.GetTopicAttributes(params)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const testAccAWSSNSTopicConfig = `
|
||||||
|
resource "aws_sns_topic" "test_topic" {
|
||||||
|
name = "terraform-test-topic"
|
||||||
|
}
|
||||||
|
`
|
|
@ -19,6 +19,7 @@ var AttributeMap = map[string]string{
|
||||||
"visibility_timeout_seconds": "VisibilityTimeout",
|
"visibility_timeout_seconds": "VisibilityTimeout",
|
||||||
"policy": "Policy",
|
"policy": "Policy",
|
||||||
"redrive_policy": "RedrivePolicy",
|
"redrive_policy": "RedrivePolicy",
|
||||||
|
"arn": "QueueArn",
|
||||||
}
|
}
|
||||||
|
|
||||||
// A number of these are marked as computed because if you don't
|
// A number of these are marked as computed because if you don't
|
||||||
|
@ -70,6 +71,10 @@ func resourceAwsSqsQueue() *schema.Resource {
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Optional: true,
|
Optional: true,
|
||||||
},
|
},
|
||||||
|
"arn": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -154,6 +159,7 @@ func resourceAwsSqsQueueRead(d *schema.ResourceData, meta interface{}) error {
|
||||||
QueueURL: aws.String(d.Id()),
|
QueueURL: aws.String(d.Id()),
|
||||||
AttributeNames: []*string{aws.String("All")},
|
AttributeNames: []*string{aws.String("All")},
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,11 +51,7 @@ func (p *ResourceProvisioner) Validate(c *terraform.ResourceConfig) (ws []string
|
||||||
num := 0
|
num := 0
|
||||||
for name := range c.Raw {
|
for name := range c.Raw {
|
||||||
switch name {
|
switch name {
|
||||||
case "scripts":
|
case "scripts", "script", "inline":
|
||||||
fallthrough
|
|
||||||
case "script":
|
|
||||||
fallthrough
|
|
||||||
case "inline":
|
|
||||||
num++
|
num++
|
||||||
default:
|
default:
|
||||||
es = append(es, fmt.Errorf("Unknown configuration '%s'", name))
|
es = append(es, fmt.Errorf("Unknown configuration '%s'", name))
|
||||||
|
|
|
@ -33,9 +33,7 @@ type fileLoaderFunc func(path string) (configurable, []string, error)
|
||||||
func loadTree(root string) (*importTree, error) {
|
func loadTree(root string) (*importTree, error) {
|
||||||
var f fileLoaderFunc
|
var f fileLoaderFunc
|
||||||
switch ext(root) {
|
switch ext(root) {
|
||||||
case ".tf":
|
case ".tf", ".tf.json":
|
||||||
fallthrough
|
|
||||||
case ".tf.json":
|
|
||||||
f = loadFileHcl
|
f = loadFileHcl
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
|
@ -299,9 +299,7 @@ func (x *parserLex) lexString(yylval *parserSymType, quoted bool) (int, bool) {
|
||||||
// Let's check to see if we're escaping anything.
|
// Let's check to see if we're escaping anything.
|
||||||
if c == '\\' {
|
if c == '\\' {
|
||||||
switch n := x.next(); n {
|
switch n := x.next(); n {
|
||||||
case '\\':
|
case '\\', '"':
|
||||||
fallthrough
|
|
||||||
case '"':
|
|
||||||
c = n
|
c = n
|
||||||
case 'n':
|
case 'n':
|
||||||
c = '\n'
|
c = '\n'
|
||||||
|
|
|
@ -78,19 +78,11 @@ func addrToSchema(addr []string, schemaMap map[string]*Schema) []*Schema {
|
||||||
}
|
}
|
||||||
|
|
||||||
switch t := current.Type; t {
|
switch t := current.Type; t {
|
||||||
case TypeBool:
|
case TypeBool, TypeInt, TypeFloat, TypeString:
|
||||||
fallthrough
|
|
||||||
case TypeInt:
|
|
||||||
fallthrough
|
|
||||||
case TypeFloat:
|
|
||||||
fallthrough
|
|
||||||
case TypeString:
|
|
||||||
if len(addr) > 0 {
|
if len(addr) > 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
case TypeList:
|
case TypeList, TypeSet:
|
||||||
fallthrough
|
|
||||||
case TypeSet:
|
|
||||||
switch v := current.Elem.(type) {
|
switch v := current.Elem.(type) {
|
||||||
case *Resource:
|
case *Resource:
|
||||||
current = &Schema{
|
current = &Schema{
|
||||||
|
|
|
@ -80,13 +80,7 @@ func (r *ConfigFieldReader) readField(
|
||||||
k := strings.Join(address, ".")
|
k := strings.Join(address, ".")
|
||||||
schema := schemaList[len(schemaList)-1]
|
schema := schemaList[len(schemaList)-1]
|
||||||
switch schema.Type {
|
switch schema.Type {
|
||||||
case TypeBool:
|
case TypeBool, TypeFloat, TypeInt, TypeString:
|
||||||
fallthrough
|
|
||||||
case TypeFloat:
|
|
||||||
fallthrough
|
|
||||||
case TypeInt:
|
|
||||||
fallthrough
|
|
||||||
case TypeString:
|
|
||||||
return r.readPrimitive(k, schema)
|
return r.readPrimitive(k, schema)
|
||||||
case TypeList:
|
case TypeList:
|
||||||
return readListField(&nestedConfigFieldReader{r}, address, schema)
|
return readListField(&nestedConfigFieldReader{r}, address, schema)
|
||||||
|
|
|
@ -39,13 +39,7 @@ func (r *DiffFieldReader) ReadField(address []string) (FieldReadResult, error) {
|
||||||
|
|
||||||
schema := schemaList[len(schemaList)-1]
|
schema := schemaList[len(schemaList)-1]
|
||||||
switch schema.Type {
|
switch schema.Type {
|
||||||
case TypeBool:
|
case TypeBool, TypeInt, TypeFloat, TypeString:
|
||||||
fallthrough
|
|
||||||
case TypeInt:
|
|
||||||
fallthrough
|
|
||||||
case TypeFloat:
|
|
||||||
fallthrough
|
|
||||||
case TypeString:
|
|
||||||
return r.readPrimitive(address, schema)
|
return r.readPrimitive(address, schema)
|
||||||
case TypeList:
|
case TypeList:
|
||||||
return readListField(r, address, schema)
|
return readListField(r, address, schema)
|
||||||
|
|
|
@ -21,13 +21,7 @@ func (r *MapFieldReader) ReadField(address []string) (FieldReadResult, error) {
|
||||||
|
|
||||||
schema := schemaList[len(schemaList)-1]
|
schema := schemaList[len(schemaList)-1]
|
||||||
switch schema.Type {
|
switch schema.Type {
|
||||||
case TypeBool:
|
case TypeBool, TypeInt, TypeFloat, TypeString:
|
||||||
fallthrough
|
|
||||||
case TypeInt:
|
|
||||||
fallthrough
|
|
||||||
case TypeFloat:
|
|
||||||
fallthrough
|
|
||||||
case TypeString:
|
|
||||||
return r.readPrimitive(address, schema)
|
return r.readPrimitive(address, schema)
|
||||||
case TypeList:
|
case TypeList:
|
||||||
return readListField(r, address, schema)
|
return readListField(r, address, schema)
|
||||||
|
|
|
@ -74,13 +74,7 @@ func (w *MapFieldWriter) set(addr []string, value interface{}) error {
|
||||||
|
|
||||||
schema := schemaList[len(schemaList)-1]
|
schema := schemaList[len(schemaList)-1]
|
||||||
switch schema.Type {
|
switch schema.Type {
|
||||||
case TypeBool:
|
case TypeBool, TypeInt, TypeFloat, TypeString:
|
||||||
fallthrough
|
|
||||||
case TypeInt:
|
|
||||||
fallthrough
|
|
||||||
case TypeFloat:
|
|
||||||
fallthrough
|
|
||||||
case TypeString:
|
|
||||||
return w.setPrimitive(addr, value, schema)
|
return w.setPrimitive(addr, value, schema)
|
||||||
case TypeList:
|
case TypeList:
|
||||||
return w.setList(addr, value, schema)
|
return w.setList(addr, value, schema)
|
||||||
|
|
|
@ -378,13 +378,7 @@ func (m schemaMap) Input(
|
||||||
|
|
||||||
var value interface{}
|
var value interface{}
|
||||||
switch v.Type {
|
switch v.Type {
|
||||||
case TypeBool:
|
case TypeBool, TypeInt, TypeFloat, TypeSet:
|
||||||
fallthrough
|
|
||||||
case TypeInt:
|
|
||||||
fallthrough
|
|
||||||
case TypeFloat:
|
|
||||||
fallthrough
|
|
||||||
case TypeSet:
|
|
||||||
continue
|
continue
|
||||||
case TypeString:
|
case TypeString:
|
||||||
value, err = m.inputString(input, k, v)
|
value, err = m.inputString(input, k, v)
|
||||||
|
@ -522,13 +516,7 @@ func (m schemaMap) diff(
|
||||||
all bool) error {
|
all bool) error {
|
||||||
var err error
|
var err error
|
||||||
switch schema.Type {
|
switch schema.Type {
|
||||||
case TypeBool:
|
case TypeBool, TypeInt, TypeFloat, TypeString:
|
||||||
fallthrough
|
|
||||||
case TypeInt:
|
|
||||||
fallthrough
|
|
||||||
case TypeFloat:
|
|
||||||
fallthrough
|
|
||||||
case TypeString:
|
|
||||||
err = m.diffString(k, schema, diff, d, all)
|
err = m.diffString(k, schema, diff, d, all)
|
||||||
case TypeList:
|
case TypeList:
|
||||||
err = m.diffList(k, schema, diff, d, all)
|
err = m.diffList(k, schema, diff, d, all)
|
||||||
|
@ -1170,9 +1158,7 @@ func (m schemaMap) validateType(
|
||||||
var ws []string
|
var ws []string
|
||||||
var es []error
|
var es []error
|
||||||
switch schema.Type {
|
switch schema.Type {
|
||||||
case TypeSet:
|
case TypeSet, TypeList:
|
||||||
fallthrough
|
|
||||||
case TypeList:
|
|
||||||
ws, es = m.validateList(k, raw, schema, c)
|
ws, es = m.validateList(k, raw, schema, c)
|
||||||
case TypeMap:
|
case TypeMap:
|
||||||
ws, es = m.validateMap(k, raw, schema, c)
|
ws, es = m.validateMap(k, raw, schema, c)
|
||||||
|
|
|
@ -149,15 +149,11 @@ func (d *ModuleDiff) ChangeType() DiffChangeType {
|
||||||
for _, r := range d.Resources {
|
for _, r := range d.Resources {
|
||||||
change := r.ChangeType()
|
change := r.ChangeType()
|
||||||
switch change {
|
switch change {
|
||||||
case DiffCreate:
|
case DiffCreate, DiffDestroy:
|
||||||
fallthrough
|
|
||||||
case DiffDestroy:
|
|
||||||
if result == DiffNone {
|
if result == DiffNone {
|
||||||
result = change
|
result = change
|
||||||
}
|
}
|
||||||
case DiffDestroyCreate:
|
case DiffDestroyCreate, DiffUpdate:
|
||||||
fallthrough
|
|
||||||
case DiffUpdate:
|
|
||||||
result = DiffUpdate
|
result = DiffUpdate
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -148,9 +148,7 @@ func (n *GraphNodeConfigResource) DynamicExpand(ctx EvalContext) (*Graph, error)
|
||||||
// Primary and non-destroy modes are responsible for creating/destroying
|
// Primary and non-destroy modes are responsible for creating/destroying
|
||||||
// all the nodes, expanding counts.
|
// all the nodes, expanding counts.
|
||||||
switch n.DestroyMode {
|
switch n.DestroyMode {
|
||||||
case DestroyNone:
|
case DestroyNone, DestroyPrimary:
|
||||||
fallthrough
|
|
||||||
case DestroyPrimary:
|
|
||||||
steps = append(steps, &ResourceCountTransformer{
|
steps = append(steps, &ResourceCountTransformer{
|
||||||
Resource: n.Resource,
|
Resource: n.Resource,
|
||||||
Destroy: n.DestroyMode != DestroyNone,
|
Destroy: n.DestroyMode != DestroyNone,
|
||||||
|
|
|
@ -79,18 +79,18 @@ GEM
|
||||||
celluloid (~> 0.16.0)
|
celluloid (~> 0.16.0)
|
||||||
rb-fsevent (>= 0.9.3)
|
rb-fsevent (>= 0.9.3)
|
||||||
rb-inotify (>= 0.9)
|
rb-inotify (>= 0.9)
|
||||||
middleman (3.3.13)
|
middleman (3.3.12)
|
||||||
coffee-script (~> 2.2)
|
coffee-script (~> 2.2)
|
||||||
compass (>= 1.0.0, < 2.0.0)
|
compass (>= 1.0.0, < 2.0.0)
|
||||||
compass-import-once (= 1.0.5)
|
compass-import-once (= 1.0.5)
|
||||||
execjs (~> 2.0)
|
execjs (~> 2.0)
|
||||||
haml (>= 4.0.5)
|
haml (>= 4.0.5)
|
||||||
kramdown (~> 1.2)
|
kramdown (~> 1.2)
|
||||||
middleman-core (= 3.3.13)
|
middleman-core (= 3.3.12)
|
||||||
middleman-sprockets (>= 3.1.2)
|
middleman-sprockets (>= 3.1.2)
|
||||||
sass (>= 3.4.0, < 4.0)
|
sass (>= 3.4.0, < 4.0)
|
||||||
uglifier (~> 2.5)
|
uglifier (~> 2.5)
|
||||||
middleman-core (3.3.13)
|
middleman-core (3.3.12)
|
||||||
activesupport (~> 4.1.0)
|
activesupport (~> 4.1.0)
|
||||||
bundler (~> 1.1)
|
bundler (~> 1.1)
|
||||||
erubis
|
erubis
|
||||||
|
|
|
@ -133,7 +133,7 @@ The supported built-in functions are:
|
||||||
|
|
||||||
## Templates
|
## Templates
|
||||||
|
|
||||||
Long strings can be managed using templates. Templates are [resources](/docs/configuration/resources.html) defined by a filename and some variables to use during interpolation. They have a computed `rendered` attribute containing the result.
|
Long strings can be managed using templates. [Templates](/docs/providers/template/index.html) are [resources](/docs/configuration/resources.html) defined by a filename and some variables to use during interpolation. They have a computed `rendered` attribute containing the result.
|
||||||
|
|
||||||
A template resource looks like:
|
A template resource looks like:
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,9 @@ resource "aws_db_instance" "default" {
|
||||||
|
|
||||||
## Argument Reference
|
## Argument Reference
|
||||||
|
|
||||||
|
For a more detailed documentation about the each argument refer to
|
||||||
|
the [AWS official documentation](http://docs.aws.amazon.com/AmazonRDS/latest/CommandLineReference/CLIReference-cmd-ModifyDBInstance.html).
|
||||||
|
|
||||||
The following arguments are supported:
|
The following arguments are supported:
|
||||||
|
|
||||||
* `allocated_storage` - (Required) The allocated storage in gigabytes.
|
* `allocated_storage` - (Required) The allocated storage in gigabytes.
|
||||||
|
@ -65,7 +68,7 @@ The following arguments are supported:
|
||||||
* `storage_encrypted` - (Optional) Specifies whether the DB instance is encrypted. The default is `false` if not specified.
|
* `storage_encrypted` - (Optional) Specifies whether the DB instance is encrypted. The default is `false` if not specified.
|
||||||
* `apply_immediately` - (Optional) Specifies whether any database modifications
|
* `apply_immediately` - (Optional) Specifies whether any database modifications
|
||||||
are applied immediately, or during the next maintenance window. Default is
|
are applied immediately, or during the next maintenance window. Default is
|
||||||
`false`. See [Amazon RDS Documentation for more for more information.](http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Overview.DBInstance.Modifying.html)
|
`false`. See [Amazon RDS Documentation for more information.](http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Overview.DBInstance.Modifying.html)
|
||||||
* `replicate_source_db` - (Optional) Specifies that this resource is a Replicate
|
* `replicate_source_db` - (Optional) Specifies that this resource is a Replicate
|
||||||
database, and to use this value as the source database. This correlates to the
|
database, and to use this value as the source database. This correlates to the
|
||||||
`identifier` of another Amazon RDS Database to replicate. See
|
`identifier` of another Amazon RDS Database to replicate. See
|
||||||
|
@ -100,5 +103,4 @@ The following attributes are exported:
|
||||||
* `username` - The master username for the database
|
* `username` - The master username for the database
|
||||||
* `storage_encrypted` - Specifies whether the DB instance is encrypted
|
* `storage_encrypted` - Specifies whether the DB instance is encrypted
|
||||||
|
|
||||||
|
|
||||||
[1]: http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Overview.Replication.html
|
[1]: http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Overview.Replication.html
|
||||||
|
|
|
@ -8,7 +8,10 @@ description: |-
|
||||||
|
|
||||||
# aws\_db\_security\_group
|
# aws\_db\_security\_group
|
||||||
|
|
||||||
Provides an RDS security group resource.
|
Provides an RDS security group resource. This is only for DB instances in the
|
||||||
|
EC2-Classic Platform. For instances inside a VPC, use the
|
||||||
|
[`aws_db_instance.vpc_security_group_ids`](/docs/providers/aws/r/db_instance.html#vpc_security_group_ids)
|
||||||
|
attribute instead.
|
||||||
|
|
||||||
## Example Usage
|
## Example Usage
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ layout: "aws"
|
||||||
page_title: "AWS: aws_ebs_volume"
|
page_title: "AWS: aws_ebs_volume"
|
||||||
sidebar_current: "docs-aws-resource-ebs-volume"
|
sidebar_current: "docs-aws-resource-ebs-volume"
|
||||||
description: |-
|
description: |-
|
||||||
Provides an Elastic IP resource.
|
Provides an elastic block storage resource.
|
||||||
---
|
---
|
||||||
|
|
||||||
# aws\_ebs\_volume
|
# aws\_ebs\_volume
|
||||||
|
@ -30,3 +30,12 @@ The following arguments are supported:
|
||||||
* `snapshot_id` (Optinal) A snapshot to base the EBS volume off of.
|
* `snapshot_id` (Optinal) A snapshot to base the EBS volume off of.
|
||||||
* `type` - (Optional) The type of EBS volume.
|
* `type` - (Optional) The type of EBS volume.
|
||||||
* `kms_key_id` - (Optional) The KMS key ID for the volume.
|
* `kms_key_id` - (Optional) The KMS key ID for the volume.
|
||||||
|
|
||||||
|
|
||||||
|
## Attributes Reference
|
||||||
|
|
||||||
|
The following attributes are exported:
|
||||||
|
|
||||||
|
* `id` - The volume ID (e.g. vol-59fcb34e).
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,102 @@
|
||||||
|
---
|
||||||
|
layout: "aws"
|
||||||
|
page_title: "AWS: aws_iam_server_certificate"
|
||||||
|
sidebar_current: "docs-aws-resource-iam-server-certificate"
|
||||||
|
description: |-
|
||||||
|
Provides an IAM Server Certificate
|
||||||
|
---
|
||||||
|
|
||||||
|
# aws\_iam\_server\_certificate
|
||||||
|
|
||||||
|
Provides an IAM Server Certificate resource to upload Server Certificates.
|
||||||
|
Certs uploated to IAM can easily work with other AWS services such as:
|
||||||
|
|
||||||
|
- AWS Elastic Beanstalk
|
||||||
|
- Elastic Load Balancing
|
||||||
|
- CloudFront
|
||||||
|
- AWS OpsWorks
|
||||||
|
|
||||||
|
For information about server certificates in IAM, see [Managing Server
|
||||||
|
Certficates][2] in AWS Documentation.
|
||||||
|
|
||||||
|
## Example Usage
|
||||||
|
|
||||||
|
**Using certs on file:**
|
||||||
|
|
||||||
|
```
|
||||||
|
resource "aws_iam_server_certificate" "test_cert" {
|
||||||
|
name = "some_test_cert"
|
||||||
|
certificate_body = "${file("self-ca-cert.pem")}"
|
||||||
|
private_key = "${file("test-key.pem")}"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Example with cert in-line:**
|
||||||
|
|
||||||
|
```
|
||||||
|
resource "aws_iam_server_certificate" "test_cert_alt" {
|
||||||
|
name = "alt_test_cert"
|
||||||
|
certificate_body = <<EOF
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
[......] # cert contents
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
EOF
|
||||||
|
|
||||||
|
private_key = <<EOF
|
||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
[......] # cert contents
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Use in combination with an AWS ELB resource:**
|
||||||
|
|
||||||
|
```
|
||||||
|
resource "aws_iam_server_certificate" "test_cert" {
|
||||||
|
name = "some_test_cert"
|
||||||
|
certificate_body = "${file("self-ca-cert.pem")}"
|
||||||
|
private_key = "${file("test-key.pem")}"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_elb" "ourapp" {
|
||||||
|
name = "terraform-asg-deployment-example"
|
||||||
|
availability_zones = ["us-west-2a"]
|
||||||
|
cross_zone_load_balancing = true
|
||||||
|
|
||||||
|
listener {
|
||||||
|
instance_port = 8000
|
||||||
|
instance_protocol = "http"
|
||||||
|
lb_port = 443
|
||||||
|
lb_protocol = "https"
|
||||||
|
ssl_certificate_id = "${aws_iam_server_certificate.test_cert.arn}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Argument Reference
|
||||||
|
|
||||||
|
The following arguments are supported:
|
||||||
|
|
||||||
|
* `name` - (Required) The name of the Server Certificate. Do not include the
|
||||||
|
path in this value.
|
||||||
|
* `certificate_body` – (Required) The contents of the public key certificate in
|
||||||
|
PEM-encoded format.
|
||||||
|
* `certificate_chain` – (Optional) The contents of the certificate chain.
|
||||||
|
This is typically a concatenation of the PEM-encoded public key certificates
|
||||||
|
of the chain.
|
||||||
|
* `private_key` – (Required) The contents of the private key in PEM-encoded format.
|
||||||
|
* `path` - (Optional) The IAM path for the server certificate. If it is not
|
||||||
|
included, it defaults to a slash (/). If this certificate is for use with
|
||||||
|
AWS CloudFront, the path must be in format `/cloudfront/your_path_here`.
|
||||||
|
See [IAM Identifiers][1] for more details on IAM Paths.
|
||||||
|
|
||||||
|
## Attributes Reference
|
||||||
|
|
||||||
|
* `id` - The unique Server Certificate name
|
||||||
|
* `name` - The name of the Server Certificate
|
||||||
|
* `arn` - The Amazon Resource Name (ARN) specifying the server certificate.
|
||||||
|
|
||||||
|
|
||||||
|
[1]: http://docs.aws.amazon.com/IAM/latest/UserGuide/Using_Identifiers.html
|
||||||
|
[2]: http://docs.aws.amazon.com/IAM/latest/UserGuide/ManagingServerCerts.html
|
|
@ -89,12 +89,13 @@ The following arguments are supported:
|
||||||
* `zone_id` - (Required) The ID of the hosted zone to contain this record.
|
* `zone_id` - (Required) The ID of the hosted zone to contain this record.
|
||||||
* `name` - (Required) The name of the record.
|
* `name` - (Required) The name of the record.
|
||||||
* `type` - (Required) The record type.
|
* `type` - (Required) The record type.
|
||||||
* `ttl` - (Required) The TTL of the record.
|
* `ttl` - (Required for non-alias records) The TTL of the record.
|
||||||
* `records` - (Required) A string list of records.
|
* `records` - (Required for non-alias records) A string list of records.
|
||||||
* `weight` - (Optional) The weight of weighted record (0-255).
|
* `weight` - (Optional) The weight of weighted record (0-255).
|
||||||
* `set_identifier` - (Optional) Unique identifier to differentiate weighted
|
* `set_identifier` - (Optional) Unique identifier to differentiate weighted
|
||||||
record from one another. Required for each weighted record.
|
record from one another. Required for each weighted record.
|
||||||
* `alias` - (Optional) An alias block. Alias record documented below.
|
* `alias` - (Optional) An alias block. Conflicts with `ttl` & `records`.
|
||||||
|
Alias record documented below.
|
||||||
|
|
||||||
Exactly one of `records` or `alias` must be specified: this determines whether it's an alias record.
|
Exactly one of `records` or `alias` must be specified: this determines whether it's an alias record.
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ description: |-
|
||||||
|
|
||||||
# aws\_security\_group\_rule
|
# aws\_security\_group\_rule
|
||||||
|
|
||||||
Provides a security group rule resource. Represents a signle `ingress` or
|
Provides a security group rule resource. Represents a single `ingress` or
|
||||||
`egress` group rule, which can be added to external Security Groups.
|
`egress` group rule, which can be added to external Security Groups.
|
||||||
|
|
||||||
~> **NOTE on Security Groups and Security Group Rules:** Terraform currently
|
~> **NOTE on Security Groups and Security Group Rules:** Terraform currently
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
---
|
||||||
|
layout: "aws"
|
||||||
|
page_title: "AWS: sns_topic"
|
||||||
|
sidebar_current: "docs-aws-resource-sns-topic"
|
||||||
|
description: |-
|
||||||
|
Provides an SNS topic resource.
|
||||||
|
---
|
||||||
|
|
||||||
|
# aws\_sns\_topic
|
||||||
|
|
||||||
|
Provides an SNS topic resource
|
||||||
|
|
||||||
|
## Example Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
resource "aws_sns_topic" "user_updates" {
|
||||||
|
name = "user-updates-topic"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Argument Reference
|
||||||
|
|
||||||
|
The following arguments are supported:
|
||||||
|
|
||||||
|
* `name` - (Required) The friendly name for the SNS topic
|
||||||
|
* `policy` - (Optional) The fully-formed AWS policy as JSON
|
||||||
|
* `delivery_policy` - (Optional) The SNS delivery policy
|
||||||
|
|
||||||
|
## Attributes Reference
|
||||||
|
|
||||||
|
The following attributes are exported:
|
||||||
|
|
||||||
|
* `id` - The ARN of the SNS topic
|
||||||
|
* `arn` - The ARN of the SNS topic, as a more obvious property (clone of id)
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
---
|
||||||
|
layout: "aws"
|
||||||
|
page_title: "AWS: sns_topic_subscription"
|
||||||
|
sidebar_current: "docs-aws-resource-sns-topic-subscription"
|
||||||
|
description: |-
|
||||||
|
Provides a resource for subscribing to SNS topics.
|
||||||
|
---
|
||||||
|
|
||||||
|
# aws\_sns\_topic\_subscription
|
||||||
|
|
||||||
|
Provides a resource for subscribing to SNS topics. Requires that an SNS topic exist for the subscription to attach to.
|
||||||
|
This resource allows you to automatically place messages sent to SNS topics in SQS queues, send them as HTTP(S) POST requests
|
||||||
|
to a given endpoint, send SMS messages, or notify devices / applications. The most likely use case for Terraform users will
|
||||||
|
probably be SQS queues.
|
||||||
|
|
||||||
|
## Example Usage
|
||||||
|
|
||||||
|
You can directly supply a topic and ARN by hand in the `topic_arn` property along with the queue ARN:
|
||||||
|
|
||||||
|
```
|
||||||
|
resource "aws_sns_topic_subscription" "user_updates_sqs_target" {
|
||||||
|
topic_arn = "arn:aws:sns:us-west-2:432981146916:user-updates-topic"
|
||||||
|
protocol = "sqs"
|
||||||
|
endpoint = "arn:aws:sqs:us-west-2:432981146916:terraform-queue-too"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Alternatively you can use the ARN properties of a managed SNS topic and SQS queue:
|
||||||
|
|
||||||
|
```
|
||||||
|
resource "aws_sns_topic" "user_updates" {
|
||||||
|
name = "user-updates-topic"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_sqs_queue" "user_updates_queue" {
|
||||||
|
name = "user-updates-queue"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_sns_topic_subscription" "user_updates_sqs_target" {
|
||||||
|
topic_arn = "${aws_sns_topic.user_updates.arn}"
|
||||||
|
protocol = "sqs"
|
||||||
|
endpoint = "${aws_sqs_queue.user_updates_queue.arn}"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Argument Reference
|
||||||
|
|
||||||
|
The following arguments are supported:
|
||||||
|
|
||||||
|
* `topic_arn` - (Required) The ARN of the SNS topic to subscribe to
|
||||||
|
* `protocol` - (Required) The protocol to use. The possible values for this are: `sqs`, `http`, `https`, `sms`, or `application`. (`email` is an option but unsupported, see below)
|
||||||
|
* `endpoint` - (Required) The endpoint to send data to, the contents will vary with the protocol. (see below for more information)
|
||||||
|
* `raw_message_delivery` - (Optional) Boolean indicating whether or not to enable raw message delivery (the original message is directly passed, not wrapped in JSON with the original message in the message property).
|
||||||
|
|
||||||
|
### Protocols supported
|
||||||
|
|
||||||
|
Supported SNS protocols include:
|
||||||
|
|
||||||
|
* `http` -- delivery of JSON-encoded message via HTTP POST
|
||||||
|
* `https` -- delivery of JSON-encoded message via HTTPS POST
|
||||||
|
* `sms` -- delivery of message via SMS
|
||||||
|
* `sqs` -- delivery of JSON-encoded message to an Amazon SQS queue
|
||||||
|
* `application` -- delivery of JSON-encoded message to an EndpointArn for a mobile app and device
|
||||||
|
|
||||||
|
Unsupported protocols include the following:
|
||||||
|
|
||||||
|
* `email` -- delivery of message via SMTP
|
||||||
|
* `email-json` -- delivery of JSON-encoded message via SMTP
|
||||||
|
|
||||||
|
These are unsupported because the email address needs to be authorized and does not generate an ARN until the target email address has been validated. This breaks
|
||||||
|
the Terraform model and as a result are not currently supported.
|
||||||
|
|
||||||
|
### Specifying endpoints
|
||||||
|
|
||||||
|
Endpoints have different format requirements according to the protocol that is chosen.
|
||||||
|
|
||||||
|
* HTTP/HTTPS endpoints will require a URL to POST data to
|
||||||
|
* SMS endpoints are mobile numbers that are capable of receiving an SMS
|
||||||
|
* SQS endpoints come in the form of the SQS queue's ARN (not the URL of the queue) e.g: `arn:aws:sqs:us-west-2:432981146916:terraform-queue-too`
|
||||||
|
* Application endpoints are also the endpoint ARN for the mobile app and device.
|
||||||
|
|
||||||
|
|
||||||
|
## Attributes Reference
|
||||||
|
|
||||||
|
The following attributes are exported:
|
||||||
|
|
||||||
|
* `id` - The ARN of the subscription
|
||||||
|
* `topic_arn` - The ARN of the topic the subscription belongs to
|
||||||
|
* `protocol` - The protocol being used
|
||||||
|
* `endpoint` - The full endpoint to send data to (SQS ARN, HTTP(S) URL, Application ARN, SMS number, etc.)
|
||||||
|
* `arn` - The ARN of the subscription stored as a more user-friendly property
|
||||||
|
|
|
@ -11,7 +11,7 @@ description: |-
|
||||||
## Example Usage
|
## Example Usage
|
||||||
|
|
||||||
```
|
```
|
||||||
resource "aws_sqs_queue" "terrform_queue" {
|
resource "aws_sqs_queue" "terraform_queue" {
|
||||||
name = "terraform-example-queue"
|
name = "terraform-example-queue"
|
||||||
delay_seconds = 90
|
delay_seconds = 90
|
||||||
max_message_size = 2048
|
max_message_size = 2048
|
||||||
|
@ -35,4 +35,5 @@ The following arguments are supported:
|
||||||
|
|
||||||
The following attributes are exported:
|
The following attributes are exported:
|
||||||
|
|
||||||
* `id` - The URL for the created Amazon SQS queue.
|
* `id` - The URL for the created Amazon SQS queue.
|
||||||
|
* `arn` - The ARN of the SQS queue
|
|
@ -41,3 +41,6 @@ The following attributes are exported:
|
||||||
* `vars` - See Argument Reference above.
|
* `vars` - See Argument Reference above.
|
||||||
* `rendered` - The final rendered template.
|
* `rendered` - The final rendered template.
|
||||||
|
|
||||||
|
## Template files syntax
|
||||||
|
|
||||||
|
The syntax of the template files is [documented here](/docs/configuration/interpolation.html), under the "Templates" section.
|
||||||
|
|
|
@ -53,7 +53,7 @@ resource "terraform_remote_state" "vpc" {
|
||||||
|
|
||||||
resource "aws_instance" "foo" {
|
resource "aws_instance" "foo" {
|
||||||
# ...
|
# ...
|
||||||
subnet_id = "${terraform_state.vpc.output.subnet_id}"
|
subnet_id = "${terraform_remote_state.vpc.output.subnet_id}"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -89,6 +89,10 @@
|
||||||
<a href="/docs/providers/aws/r/iam_role_policy.html">aws_iam_role_policy</a>
|
<a href="/docs/providers/aws/r/iam_role_policy.html">aws_iam_role_policy</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
<li<%= sidebar_current("docs-aws-resource-iam-server-certificate") %>>
|
||||||
|
<a href="/docs/providers/aws/r/iam_server_certificate.html">aws_iam_server_certificate</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
<li<%= sidebar_current("docs-aws-resource-iam-user") %>>
|
<li<%= sidebar_current("docs-aws-resource-iam-user") %>>
|
||||||
<a href="/docs/providers/aws/r/iam_user.html">aws_iam_user</a>
|
<a href="/docs/providers/aws/r/iam_user.html">aws_iam_user</a>
|
||||||
</li>
|
</li>
|
||||||
|
@ -152,6 +156,14 @@
|
||||||
<a href="/docs/providers/aws/r/s3_bucket.html">aws_s3_bucket</a>
|
<a href="/docs/providers/aws/r/s3_bucket.html">aws_s3_bucket</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
<li<%= sidebar_current("docs-aws-resource-sns-topic") %>>
|
||||||
|
<a href="/docs/providers/aws/r/sns_topic.html">aws_sns_topic</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li<%= sidebar_current("docs-aws-resource-sns-topic-subscription") %>>
|
||||||
|
<a href="/docs/providers/aws/r/sns_topic_subscription.html">aws_sns_topic_subscription</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
<li<%= sidebar_current("docs-aws-resource-security-group") %>>
|
<li<%= sidebar_current("docs-aws-resource-security-group") %>>
|
||||||
<a href="/docs/providers/aws/r/security_group.html">aws_security_group</a>
|
<a href="/docs/providers/aws/r/security_group.html">aws_security_group</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
Loading…
Reference in New Issue