provider/aws: Enforced kms_key_* attributes to be ARNs (#10356)
* Added kms_key_* validation to force ARNs * Added Redshift Cluster KMS key test * Added cloudtrail kms key test * Added EBS volume kms key * Added Elastic Transcoder Pipeline kms key arn test
This commit is contained in:
parent
b15b8bd99a
commit
5481e9ecb3
|
@ -107,7 +107,7 @@ func TestAccDataSourceAWSS3BucketObject_kmsEncrypted(t *testing.T) {
|
|||
resource.TestMatchResourceAttr("data.aws_s3_bucket_object.obj", "etag", regexp.MustCompile("^[a-f0-9]{32}$")),
|
||||
resource.TestCheckResourceAttr("data.aws_s3_bucket_object.obj", "server_side_encryption", "aws:kms"),
|
||||
resource.TestMatchResourceAttr("data.aws_s3_bucket_object.obj", "sse_kms_key_id",
|
||||
regexp.MustCompile("^arn:aws:kms:us-west-2:[0-9]{12}:key/[a-z0-9-]{36}$")),
|
||||
regexp.MustCompile("^arn:aws:kms:[a-z]{2}-[a-z]+-\\d{1}:[0-9]{12}:key/[a-z0-9-]{36}$")),
|
||||
resource.TestMatchResourceAttr("data.aws_s3_bucket_object.obj", "last_modified",
|
||||
regexp.MustCompile("^[a-zA-Z]{3}, [0-9]+ [a-zA-Z]+ [0-9]{4} [0-9:]+ [A-Z]+$")),
|
||||
resource.TestCheckResourceAttr("data.aws_s3_bucket_object.obj", "body", "Keep Calm and Carry On"),
|
||||
|
|
|
@ -20,60 +20,61 @@ func resourceAwsCloudTrail() *schema.Resource {
|
|||
},
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": &schema.Schema{
|
||||
"name": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
"enable_logging": &schema.Schema{
|
||||
"enable_logging": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: true,
|
||||
},
|
||||
"s3_bucket_name": &schema.Schema{
|
||||
"s3_bucket_name": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
"s3_key_prefix": &schema.Schema{
|
||||
"s3_key_prefix": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
"cloud_watch_logs_role_arn": &schema.Schema{
|
||||
"cloud_watch_logs_role_arn": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
"cloud_watch_logs_group_arn": &schema.Schema{
|
||||
"cloud_watch_logs_group_arn": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
"include_global_service_events": &schema.Schema{
|
||||
"include_global_service_events": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: true,
|
||||
},
|
||||
"is_multi_region_trail": &schema.Schema{
|
||||
"is_multi_region_trail": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: false,
|
||||
},
|
||||
"sns_topic_name": &schema.Schema{
|
||||
"sns_topic_name": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
"enable_log_file_validation": &schema.Schema{
|
||||
"enable_log_file_validation": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: false,
|
||||
},
|
||||
"kms_key_id": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
"kms_key_id": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ValidateFunc: validateArn,
|
||||
},
|
||||
"home_region": &schema.Schema{
|
||||
"home_region": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
"arn": &schema.Schema{
|
||||
"arn": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"github.com/hashicorp/terraform/helper/acctest"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
func TestAccAWSCloudTrail_basic(t *testing.T) {
|
||||
|
@ -21,7 +22,7 @@ func TestAccAWSCloudTrail_basic(t *testing.T) {
|
|||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAWSCloudTrailDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
{
|
||||
Config: testAccAWSCloudTrailConfig(cloudTrailRandInt),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckCloudTrailExists("aws_cloudtrail.foobar", &trail),
|
||||
|
@ -30,7 +31,7 @@ func TestAccAWSCloudTrail_basic(t *testing.T) {
|
|||
testAccCheckCloudTrailKmsKeyIdEquals("aws_cloudtrail.foobar", "", &trail),
|
||||
),
|
||||
},
|
||||
resource.TestStep{
|
||||
{
|
||||
Config: testAccAWSCloudTrailConfigModified(cloudTrailRandInt),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckCloudTrailExists("aws_cloudtrail.foobar", &trail),
|
||||
|
@ -53,7 +54,7 @@ func TestAccAWSCloudTrail_enable_logging(t *testing.T) {
|
|||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAWSCloudTrailDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
{
|
||||
Config: testAccAWSCloudTrailConfig(cloudTrailRandInt),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckCloudTrailExists("aws_cloudtrail.foobar", &trail),
|
||||
|
@ -64,7 +65,7 @@ func TestAccAWSCloudTrail_enable_logging(t *testing.T) {
|
|||
testAccCheckCloudTrailKmsKeyIdEquals("aws_cloudtrail.foobar", "", &trail),
|
||||
),
|
||||
},
|
||||
resource.TestStep{
|
||||
{
|
||||
Config: testAccAWSCloudTrailConfigModified(cloudTrailRandInt),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckCloudTrailExists("aws_cloudtrail.foobar", &trail),
|
||||
|
@ -73,7 +74,7 @@ func TestAccAWSCloudTrail_enable_logging(t *testing.T) {
|
|||
testAccCheckCloudTrailKmsKeyIdEquals("aws_cloudtrail.foobar", "", &trail),
|
||||
),
|
||||
},
|
||||
resource.TestStep{
|
||||
{
|
||||
Config: testAccAWSCloudTrailConfig(cloudTrailRandInt),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckCloudTrailExists("aws_cloudtrail.foobar", &trail),
|
||||
|
@ -95,7 +96,7 @@ func TestAccAWSCloudTrail_is_multi_region(t *testing.T) {
|
|||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAWSCloudTrailDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
{
|
||||
Config: testAccAWSCloudTrailConfig(cloudTrailRandInt),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckCloudTrailExists("aws_cloudtrail.foobar", &trail),
|
||||
|
@ -104,7 +105,7 @@ func TestAccAWSCloudTrail_is_multi_region(t *testing.T) {
|
|||
testAccCheckCloudTrailKmsKeyIdEquals("aws_cloudtrail.foobar", "", &trail),
|
||||
),
|
||||
},
|
||||
resource.TestStep{
|
||||
{
|
||||
Config: testAccAWSCloudTrailConfigMultiRegion(cloudTrailRandInt),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckCloudTrailExists("aws_cloudtrail.foobar", &trail),
|
||||
|
@ -113,7 +114,7 @@ func TestAccAWSCloudTrail_is_multi_region(t *testing.T) {
|
|||
testAccCheckCloudTrailKmsKeyIdEquals("aws_cloudtrail.foobar", "", &trail),
|
||||
),
|
||||
},
|
||||
resource.TestStep{
|
||||
{
|
||||
Config: testAccAWSCloudTrailConfig(cloudTrailRandInt),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckCloudTrailExists("aws_cloudtrail.foobar", &trail),
|
||||
|
@ -130,14 +131,12 @@ func TestAccAWSCloudTrail_logValidation(t *testing.T) {
|
|||
var trail cloudtrail.Trail
|
||||
cloudTrailRandInt := acctest.RandInt()
|
||||
|
||||
// TODO: Add test for KMS Key ID
|
||||
// once https://github.com/hashicorp/terraform/pull/3928 is merged
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAWSCloudTrailDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
{
|
||||
Config: testAccAWSCloudTrailConfig_logValidation(cloudTrailRandInt),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckCloudTrailExists("aws_cloudtrail.foobar", &trail),
|
||||
|
@ -147,7 +146,7 @@ func TestAccAWSCloudTrail_logValidation(t *testing.T) {
|
|||
testAccCheckCloudTrailKmsKeyIdEquals("aws_cloudtrail.foobar", "", &trail),
|
||||
),
|
||||
},
|
||||
resource.TestStep{
|
||||
{
|
||||
Config: testAccAWSCloudTrailConfig_logValidationModified(cloudTrailRandInt),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckCloudTrailExists("aws_cloudtrail.foobar", &trail),
|
||||
|
@ -161,6 +160,30 @@ func TestAccAWSCloudTrail_logValidation(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestAccAWSCloudTrail_kmsKey(t *testing.T) {
|
||||
var trail cloudtrail.Trail
|
||||
cloudTrailRandInt := acctest.RandInt()
|
||||
keyRegex := regexp.MustCompile("^arn:aws:([a-zA-Z0-9\\-])+:([a-z]{2}-[a-z]+-\\d{1})?:(\\d{12})?:(.*)$")
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAWSCloudTrailDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccAWSCloudTrailConfig_kmsKey(cloudTrailRandInt),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckCloudTrailExists("aws_cloudtrail.foobar", &trail),
|
||||
resource.TestCheckResourceAttr("aws_cloudtrail.foobar", "s3_key_prefix", ""),
|
||||
resource.TestCheckResourceAttr("aws_cloudtrail.foobar", "include_global_service_events", "true"),
|
||||
testAccCheckCloudTrailLogValidationEnabled("aws_cloudtrail.foobar", false, &trail),
|
||||
resource.TestMatchResourceAttr("aws_cloudtrail.foobar", "kms_key_id", keyRegex),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccAWSCloudTrail_tags(t *testing.T) {
|
||||
var trail cloudtrail.Trail
|
||||
var trailTags []*cloudtrail.Tag
|
||||
|
@ -172,7 +195,7 @@ func TestAccAWSCloudTrail_tags(t *testing.T) {
|
|||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAWSCloudTrailDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
{
|
||||
Config: testAccAWSCloudTrailConfig_tags(cloudTrailRandInt),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckCloudTrailExists("aws_cloudtrail.foobar", &trail),
|
||||
|
@ -183,7 +206,7 @@ func TestAccAWSCloudTrail_tags(t *testing.T) {
|
|||
testAccCheckCloudTrailKmsKeyIdEquals("aws_cloudtrail.foobar", "", &trail),
|
||||
),
|
||||
},
|
||||
resource.TestStep{
|
||||
{
|
||||
Config: testAccAWSCloudTrailConfig_tagsModified(cloudTrailRandInt),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckCloudTrailExists("aws_cloudtrail.foobar", &trail),
|
||||
|
@ -194,7 +217,7 @@ func TestAccAWSCloudTrail_tags(t *testing.T) {
|
|||
testAccCheckCloudTrailKmsKeyIdEquals("aws_cloudtrail.foobar", "", &trail),
|
||||
),
|
||||
},
|
||||
resource.TestStep{
|
||||
{
|
||||
Config: testAccAWSCloudTrailConfig_tagsModifiedAgain(cloudTrailRandInt),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckCloudTrailExists("aws_cloudtrail.foobar", &trail),
|
||||
|
@ -577,6 +600,69 @@ POLICY
|
|||
`, cloudTrailRandInt, cloudTrailRandInt, cloudTrailRandInt, cloudTrailRandInt)
|
||||
}
|
||||
|
||||
func testAccAWSCloudTrailConfig_kmsKey(cloudTrailRandInt int) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "aws_kms_key" "foo" {
|
||||
description = "Terraform acc test %d"
|
||||
policy = <<POLICY
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Id": "kms-tf-1",
|
||||
"Statement": [
|
||||
{
|
||||
"Sid": "Enable IAM User Permissions",
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"AWS": "*"
|
||||
},
|
||||
"Action": "kms:*",
|
||||
"Resource": "*"
|
||||
}
|
||||
]
|
||||
}
|
||||
POLICY
|
||||
}
|
||||
|
||||
resource "aws_cloudtrail" "foobar" {
|
||||
name = "tf-acc-trail-log-validation-test-%d"
|
||||
s3_bucket_name = "${aws_s3_bucket.foo.id}"
|
||||
include_global_service_events = true
|
||||
kms_key_id = "${aws_kms_key.foo.arn}"
|
||||
}
|
||||
|
||||
resource "aws_s3_bucket" "foo" {
|
||||
bucket = "tf-test-trail-%d"
|
||||
force_destroy = true
|
||||
policy = <<POLICY
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Sid": "AWSCloudTrailAclCheck",
|
||||
"Effect": "Allow",
|
||||
"Principal": "*",
|
||||
"Action": "s3:GetBucketAcl",
|
||||
"Resource": "arn:aws:s3:::tf-test-trail-%d"
|
||||
},
|
||||
{
|
||||
"Sid": "AWSCloudTrailWrite",
|
||||
"Effect": "Allow",
|
||||
"Principal": "*",
|
||||
"Action": "s3:PutObject",
|
||||
"Resource": "arn:aws:s3:::tf-test-trail-%d/*",
|
||||
"Condition": {
|
||||
"StringEquals": {
|
||||
"s3:x-amz-acl": "bucket-owner-full-control"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
POLICY
|
||||
}
|
||||
`, cloudTrailRandInt, cloudTrailRandInt, cloudTrailRandInt, cloudTrailRandInt, cloudTrailRandInt)
|
||||
}
|
||||
|
||||
var testAccAWSCloudTrailConfig_tags_tpl = `
|
||||
resource "aws_cloudtrail" "foobar" {
|
||||
name = "tf-acc-trail-log-validation-test-%d"
|
||||
|
|
|
@ -26,32 +26,32 @@ func resourceAwsDbInstance() *schema.Resource {
|
|||
},
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": &schema.Schema{
|
||||
"name": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"arn": &schema.Schema{
|
||||
"arn": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"username": &schema.Schema{
|
||||
"username": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"password": &schema.Schema{
|
||||
"password": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Sensitive: true,
|
||||
},
|
||||
|
||||
"engine": &schema.Schema{
|
||||
"engine": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
|
@ -62,38 +62,38 @@ func resourceAwsDbInstance() *schema.Resource {
|
|||
},
|
||||
},
|
||||
|
||||
"engine_version": &schema.Schema{
|
||||
"engine_version": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"character_set_name": &schema.Schema{
|
||||
"character_set_name": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"storage_encrypted": &schema.Schema{
|
||||
"storage_encrypted": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"allocated_storage": &schema.Schema{
|
||||
"allocated_storage": {
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"storage_type": &schema.Schema{
|
||||
"storage_type": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"identifier": &schema.Schema{
|
||||
"identifier": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
|
@ -101,42 +101,42 @@ func resourceAwsDbInstance() *schema.Resource {
|
|||
ValidateFunc: validateRdsId,
|
||||
},
|
||||
|
||||
"instance_class": &schema.Schema{
|
||||
"instance_class": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
|
||||
"availability_zone": &schema.Schema{
|
||||
"availability_zone": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"backup_retention_period": &schema.Schema{
|
||||
"backup_retention_period": {
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"backup_window": &schema.Schema{
|
||||
"backup_window": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"iops": &schema.Schema{
|
||||
"iops": {
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
},
|
||||
|
||||
"license_model": &schema.Schema{
|
||||
"license_model": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"maintenance_window": &schema.Schema{
|
||||
"maintenance_window": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
|
@ -149,25 +149,25 @@ func resourceAwsDbInstance() *schema.Resource {
|
|||
},
|
||||
},
|
||||
|
||||
"multi_az": &schema.Schema{
|
||||
"multi_az": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"port": &schema.Schema{
|
||||
"port": {
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"publicly_accessible": &schema.Schema{
|
||||
"publicly_accessible": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: false,
|
||||
},
|
||||
|
||||
"vpc_security_group_ids": &schema.Schema{
|
||||
"vpc_security_group_ids": {
|
||||
Type: schema.TypeSet,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
|
@ -175,14 +175,14 @@ func resourceAwsDbInstance() *schema.Resource {
|
|||
Set: schema.HashString,
|
||||
},
|
||||
|
||||
"security_group_names": &schema.Schema{
|
||||
"security_group_names": {
|
||||
Type: schema.TypeSet,
|
||||
Optional: true,
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
Set: schema.HashString,
|
||||
},
|
||||
|
||||
"final_snapshot_identifier": &schema.Schema{
|
||||
"final_snapshot_identifier": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ValidateFunc: func(v interface{}, k string) (ws []string, es []error) {
|
||||
|
@ -201,47 +201,47 @@ func resourceAwsDbInstance() *schema.Resource {
|
|||
},
|
||||
},
|
||||
|
||||
"skip_final_snapshot": &schema.Schema{
|
||||
"skip_final_snapshot": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: true,
|
||||
},
|
||||
|
||||
"copy_tags_to_snapshot": &schema.Schema{
|
||||
"copy_tags_to_snapshot": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: false,
|
||||
},
|
||||
|
||||
"db_subnet_group_name": &schema.Schema{
|
||||
"db_subnet_group_name": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"parameter_group_name": &schema.Schema{
|
||||
"parameter_group_name": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"address": &schema.Schema{
|
||||
"address": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"endpoint": &schema.Schema{
|
||||
"endpoint": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"hosted_zone_id": &schema.Schema{
|
||||
"hosted_zone_id": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"status": &schema.Schema{
|
||||
"status": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
@ -249,24 +249,24 @@ func resourceAwsDbInstance() *schema.Resource {
|
|||
// apply_immediately is used to determine when the update modifications
|
||||
// take place.
|
||||
// See http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Overview.DBInstance.Modifying.html
|
||||
"apply_immediately": &schema.Schema{
|
||||
"apply_immediately": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"replicate_source_db": &schema.Schema{
|
||||
"replicate_source_db": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
|
||||
"replicas": &schema.Schema{
|
||||
"replicas": {
|
||||
Type: schema.TypeList,
|
||||
Computed: true,
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
},
|
||||
|
||||
"snapshot_identifier": &schema.Schema{
|
||||
"snapshot_identifier": {
|
||||
Type: schema.TypeString,
|
||||
Computed: false,
|
||||
Optional: true,
|
||||
|
@ -274,41 +274,42 @@ func resourceAwsDbInstance() *schema.Resource {
|
|||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
},
|
||||
|
||||
"auto_minor_version_upgrade": &schema.Schema{
|
||||
"auto_minor_version_upgrade": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: true,
|
||||
},
|
||||
|
||||
"allow_major_version_upgrade": &schema.Schema{
|
||||
"allow_major_version_upgrade": {
|
||||
Type: schema.TypeBool,
|
||||
Computed: false,
|
||||
Optional: true,
|
||||
},
|
||||
|
||||
"monitoring_role_arn": &schema.Schema{
|
||||
"monitoring_role_arn": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"monitoring_interval": &schema.Schema{
|
||||
"monitoring_interval": {
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
Default: 0,
|
||||
},
|
||||
|
||||
"option_group_name": &schema.Schema{
|
||||
"option_group_name": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"kms_key_id": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
"kms_key_id": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
ValidateFunc: validateArn,
|
||||
},
|
||||
|
||||
"tags": tagsSchema(),
|
||||
|
|
|
@ -25,42 +25,43 @@ func resourceAwsEbsVolume() *schema.Resource {
|
|||
},
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"availability_zone": &schema.Schema{
|
||||
"availability_zone": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
"encrypted": &schema.Schema{
|
||||
"encrypted": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
"iops": &schema.Schema{
|
||||
"iops": {
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
"kms_key_id": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
"kms_key_id": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
ValidateFunc: validateArn,
|
||||
},
|
||||
"size": &schema.Schema{
|
||||
"size": {
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
"snapshot_id": &schema.Schema{
|
||||
"snapshot_id": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
"type": &schema.Schema{
|
||||
"type": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
|
|
|
@ -6,8 +6,10 @@ import (
|
|||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/hashicorp/terraform/helper/acctest"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
func TestAccAWSEBSVolume_basic(t *testing.T) {
|
||||
|
@ -17,7 +19,7 @@ func TestAccAWSEBSVolume_basic(t *testing.T) {
|
|||
IDRefreshName: "aws_ebs_volume.test",
|
||||
Providers: testAccProviders,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
{
|
||||
Config: testAccAwsEbsVolumeConfig,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckVolumeExists("aws_ebs_volume.test", &v),
|
||||
|
@ -27,13 +29,36 @@ func TestAccAWSEBSVolume_basic(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestAccAWSEBSVolume_kmsKey(t *testing.T) {
|
||||
var v ec2.Volume
|
||||
ri := acctest.RandInt()
|
||||
config := fmt.Sprintf(testAccAwsEbsVolumeConfigWithKmsKey, ri)
|
||||
keyRegex := regexp.MustCompile("^arn:aws:([a-zA-Z0-9\\-])+:([a-z]{2}-[a-z]+-\\d{1})?:(\\d{12})?:(.*)$")
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
IDRefreshName: "aws_ebs_volume.test",
|
||||
Providers: testAccProviders,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: config,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckVolumeExists("aws_ebs_volume.test", &v),
|
||||
resource.TestCheckResourceAttr("aws_ebs_volume.test", "encrypted", "true"),
|
||||
resource.TestMatchResourceAttr("aws_ebs_volume.test", "kms_key_id", keyRegex),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccAWSEBSVolume_NoIops(t *testing.T) {
|
||||
var v ec2.Volume
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
{
|
||||
Config: testAccAwsEbsVolumeConfigWithNoIops,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckVolumeExists("aws_ebs_volume.iops_test", &v),
|
||||
|
@ -50,7 +75,7 @@ func TestAccAWSEBSVolume_withTags(t *testing.T) {
|
|||
IDRefreshName: "aws_ebs_volume.tags_test",
|
||||
Providers: testAccProviders,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
{
|
||||
Config: testAccAwsEbsVolumeConfigWithTags,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckVolumeExists("aws_ebs_volume.tags_test", &v),
|
||||
|
@ -90,29 +115,59 @@ func testAccCheckVolumeExists(n string, v *ec2.Volume) resource.TestCheckFunc {
|
|||
|
||||
const testAccAwsEbsVolumeConfig = `
|
||||
resource "aws_ebs_volume" "test" {
|
||||
availability_zone = "us-west-2a"
|
||||
size = 1
|
||||
availability_zone = "us-west-2a"
|
||||
size = 1
|
||||
}
|
||||
`
|
||||
|
||||
const testAccAwsEbsVolumeConfigWithKmsKey = `
|
||||
resource "aws_kms_key" "foo" {
|
||||
description = "Terraform acc test %d"
|
||||
policy = <<POLICY
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Id": "kms-tf-1",
|
||||
"Statement": [
|
||||
{
|
||||
"Sid": "Enable IAM User Permissions",
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"AWS": "*"
|
||||
},
|
||||
"Action": "kms:*",
|
||||
"Resource": "*"
|
||||
}
|
||||
]
|
||||
}
|
||||
POLICY
|
||||
}
|
||||
|
||||
resource "aws_ebs_volume" "test" {
|
||||
availability_zone = "us-west-2a"
|
||||
size = 1
|
||||
encrypted = true
|
||||
kms_key_id = "${aws_kms_key.foo.arn}"
|
||||
}
|
||||
`
|
||||
|
||||
const testAccAwsEbsVolumeConfigWithTags = `
|
||||
resource "aws_ebs_volume" "tags_test" {
|
||||
availability_zone = "us-west-2a"
|
||||
size = 1
|
||||
tags {
|
||||
Name = "TerraformTest"
|
||||
}
|
||||
availability_zone = "us-west-2a"
|
||||
size = 1
|
||||
tags {
|
||||
Name = "TerraformTest"
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const testAccAwsEbsVolumeConfigWithNoIops = `
|
||||
resource "aws_ebs_volume" "iops_test" {
|
||||
availability_zone = "us-west-2a"
|
||||
size = 10
|
||||
availability_zone = "us-west-2a"
|
||||
size = 10
|
||||
type = "gp2"
|
||||
iops = 0
|
||||
tags {
|
||||
Name = "TerraformTest"
|
||||
}
|
||||
iops = 0
|
||||
tags {
|
||||
Name = "TerraformTest"
|
||||
}
|
||||
}
|
||||
`
|
||||
|
|
|
@ -20,18 +20,19 @@ func resourceAwsElasticTranscoderPipeline() *schema.Resource {
|
|||
Delete: resourceAwsElasticTranscoderPipelineDelete,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"arn": &schema.Schema{
|
||||
"arn": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"aws_kms_key_arn": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
"aws_kms_key_arn": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ValidateFunc: validateArn,
|
||||
},
|
||||
|
||||
// ContentConfig also requires ThumbnailConfig
|
||||
"content_config": &schema.Schema{
|
||||
"content_config": {
|
||||
Type: schema.TypeSet,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
|
@ -39,13 +40,13 @@ func resourceAwsElasticTranscoderPipeline() *schema.Resource {
|
|||
Elem: &schema.Resource{
|
||||
// elastictranscoder.PipelineOutputConfig
|
||||
Schema: map[string]*schema.Schema{
|
||||
"bucket": &schema.Schema{
|
||||
"bucket": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
// AWS may insert the bucket name here taken from output_bucket
|
||||
Computed: true,
|
||||
},
|
||||
"storage_class": &schema.Schema{
|
||||
"storage_class": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
|
@ -53,21 +54,21 @@ func resourceAwsElasticTranscoderPipeline() *schema.Resource {
|
|||
},
|
||||
},
|
||||
|
||||
"content_config_permissions": &schema.Schema{
|
||||
"content_config_permissions": {
|
||||
Type: schema.TypeSet,
|
||||
Optional: true,
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"access": &schema.Schema{
|
||||
"access": {
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
},
|
||||
"grantee": &schema.Schema{
|
||||
"grantee": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
"grantee_type": &schema.Schema{
|
||||
"grantee_type": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
|
@ -75,12 +76,12 @@ func resourceAwsElasticTranscoderPipeline() *schema.Resource {
|
|||
},
|
||||
},
|
||||
|
||||
"input_bucket": &schema.Schema{
|
||||
"input_bucket": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
|
||||
"name": &schema.Schema{
|
||||
"name": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
|
@ -98,25 +99,25 @@ func resourceAwsElasticTranscoderPipeline() *schema.Resource {
|
|||
},
|
||||
},
|
||||
|
||||
"notifications": &schema.Schema{
|
||||
"notifications": {
|
||||
Type: schema.TypeSet,
|
||||
Optional: true,
|
||||
MaxItems: 1,
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"completed": &schema.Schema{
|
||||
"completed": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
"error": &schema.Schema{
|
||||
"error": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
"progressing": &schema.Schema{
|
||||
"progressing": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
"warning": &schema.Schema{
|
||||
"warning": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
|
@ -128,18 +129,18 @@ func resourceAwsElasticTranscoderPipeline() *schema.Resource {
|
|||
// and thumbnail_config.bucket.
|
||||
// This is set as Computed, because the API may or may not return
|
||||
// this as set based on the other 2 configurations.
|
||||
"output_bucket": &schema.Schema{
|
||||
"output_bucket": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"role": &schema.Schema{
|
||||
"role": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
|
||||
"thumbnail_config": &schema.Schema{
|
||||
"thumbnail_config": {
|
||||
Type: schema.TypeSet,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
|
@ -147,13 +148,13 @@ func resourceAwsElasticTranscoderPipeline() *schema.Resource {
|
|||
Elem: &schema.Resource{
|
||||
// elastictranscoder.PipelineOutputConfig
|
||||
Schema: map[string]*schema.Schema{
|
||||
"bucket": &schema.Schema{
|
||||
"bucket": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
// AWS may insert the bucket name here taken from output_bucket
|
||||
Computed: true,
|
||||
},
|
||||
"storage_class": &schema.Schema{
|
||||
"storage_class": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
|
@ -161,21 +162,21 @@ func resourceAwsElasticTranscoderPipeline() *schema.Resource {
|
|||
},
|
||||
},
|
||||
|
||||
"thumbnail_config_permissions": &schema.Schema{
|
||||
"thumbnail_config_permissions": {
|
||||
Type: schema.TypeSet,
|
||||
Optional: true,
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"access": &schema.Schema{
|
||||
"access": {
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
},
|
||||
"grantee": &schema.Schema{
|
||||
"grantee": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
"grantee_type": &schema.Schema{
|
||||
"grantee_type": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"github.com/hashicorp/terraform/helper/acctest"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
func TestAccAWSElasticTranscoderPipeline_basic(t *testing.T) {
|
||||
|
@ -23,7 +24,7 @@ func TestAccAWSElasticTranscoderPipeline_basic(t *testing.T) {
|
|||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckElasticTranscoderPipelineDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
{
|
||||
Config: awsElasticTranscoderPipelineConfigBasic,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSElasticTranscoderPipelineExists("aws_elastictranscoder_pipeline.bar", pipeline),
|
||||
|
@ -33,6 +34,29 @@ func TestAccAWSElasticTranscoderPipeline_basic(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestAccAWSElasticTranscoderPipeline_kmsKey(t *testing.T) {
|
||||
pipeline := &elastictranscoder.Pipeline{}
|
||||
ri := acctest.RandInt()
|
||||
config := fmt.Sprintf(awsElasticTranscoderPipelineConfigKmsKey, ri)
|
||||
keyRegex := regexp.MustCompile("^arn:aws:([a-zA-Z0-9\\-])+:([a-z]{2}-[a-z]+-\\d{1})?:(\\d{12})?:(.*)$")
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
IDRefreshName: "aws_elastictranscoder_pipeline.bar",
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckElasticTranscoderPipelineDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: config,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSElasticTranscoderPipelineExists("aws_elastictranscoder_pipeline.bar", pipeline),
|
||||
resource.TestMatchResourceAttr("aws_elastictranscoder_pipeline.bar", "aws_kms_key_arn", keyRegex),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccAWSElasticTranscoderPipeline_notifications(t *testing.T) {
|
||||
pipeline := elastictranscoder.Pipeline{}
|
||||
|
||||
|
@ -44,7 +68,7 @@ func TestAccAWSElasticTranscoderPipeline_notifications(t *testing.T) {
|
|||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckElasticTranscoderPipelineDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
{
|
||||
Config: awsElasticTranscoderNotifications(rInt),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSElasticTranscoderPipelineExists("aws_elastictranscoder_pipeline.bar", &pipeline),
|
||||
|
@ -107,13 +131,13 @@ func TestAccAWSElasticTranscoderPipeline_withContentConfig(t *testing.T) {
|
|||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckElasticTranscoderPipelineDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
{
|
||||
Config: awsElasticTranscoderPipelineWithContentConfig,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSElasticTranscoderPipelineExists("aws_elastictranscoder_pipeline.bar", pipeline),
|
||||
),
|
||||
},
|
||||
resource.TestStep{
|
||||
{
|
||||
Config: awsElasticTranscoderPipelineWithContentConfigUpdate,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSElasticTranscoderPipelineExists("aws_elastictranscoder_pipeline.bar", pipeline),
|
||||
|
@ -132,7 +156,7 @@ func TestAccAWSElasticTranscoderPipeline_withPermissions(t *testing.T) {
|
|||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckElasticTranscoderPipelineDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
{
|
||||
Config: awsElasticTranscoderPipelineWithPerms,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSElasticTranscoderPipelineExists("aws_elastictranscoder_pipeline.baz", pipeline),
|
||||
|
@ -234,6 +258,62 @@ resource "aws_s3_bucket" "test_bucket" {
|
|||
}
|
||||
`
|
||||
|
||||
const awsElasticTranscoderPipelineConfigKmsKey = `
|
||||
resource "aws_kms_key" "foo" {
|
||||
description = "Terraform acc test %d"
|
||||
policy = <<POLICY
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Id": "kms-tf-1",
|
||||
"Statement": [
|
||||
{
|
||||
"Sid": "Enable IAM User Permissions",
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"AWS": "*"
|
||||
},
|
||||
"Action": "kms:*",
|
||||
"Resource": "*"
|
||||
}
|
||||
]
|
||||
}
|
||||
POLICY
|
||||
}
|
||||
|
||||
resource "aws_elastictranscoder_pipeline" "bar" {
|
||||
input_bucket = "${aws_s3_bucket.test_bucket.bucket}"
|
||||
output_bucket = "${aws_s3_bucket.test_bucket.bucket}"
|
||||
name = "aws_elastictranscoder_pipeline_tf_test_"
|
||||
role = "${aws_iam_role.test_role.arn}"
|
||||
aws_kms_key_arn = "${aws_kms_key.foo.arn}"
|
||||
}
|
||||
|
||||
resource "aws_iam_role" "test_role" {
|
||||
name = "aws_elastictranscoder_pipeline_tf_test_role_"
|
||||
|
||||
assume_role_policy = <<EOF
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Action": "sts:AssumeRole",
|
||||
"Principal": {
|
||||
"Service": "ec2.amazonaws.com"
|
||||
},
|
||||
"Effect": "Allow",
|
||||
"Sid": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
EOF
|
||||
}
|
||||
|
||||
resource "aws_s3_bucket" "test_bucket" {
|
||||
bucket = "aws-elasticencoder-pipeline-tf-test-bucket"
|
||||
acl = "private"
|
||||
}
|
||||
`
|
||||
|
||||
const awsElasticTranscoderPipelineWithContentConfig = `
|
||||
resource "aws_elastictranscoder_pipeline" "bar" {
|
||||
input_bucket = "${aws_s3_bucket.content_bucket.bucket}"
|
||||
|
|
|
@ -150,8 +150,9 @@ func resourceAwsKinesisFirehoseDeliveryStream() *schema.Resource {
|
|||
},
|
||||
|
||||
"kms_key_arn": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ValidateFunc: validateArn,
|
||||
},
|
||||
|
||||
"role_arn": {
|
||||
|
|
|
@ -26,7 +26,7 @@ func resourceAwsRDSCluster() *schema.Resource {
|
|||
|
||||
Schema: map[string]*schema.Schema{
|
||||
|
||||
"availability_zones": &schema.Schema{
|
||||
"availability_zones": {
|
||||
Type: schema.TypeSet,
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
Optional: true,
|
||||
|
@ -35,14 +35,14 @@ func resourceAwsRDSCluster() *schema.Resource {
|
|||
Set: schema.HashString,
|
||||
},
|
||||
|
||||
"cluster_identifier": &schema.Schema{
|
||||
"cluster_identifier": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
ValidateFunc: validateRdsId,
|
||||
},
|
||||
|
||||
"cluster_members": &schema.Schema{
|
||||
"cluster_members": {
|
||||
Type: schema.TypeSet,
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
Optional: true,
|
||||
|
@ -50,14 +50,14 @@ func resourceAwsRDSCluster() *schema.Resource {
|
|||
Set: schema.HashString,
|
||||
},
|
||||
|
||||
"database_name": &schema.Schema{
|
||||
"database_name": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"db_subnet_group_name": &schema.Schema{
|
||||
"db_subnet_group_name": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
|
@ -67,42 +67,42 @@ func resourceAwsRDSCluster() *schema.Resource {
|
|||
// TODO: remove parameter_group_name
|
||||
// See https://github.com/hashicorp/terraform/issues/7046
|
||||
// Likely need migration to remove from state
|
||||
"parameter_group_name": &schema.Schema{
|
||||
"parameter_group_name": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
Deprecated: "Use db_cluster_parameter_group_name instead. This attribute will be removed in a future version",
|
||||
},
|
||||
|
||||
"db_cluster_parameter_group_name": &schema.Schema{
|
||||
"db_cluster_parameter_group_name": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"endpoint": &schema.Schema{
|
||||
"endpoint": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"reader_endpoint": &schema.Schema{
|
||||
"reader_endpoint": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"engine": &schema.Schema{
|
||||
"engine": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"storage_encrypted": &schema.Schema{
|
||||
"storage_encrypted": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: false,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"final_snapshot_identifier": &schema.Schema{
|
||||
"final_snapshot_identifier": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ValidateFunc: func(v interface{}, k string) (ws []string, es []error) {
|
||||
|
@ -121,32 +121,32 @@ func resourceAwsRDSCluster() *schema.Resource {
|
|||
},
|
||||
},
|
||||
|
||||
"skip_final_snapshot": &schema.Schema{
|
||||
"skip_final_snapshot": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: true,
|
||||
},
|
||||
|
||||
"master_username": &schema.Schema{
|
||||
"master_username": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"master_password": &schema.Schema{
|
||||
"master_password": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
|
||||
"snapshot_identifier": &schema.Schema{
|
||||
"snapshot_identifier": {
|
||||
Type: schema.TypeString,
|
||||
Computed: false,
|
||||
Optional: true,
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
},
|
||||
|
||||
"port": &schema.Schema{
|
||||
"port": {
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
|
@ -155,13 +155,13 @@ func resourceAwsRDSCluster() *schema.Resource {
|
|||
// apply_immediately is used to determine when the update modifications
|
||||
// take place.
|
||||
// See http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Overview.DBInstance.Modifying.html
|
||||
"apply_immediately": &schema.Schema{
|
||||
"apply_immediately": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"vpc_security_group_ids": &schema.Schema{
|
||||
"vpc_security_group_ids": {
|
||||
Type: schema.TypeSet,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
|
@ -169,13 +169,13 @@ func resourceAwsRDSCluster() *schema.Resource {
|
|||
Set: schema.HashString,
|
||||
},
|
||||
|
||||
"preferred_backup_window": &schema.Schema{
|
||||
"preferred_backup_window": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"preferred_maintenance_window": &schema.Schema{
|
||||
"preferred_maintenance_window": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
|
@ -187,7 +187,7 @@ func resourceAwsRDSCluster() *schema.Resource {
|
|||
},
|
||||
},
|
||||
|
||||
"backup_retention_period": &schema.Schema{
|
||||
"backup_retention_period": {
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
Default: 1,
|
||||
|
@ -201,11 +201,12 @@ func resourceAwsRDSCluster() *schema.Resource {
|
|||
},
|
||||
},
|
||||
|
||||
"kms_key_id": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
"kms_key_id": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
ValidateFunc: validateArn,
|
||||
},
|
||||
|
||||
"tags": tagsSchema(),
|
||||
|
|
|
@ -22,7 +22,7 @@ func TestAccAWSRDSCluster_basic(t *testing.T) {
|
|||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAWSClusterDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
{
|
||||
Config: testAccAWSClusterConfig(acctest.RandInt()),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSClusterExists("aws_rds_cluster.default", &v),
|
||||
|
@ -47,7 +47,7 @@ func TestAccAWSRDSCluster_updateTags(t *testing.T) {
|
|||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAWSClusterDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
{
|
||||
Config: testAccAWSClusterConfig(ri),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSClusterExists("aws_rds_cluster.default", &v),
|
||||
|
@ -55,7 +55,7 @@ func TestAccAWSRDSCluster_updateTags(t *testing.T) {
|
|||
"aws_rds_cluster.default", "tags.%", "1"),
|
||||
),
|
||||
},
|
||||
resource.TestStep{
|
||||
{
|
||||
Config: testAccAWSClusterConfigUpdatedTags(ri),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSClusterExists("aws_rds_cluster.default", &v),
|
||||
|
@ -76,7 +76,7 @@ func TestAccAWSRDSCluster_kmsKey(t *testing.T) {
|
|||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAWSClusterDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
{
|
||||
Config: testAccAWSClusterConfig_kmsKey(acctest.RandInt()),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSClusterExists("aws_rds_cluster.default", &v),
|
||||
|
@ -96,7 +96,7 @@ func TestAccAWSRDSCluster_encrypted(t *testing.T) {
|
|||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAWSClusterDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
{
|
||||
Config: testAccAWSClusterConfig_encrypted(acctest.RandInt()),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSClusterExists("aws_rds_cluster.default", &v),
|
||||
|
@ -119,7 +119,7 @@ func TestAccAWSRDSCluster_backupsUpdate(t *testing.T) {
|
|||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAWSClusterDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
{
|
||||
Config: testAccAWSClusterConfig_backups(ri),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSClusterExists("aws_rds_cluster.default", &v),
|
||||
|
|
|
@ -25,44 +25,44 @@ func resourceAwsRedshiftCluster() *schema.Resource {
|
|||
},
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"database_name": &schema.Schema{
|
||||
"database_name": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ValidateFunc: validateRedshiftClusterDbName,
|
||||
},
|
||||
|
||||
"cluster_identifier": &schema.Schema{
|
||||
"cluster_identifier": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
ValidateFunc: validateRedshiftClusterIdentifier,
|
||||
},
|
||||
"cluster_type": &schema.Schema{
|
||||
"cluster_type": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"node_type": &schema.Schema{
|
||||
"node_type": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
|
||||
"master_username": &schema.Schema{
|
||||
"master_username": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ValidateFunc: validateRedshiftClusterMasterUsername,
|
||||
},
|
||||
|
||||
"master_password": &schema.Schema{
|
||||
"master_password": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Sensitive: true,
|
||||
ValidateFunc: validateRedshiftClusterMasterPassword,
|
||||
},
|
||||
|
||||
"cluster_security_groups": &schema.Schema{
|
||||
"cluster_security_groups": {
|
||||
Type: schema.TypeSet,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
|
@ -70,7 +70,7 @@ func resourceAwsRedshiftCluster() *schema.Resource {
|
|||
Set: schema.HashString,
|
||||
},
|
||||
|
||||
"vpc_security_group_ids": &schema.Schema{
|
||||
"vpc_security_group_ids": {
|
||||
Type: schema.TypeSet,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
|
@ -78,20 +78,20 @@ func resourceAwsRedshiftCluster() *schema.Resource {
|
|||
Set: schema.HashString,
|
||||
},
|
||||
|
||||
"cluster_subnet_group_name": &schema.Schema{
|
||||
"cluster_subnet_group_name": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"availability_zone": &schema.Schema{
|
||||
"availability_zone": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"preferred_maintenance_window": &schema.Schema{
|
||||
"preferred_maintenance_window": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
|
@ -103,13 +103,13 @@ func resourceAwsRedshiftCluster() *schema.Resource {
|
|||
},
|
||||
},
|
||||
|
||||
"cluster_parameter_group_name": &schema.Schema{
|
||||
"cluster_parameter_group_name": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"automated_snapshot_retention_period": &schema.Schema{
|
||||
"automated_snapshot_retention_period": {
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
Default: 1,
|
||||
|
@ -123,91 +123,92 @@ func resourceAwsRedshiftCluster() *schema.Resource {
|
|||
},
|
||||
},
|
||||
|
||||
"port": &schema.Schema{
|
||||
"port": {
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
Default: 5439,
|
||||
},
|
||||
|
||||
"cluster_version": &schema.Schema{
|
||||
"cluster_version": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Default: "1.0",
|
||||
},
|
||||
|
||||
"allow_version_upgrade": &schema.Schema{
|
||||
"allow_version_upgrade": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: true,
|
||||
},
|
||||
|
||||
"number_of_nodes": &schema.Schema{
|
||||
"number_of_nodes": {
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
Default: 1,
|
||||
},
|
||||
|
||||
"publicly_accessible": &schema.Schema{
|
||||
"publicly_accessible": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: true,
|
||||
},
|
||||
|
||||
"encrypted": &schema.Schema{
|
||||
"encrypted": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"enhanced_vpc_routing": &schema.Schema{
|
||||
"enhanced_vpc_routing": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"kms_key_id": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
"kms_key_id": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
ValidateFunc: validateArn,
|
||||
},
|
||||
|
||||
"elastic_ip": &schema.Schema{
|
||||
"elastic_ip": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
|
||||
"final_snapshot_identifier": &schema.Schema{
|
||||
"final_snapshot_identifier": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ValidateFunc: validateRedshiftClusterFinalSnapshotIdentifier,
|
||||
},
|
||||
|
||||
"skip_final_snapshot": &schema.Schema{
|
||||
"skip_final_snapshot": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: true,
|
||||
},
|
||||
|
||||
"endpoint": &schema.Schema{
|
||||
"endpoint": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"cluster_public_key": &schema.Schema{
|
||||
"cluster_public_key": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"cluster_revision_number": &schema.Schema{
|
||||
"cluster_revision_number": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"iam_roles": &schema.Schema{
|
||||
"iam_roles": {
|
||||
Type: schema.TypeSet,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
|
@ -233,12 +234,12 @@ func resourceAwsRedshiftCluster() *schema.Resource {
|
|||
Computed: true,
|
||||
},
|
||||
|
||||
"snapshot_identifier": &schema.Schema{
|
||||
"snapshot_identifier": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
|
||||
"snapshot_cluster_identifier": &schema.Schema{
|
||||
"snapshot_cluster_identifier": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"github.com/aws/aws-sdk-go/service/redshift"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
func TestValidateRedshiftClusterDbName(t *testing.T) {
|
||||
|
@ -60,7 +61,7 @@ func TestAccAWSRedshiftCluster_basic(t *testing.T) {
|
|||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAWSRedshiftClusterDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
{
|
||||
Config: config,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSRedshiftClusterExists("aws_redshift_cluster.default", &v),
|
||||
|
@ -74,6 +75,33 @@ func TestAccAWSRedshiftCluster_basic(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestAccAWSRedshiftCluster_kmsKey(t *testing.T) {
|
||||
var v redshift.Cluster
|
||||
|
||||
ri := rand.New(rand.NewSource(time.Now().UnixNano())).Int()
|
||||
config := fmt.Sprintf(testAccAWSRedshiftClusterConfig_kmsKey, ri, ri)
|
||||
keyRegex := regexp.MustCompile("^arn:aws:([a-zA-Z0-9\\-])+:([a-z]{2}-[a-z]+-\\d{1})?:(\\d{12})?:(.*)$")
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAWSRedshiftClusterDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: config,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSRedshiftClusterExists("aws_redshift_cluster.default", &v),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_redshift_cluster.default", "cluster_type", "single-node"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_redshift_cluster.default", "publicly_accessible", "true"),
|
||||
resource.TestMatchResourceAttr("aws_redshift_cluster.default", "kms_key_id", keyRegex),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccAWSRedshiftCluster_enhancedVpcRoutingEnabled(t *testing.T) {
|
||||
var v redshift.Cluster
|
||||
|
||||
|
@ -86,7 +114,7 @@ func TestAccAWSRedshiftCluster_enhancedVpcRoutingEnabled(t *testing.T) {
|
|||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAWSRedshiftClusterDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
{
|
||||
Config: preConfig,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSRedshiftClusterExists("aws_redshift_cluster.default", &v),
|
||||
|
@ -94,7 +122,7 @@ func TestAccAWSRedshiftCluster_enhancedVpcRoutingEnabled(t *testing.T) {
|
|||
"aws_redshift_cluster.default", "enhanced_vpc_routing", "true"),
|
||||
),
|
||||
},
|
||||
resource.TestStep{
|
||||
{
|
||||
Config: postConfig,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSRedshiftClusterExists("aws_redshift_cluster.default", &v),
|
||||
|
@ -118,7 +146,7 @@ func TestAccAWSRedshiftCluster_loggingEnabled(t *testing.T) {
|
|||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAWSRedshiftClusterDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
{
|
||||
Config: preConfig,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSRedshiftClusterExists("aws_redshift_cluster.default", &v),
|
||||
|
@ -129,7 +157,7 @@ func TestAccAWSRedshiftCluster_loggingEnabled(t *testing.T) {
|
|||
),
|
||||
},
|
||||
|
||||
resource.TestStep{
|
||||
{
|
||||
Config: postConfig,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSRedshiftClusterExists("aws_redshift_cluster.default", &v),
|
||||
|
@ -153,7 +181,7 @@ func TestAccAWSRedshiftCluster_iamRoles(t *testing.T) {
|
|||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAWSRedshiftClusterDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
{
|
||||
Config: preConfig,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSRedshiftClusterExists("aws_redshift_cluster.default", &v),
|
||||
|
@ -162,7 +190,7 @@ func TestAccAWSRedshiftCluster_iamRoles(t *testing.T) {
|
|||
),
|
||||
},
|
||||
|
||||
resource.TestStep{
|
||||
{
|
||||
Config: postConfig,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSRedshiftClusterExists("aws_redshift_cluster.default", &v),
|
||||
|
@ -186,7 +214,7 @@ func TestAccAWSRedshiftCluster_publiclyAccessible(t *testing.T) {
|
|||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAWSRedshiftClusterDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
{
|
||||
Config: preConfig,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSRedshiftClusterExists("aws_redshift_cluster.default", &v),
|
||||
|
@ -195,7 +223,7 @@ func TestAccAWSRedshiftCluster_publiclyAccessible(t *testing.T) {
|
|||
),
|
||||
},
|
||||
|
||||
resource.TestStep{
|
||||
{
|
||||
Config: postConfig,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSRedshiftClusterExists("aws_redshift_cluster.default", &v),
|
||||
|
@ -219,7 +247,7 @@ func TestAccAWSRedshiftCluster_updateNodeCount(t *testing.T) {
|
|||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAWSRedshiftClusterDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
{
|
||||
Config: preConfig,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSRedshiftClusterExists("aws_redshift_cluster.default", &v),
|
||||
|
@ -228,7 +256,7 @@ func TestAccAWSRedshiftCluster_updateNodeCount(t *testing.T) {
|
|||
),
|
||||
},
|
||||
|
||||
resource.TestStep{
|
||||
{
|
||||
Config: postConfig,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSRedshiftClusterExists("aws_redshift_cluster.default", &v),
|
||||
|
@ -252,7 +280,7 @@ func TestAccAWSRedshiftCluster_tags(t *testing.T) {
|
|||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAWSRedshiftClusterDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
{
|
||||
Config: preConfig,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSRedshiftClusterExists("aws_redshift_cluster.default", &v),
|
||||
|
@ -262,7 +290,7 @@ func TestAccAWSRedshiftCluster_tags(t *testing.T) {
|
|||
),
|
||||
},
|
||||
|
||||
resource.TestStep{
|
||||
{
|
||||
Config: postConfig,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSRedshiftClusterExists("aws_redshift_cluster.default", &v),
|
||||
|
@ -502,6 +530,41 @@ resource "aws_redshift_cluster" "default" {
|
|||
allow_version_upgrade = false
|
||||
}`
|
||||
|
||||
var testAccAWSRedshiftClusterConfig_kmsKey = `
|
||||
resource "aws_kms_key" "foo" {
|
||||
description = "Terraform acc test %d"
|
||||
policy = <<POLICY
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Id": "kms-tf-1",
|
||||
"Statement": [
|
||||
{
|
||||
"Sid": "Enable IAM User Permissions",
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"AWS": "*"
|
||||
},
|
||||
"Action": "kms:*",
|
||||
"Resource": "*"
|
||||
}
|
||||
]
|
||||
}
|
||||
POLICY
|
||||
}
|
||||
|
||||
resource "aws_redshift_cluster" "default" {
|
||||
cluster_identifier = "tf-redshift-cluster-%d"
|
||||
availability_zone = "us-west-2a"
|
||||
database_name = "mydb"
|
||||
master_username = "foo_test"
|
||||
master_password = "Mustbe8characters"
|
||||
node_type = "dc1.large"
|
||||
automated_snapshot_retention_period = 0
|
||||
allow_version_upgrade = false
|
||||
kms_key_id = "${aws_kms_key.foo.arn}"
|
||||
encrypted = true
|
||||
}`
|
||||
|
||||
var testAccAWSRedshiftClusterConfig_enhancedVpcRoutingEnabled = `
|
||||
resource "aws_redshift_cluster" "default" {
|
||||
cluster_identifier = "tf-redshift-cluster-%d"
|
||||
|
|
|
@ -25,76 +25,77 @@ func resourceAwsS3BucketObject() *schema.Resource {
|
|||
Delete: resourceAwsS3BucketObjectDelete,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"bucket": &schema.Schema{
|
||||
"bucket": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"acl": &schema.Schema{
|
||||
"acl": {
|
||||
Type: schema.TypeString,
|
||||
Default: "private",
|
||||
Optional: true,
|
||||
ValidateFunc: validateS3BucketObjectAclType,
|
||||
},
|
||||
|
||||
"cache_control": &schema.Schema{
|
||||
"cache_control": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
|
||||
"content_disposition": &schema.Schema{
|
||||
"content_disposition": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
|
||||
"content_encoding": &schema.Schema{
|
||||
"content_encoding": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
|
||||
"content_language": &schema.Schema{
|
||||
"content_language": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
|
||||
"content_type": &schema.Schema{
|
||||
"content_type": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"key": &schema.Schema{
|
||||
"key": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"source": &schema.Schema{
|
||||
"source": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ConflictsWith: []string{"content"},
|
||||
},
|
||||
|
||||
"content": &schema.Schema{
|
||||
"content": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ConflictsWith: []string{"source"},
|
||||
},
|
||||
|
||||
"storage_class": &schema.Schema{
|
||||
"storage_class": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ValidateFunc: validateS3BucketObjectStorageClassType,
|
||||
},
|
||||
|
||||
"kms_key_id": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
"kms_key_id": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ValidateFunc: validateArn,
|
||||
},
|
||||
|
||||
"etag": &schema.Schema{
|
||||
"etag": {
|
||||
Type: schema.TypeString,
|
||||
// This will conflict with SSE-C and SSE-KMS encryption and multi-part upload
|
||||
// if/when it's actually implemented. The Etag then won't match raw-file MD5.
|
||||
|
@ -104,7 +105,7 @@ func resourceAwsS3BucketObject() *schema.Resource {
|
|||
ConflictsWith: []string{"kms_key_id"},
|
||||
},
|
||||
|
||||
"version_id": &schema.Schema{
|
||||
"version_id": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
|
|
@ -21,64 +21,64 @@ func resourceAwsSesReceiptRule() *schema.Resource {
|
|||
Delete: resourceAwsSesReceiptRuleDelete,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": &schema.Schema{
|
||||
"name": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"rule_set_name": &schema.Schema{
|
||||
"rule_set_name": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"after": &schema.Schema{
|
||||
"after": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
|
||||
"enabled": &schema.Schema{
|
||||
"enabled": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"recipients": &schema.Schema{
|
||||
"recipients": {
|
||||
Type: schema.TypeSet,
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
Optional: true,
|
||||
Set: schema.HashString,
|
||||
},
|
||||
|
||||
"scan_enabled": &schema.Schema{
|
||||
"scan_enabled": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"tls_policy": &schema.Schema{
|
||||
"tls_policy": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"add_header_action": &schema.Schema{
|
||||
"add_header_action": {
|
||||
Type: schema.TypeSet,
|
||||
Optional: true,
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"header_name": &schema.Schema{
|
||||
"header_name": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
|
||||
"header_value": &schema.Schema{
|
||||
"header_value": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
|
||||
"position": &schema.Schema{
|
||||
"position": {
|
||||
Type: schema.TypeInt,
|
||||
Required: true,
|
||||
},
|
||||
|
@ -95,37 +95,37 @@ func resourceAwsSesReceiptRule() *schema.Resource {
|
|||
},
|
||||
},
|
||||
|
||||
"bounce_action": &schema.Schema{
|
||||
"bounce_action": {
|
||||
Type: schema.TypeSet,
|
||||
Optional: true,
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"message": &schema.Schema{
|
||||
"message": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
|
||||
"sender": &schema.Schema{
|
||||
"sender": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
|
||||
"smtp_reply_code": &schema.Schema{
|
||||
"smtp_reply_code": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
|
||||
"status_code": &schema.Schema{
|
||||
"status_code": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
|
||||
"topic_arn": &schema.Schema{
|
||||
"topic_arn": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
|
||||
"position": &schema.Schema{
|
||||
"position": {
|
||||
Type: schema.TypeInt,
|
||||
Required: true,
|
||||
},
|
||||
|
@ -152,28 +152,28 @@ func resourceAwsSesReceiptRule() *schema.Resource {
|
|||
},
|
||||
},
|
||||
|
||||
"lambda_action": &schema.Schema{
|
||||
"lambda_action": {
|
||||
Type: schema.TypeSet,
|
||||
Optional: true,
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"function_arn": &schema.Schema{
|
||||
"function_arn": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
|
||||
"invocation_type": &schema.Schema{
|
||||
"invocation_type": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"topic_arn": &schema.Schema{
|
||||
"topic_arn": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
|
||||
"position": &schema.Schema{
|
||||
"position": {
|
||||
Type: schema.TypeInt,
|
||||
Required: true,
|
||||
},
|
||||
|
@ -198,32 +198,33 @@ func resourceAwsSesReceiptRule() *schema.Resource {
|
|||
},
|
||||
},
|
||||
|
||||
"s3_action": &schema.Schema{
|
||||
"s3_action": {
|
||||
Type: schema.TypeSet,
|
||||
Optional: true,
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"bucket_name": &schema.Schema{
|
||||
"bucket_name": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
|
||||
"kms_key_arn": &schema.Schema{
|
||||
"kms_key_arn": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ValidateFunc: validateArn,
|
||||
},
|
||||
|
||||
"object_key_prefix": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
|
||||
"object_key_prefix": &schema.Schema{
|
||||
"topic_arn": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
|
||||
"topic_arn": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
|
||||
"position": &schema.Schema{
|
||||
"position": {
|
||||
Type: schema.TypeInt,
|
||||
Required: true,
|
||||
},
|
||||
|
@ -252,17 +253,17 @@ func resourceAwsSesReceiptRule() *schema.Resource {
|
|||
},
|
||||
},
|
||||
|
||||
"sns_action": &schema.Schema{
|
||||
"sns_action": {
|
||||
Type: schema.TypeSet,
|
||||
Optional: true,
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"topic_arn": &schema.Schema{
|
||||
"topic_arn": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
|
||||
"position": &schema.Schema{
|
||||
"position": {
|
||||
Type: schema.TypeInt,
|
||||
Required: true,
|
||||
},
|
||||
|
@ -278,22 +279,22 @@ func resourceAwsSesReceiptRule() *schema.Resource {
|
|||
},
|
||||
},
|
||||
|
||||
"stop_action": &schema.Schema{
|
||||
"stop_action": {
|
||||
Type: schema.TypeSet,
|
||||
Optional: true,
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"scope": &schema.Schema{
|
||||
"scope": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
|
||||
"topic_arn": &schema.Schema{
|
||||
"topic_arn": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
|
||||
"position": &schema.Schema{
|
||||
"position": {
|
||||
Type: schema.TypeInt,
|
||||
Required: true,
|
||||
},
|
||||
|
@ -314,22 +315,22 @@ func resourceAwsSesReceiptRule() *schema.Resource {
|
|||
},
|
||||
},
|
||||
|
||||
"workmail_action": &schema.Schema{
|
||||
"workmail_action": {
|
||||
Type: schema.TypeSet,
|
||||
Optional: true,
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"organization_arn": &schema.Schema{
|
||||
"organization_arn": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
},
|
||||
|
||||
"topic_arn": &schema.Schema{
|
||||
"topic_arn": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
|
||||
"position": &schema.Schema{
|
||||
"position": {
|
||||
Type: schema.TypeInt,
|
||||
Required: true,
|
||||
},
|
||||
|
|
|
@ -55,8 +55,8 @@ The following arguments are supported:
|
|||
* `identifier` - (Optional) The name of the RDS instance, if omitted, Terraform will assign a random, unique name
|
||||
* `instance_class` - (Required) The instance type of the RDS instance.
|
||||
* `storage_type` - (Optional) One of "standard" (magnetic), "gp2" (general
|
||||
purpose SSD), or "io1" (provisioned IOPS SSD). The default is "io1" if
|
||||
`iops` is specified, "standard" if not.
|
||||
purpose SSD), or "io1" (provisioned IOPS SSD). The default is "io1" if
|
||||
`iops` is specified, "standard" if not.
|
||||
* `final_snapshot_identifier` - (Optional) The name of your final DB snapshot
|
||||
when this DB instance is deleted. If omitted, no final snapshot will be
|
||||
made.
|
||||
|
|
|
@ -34,7 +34,7 @@ The following arguments are supported:
|
|||
* `size` - (Optional) The size of the drive in GiBs.
|
||||
* `snapshot_id` (Optional) A snapshot to base the EBS volume off of.
|
||||
* `type` - (Optional) The type of EBS volume. Can be "standard", "gp2", "io1", or "st1" (Default: "standard").
|
||||
* `kms_key_id` - (Optional) The ARN for the KMS encryption key. When specifying `kms_key_id`, `encrypted` needs to be set to true
|
||||
* `kms_key_id` - (Optional) The ARN for the KMS encryption key. When specifying `kms_key_id`, `encrypted` needs to be set to true.
|
||||
* `tags` - (Optional) A mapping of tags to assign to the resource.
|
||||
|
||||
## Attributes Reference
|
||||
|
|
|
@ -135,7 +135,7 @@ The `s3_configuration` object supports the following:
|
|||
We recommend setting SizeInMBs to a value greater than the amount of data you typically ingest into the delivery stream in 10 seconds. For example, if you typically ingest data at 1 MB/sec set SizeInMBs to be 10 MB or higher.
|
||||
* `buffer_interval` - (Optional) Buffer incoming data for the specified period of time, in seconds, before delivering it to the destination. The default value is 300.
|
||||
* `compression_format` - (Optional) The compression format. If no value is specified, the default is UNCOMPRESSED. Other supported values are GZIP, ZIP & Snappy. If the destination is redshift you cannot use ZIP or Snappy.
|
||||
* `kms_key_arn` - (Optional) If set, the stream will encrypt data using the key in KMS, otherwise, no encryption will
|
||||
* `kms_key_arn` - (Optional) Specifies the KMS key ARN the stream will use to encrypt data. If not set, no encryption will
|
||||
be used.
|
||||
* `cloudwatch_logging_options` - (Optional) The CloudWatch Logging Options for the delivery stream. More details are given below
|
||||
|
||||
|
|
|
@ -79,7 +79,7 @@ Default: A 30-minute window selected at random from an 8-hour block of time per
|
|||
`false`. See [Amazon RDS Documentation for more information.](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Overview.DBInstance.Modifying.html)
|
||||
* `db_subnet_group_name` - (Optional) A DB subnet group to associate with this DB instance. **NOTE:** This must match the `db_subnet_group_name` specified on every [`aws_rds_cluster_instance`](/docs/providers/aws/r/rds_cluster_instance.html) in the cluster.
|
||||
* `db_cluster_parameter_group_name` - (Optional) A cluster parameter group to associate with the cluster.
|
||||
* `kms_key_id` - (Optional) The ARN for the KMS encryption key. When specifying `kms_key_id`, `storage_encrypted` needs to be set to true
|
||||
* `kms_key_id` - (Optional) The ARN for the KMS encryption key. When specifying `kms_key_id`, `storage_encrypted` needs to be set to true.
|
||||
|
||||
## Attributes Reference
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ string.
|
|||
* `publicly_accessible` - (Optional) If true, the cluster can be accessed from a public network. Default is `true`.
|
||||
* `encrypted` - (Optional) If true , the data in the cluster is encrypted at rest.
|
||||
* `enhanced_vpc_routing` - (Optional) If true , enhanced VPC routing is enabled.
|
||||
* `kms_key_id` - (Optional) The ARN for the KMS encryption key. When specifying `kms_key_id`, `encrypted` needs to be set to true
|
||||
* `kms_key_id` - (Optional) The ARN for the KMS encryption key. When specifying `kms_key_id`, `encrypted` needs to be set to true.
|
||||
* `elastic_ip` - (Optional) The Elastic IP (EIP) address for the cluster.
|
||||
* `skip_final_snapshot` - (Optional) Determines whether a final snapshot of the cluster is created before Amazon Redshift deletes the cluster. If true , a final cluster snapshot is not created. If false , a final cluster snapshot is created before the cluster is deleted. Default is true.
|
||||
* `final_snapshot_identifier` - (Optional) The identifier of the final snapshot that is to be created immediately before deleting the cluster. If this parameter is provided, `skip_final_snapshot` must be false.
|
||||
|
|
|
@ -61,8 +61,8 @@ The following arguments are supported:
|
|||
* `storage_class` - (Optional) Specifies the desired [Storage Class](http://docs.aws.amazon.com/AmazonS3/latest/dev/storage-class-intro.html)
|
||||
for the object. Can be either "`STANDARD`", "`REDUCED_REDUNDANCY`", or "`STANDARD_IA`". Defaults to "`STANDARD`".
|
||||
* `etag` - (Optional) Used to trigger updates. The only meaningful value is `${md5(file("path/to/file"))}`.
|
||||
This attribute is not compatible with `kms_key_id`
|
||||
* `kms_key_id` - (Optional) Specifies the AWS KMS Key ID to use for object encryption.
|
||||
This attribute is not compatible with `kms_key_id`.
|
||||
* `kms_key_id` - (Optional) Specifies the AWS KMS Key ARN to use for object encryption.
|
||||
This value is a fully qualified **ARN** of the KMS Key. If using `aws_kms_key`,
|
||||
use the exported `arn` attribute:
|
||||
`kms_key_id = "${aws_kms_key.foo.arn}"`
|
||||
|
|
Loading…
Reference in New Issue