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:
Clint Shryock 2015-05-28 10:13:58 -05:00
commit 3f68ea7d0e
37 changed files with 1184 additions and 91 deletions

View File

@ -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]

View File

@ -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)

View File

@ -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(),

View File

@ -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"

View File

@ -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 ""
}
}

View File

@ -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())

View File

@ -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 {

View File

@ -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
}

View File

@ -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
}

View File

@ -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}"
}
`

View File

@ -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"
}
`

View File

@ -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
} }

View File

@ -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))

View File

@ -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:
} }

View File

@ -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'

View File

@ -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{

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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
} }
} }

View File

@ -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,

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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).

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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
@ -36,3 +36,4 @@ 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

View File

@ -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.

View File

@ -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}"
} }
``` ```

View File

@ -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>