From e3912c2d534a4c9dc6b5831efc163dceb1b49857 Mon Sep 17 00:00:00 2001 From: Atsushi Ishibashi Date: Sun, 15 Oct 2017 05:00:41 +0900 Subject: [PATCH 1/6] CRD methods for ResourceDayaSync --- aws/provider.go | 1 + aws/resource_aws_ssm_resource_data_sync.go | 179 ++++++++++++++++++ ...esource_aws_ssm_resource_data_sync_test.go | 129 +++++++++++++ 3 files changed, 309 insertions(+) create mode 100644 aws/resource_aws_ssm_resource_data_sync.go create mode 100644 aws/resource_aws_ssm_resource_data_sync_test.go diff --git a/aws/provider.go b/aws/provider.go index fea7bceb456d..5f12797b0720 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -450,6 +450,7 @@ func Provider() terraform.ResourceProvider { "aws_ssm_patch_baseline": resourceAwsSsmPatchBaseline(), "aws_ssm_patch_group": resourceAwsSsmPatchGroup(), "aws_ssm_parameter": resourceAwsSsmParameter(), + "aws_ssm_resource_data_sync": resourceAwsSsmResourceDataSync(), "aws_spot_datafeed_subscription": resourceAwsSpotDataFeedSubscription(), "aws_spot_instance_request": resourceAwsSpotInstanceRequest(), "aws_spot_fleet_request": resourceAwsSpotFleetRequest(), diff --git a/aws/resource_aws_ssm_resource_data_sync.go b/aws/resource_aws_ssm_resource_data_sync.go new file mode 100644 index 000000000000..438130f8b439 --- /dev/null +++ b/aws/resource_aws_ssm_resource_data_sync.go @@ -0,0 +1,179 @@ +package aws + +import ( + "bytes" + "fmt" + "log" + "strings" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/service/ssm" + "github.com/hashicorp/terraform/helper/hashcode" + "github.com/hashicorp/terraform/helper/schema" +) + +func resourceAwsSsmResourceDataSync() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsSsmResourceDataSyncCreate, + Read: resourceAwsSsmResourceDataSyncRead, + Delete: resourceAwsSsmResourceDataSyncDelete, + + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "destination": { + Type: schema.TypeSet, + Required: true, + ForceNew: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "key": { + Type: schema.TypeString, + Optional: true, + }, + "bucket": { + Type: schema.TypeString, + Required: true, + }, + "prefix": { + Type: schema.TypeString, + Optional: true, + }, + "region": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + Set: func(v interface{}) int { + var buf bytes.Buffer + m := v.(map[string]interface{}) + buf.WriteString(fmt.Sprintf("%s-", strings.ToLower(m["bucket"].(string)))) + buf.WriteString(fmt.Sprintf("%s-", strings.ToLower(m["region"].(string)))) + if val, ok := m["key"]; ok { + buf.WriteString(fmt.Sprintf("%s-", strings.ToLower(val.(string)))) + } + if val, ok := m["prefix"]; ok { + buf.WriteString(fmt.Sprintf("%s-", strings.ToLower(val.(string)))) + } + return hashcode.String(buf.String()) + }, + }, + }, + } +} + +func resourceAwsSsmResourceDataSyncCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).ssmconn + + input := &ssm.CreateResourceDataSyncInput{ + S3Destination: &ssm.ResourceDataSyncS3Destination{ + SyncFormat: aws.String(ssm.ResourceDataSyncS3FormatJsonSerDe), + }, + SyncName: aws.String(d.Get("name").(string)), + } + destination := d.Get("destination").(*schema.Set).List() + for _, v := range destination { + dest := v.(map[string]interface{}) + input.S3Destination.SetBucketName(dest["bucket"].(string)) + input.S3Destination.SetRegion(dest["region"].(string)) + if val, ok := dest["key"].(string); ok && val != "" { + input.S3Destination.SetAWSKMSKeyARN(val) + } + if val, ok := dest["prefix"].(string); ok && val != "" { + input.S3Destination.SetPrefix(val) + } + } + + _, err := conn.CreateResourceDataSync(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + case ssm.ErrCodeResourceDataSyncAlreadyExistsException: + if err := resourceAwsSsmResourceDataSyncDeleteAndCreate(meta, input); err != nil { + return err + } + default: + return err + } + } else { + return err + } + } + return resourceAwsSsmResourceDataSyncRead(d, meta) +} + +func resourceAwsSsmResourceDataSyncRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).ssmconn + + nextToken := "" + found := false + for { + input := &ssm.ListResourceDataSyncInput{} + if nextToken != "" { + input.NextToken = aws.String(nextToken) + } + resp, err := conn.ListResourceDataSync(input) + if err != nil { + return err + } + for _, v := range resp.ResourceDataSyncItems { + if *v.SyncName == d.Get("name").(string) { + found = true + } + } + if found || *resp.NextToken == "" { + break + } + nextToken = *resp.NextToken + } + if !found { + log.Printf("[INFO] No Resource Data Sync found for SyncName: %s", d.Get("name").(string)) + } + return nil +} + +func resourceAwsSsmResourceDataSyncDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).ssmconn + + input := &ssm.DeleteResourceDataSyncInput{ + SyncName: aws.String(d.Get("name").(string)), + } + + _, err := conn.DeleteResourceDataSync(input) + if err != nil { + if aerr, ok := err.(awserr.Error); ok { + switch aerr.Code() { + case ssm.ErrCodeResourceDataSyncNotFoundException: + return nil + default: + return err + } + } + return err + } + return nil +} + +func resourceAwsSsmResourceDataSyncDeleteAndCreate(meta interface{}, input *ssm.CreateResourceDataSyncInput) error { + conn := meta.(*AWSClient).ssmconn + + delinput := &ssm.DeleteResourceDataSyncInput{ + SyncName: input.SyncName, + } + + _, err := conn.DeleteResourceDataSync(delinput) + if err != nil { + return err + } + _, err = conn.CreateResourceDataSync(input) + if err != nil { + return err + } + return nil +} diff --git a/aws/resource_aws_ssm_resource_data_sync_test.go b/aws/resource_aws_ssm_resource_data_sync_test.go new file mode 100644 index 000000000000..473acf7639a7 --- /dev/null +++ b/aws/resource_aws_ssm_resource_data_sync_test.go @@ -0,0 +1,129 @@ +package aws + +import ( + "fmt" + "log" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ssm" + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" +) + +func TestAccAWSSsmResourceDataSync(t *testing.T) { + rInt := acctest.RandInt() + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSSsmResourceDataSyncDestroy, + Steps: []resource.TestStep{ + { + Config: testAccSsmResourceDataSyncConfig(rInt), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSSsmResourceDataSyncExists("aws_ssm_resource_data_sync.foo"), + ), + }, + }, + }) +} + +func testAccCheckAWSSsmResourceDataSyncDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).ssmconn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_ssm_resource_data_sync" { + continue + } + nextToken := "" + found := false + for { + input := &ssm.ListResourceDataSyncInput{} + if nextToken != "" { + input.NextToken = aws.String(nextToken) + } + resp, err := conn.ListResourceDataSync(input) + if err != nil { + return err + } + for _, v := range resp.ResourceDataSyncItems { + if *v.SyncName == rs.Primary.Attributes["name"] { + found = true + } + } + if found || *resp.NextToken == "" { + break + } + nextToken = *resp.NextToken + } + if !found { + return fmt.Errorf("No Resource Data Sync found for SyncName: %s", rs.Primary.Attributes["name"]) + } + } + return nil +} + +func testAccCheckAWSSsmResourceDataSyncExists(name string) resource.TestCheckFunc { + return func(s *terraform.State) error { + log.Println(s.RootModule().Resources) + _, ok := s.RootModule().Resources[name] + if !ok { + return fmt.Errorf("Not found: %s", name) + } + + return nil + } +} + +func testAccSsmResourceDataSyncConfig(randInt int) string { + return fmt.Sprintf(` + resource "aws_s3_bucket" "hoge" { + bucket = "tf-test-bucket-%d" + region = "us-east-1" + force_destroy = true + } + + resource "aws_s3_bucket_policy" "hoge" { + bucket = "${aws_s3_bucket.hoge.bucket}" + policy = < Date: Mon, 23 Oct 2017 17:07:41 +0900 Subject: [PATCH 2/6] Modify checkDestroy, make docs --- aws/resource_aws_ssm_resource_data_sync.go | 1 + ...esource_aws_ssm_resource_data_sync_test.go | 11 +-- website/aws.erb | 4 + .../r/ssm_resource_data_sync.html.markdown | 78 +++++++++++++++++++ 4 files changed, 89 insertions(+), 5 deletions(-) create mode 100644 website/docs/r/ssm_resource_data_sync.html.markdown diff --git a/aws/resource_aws_ssm_resource_data_sync.go b/aws/resource_aws_ssm_resource_data_sync.go index 438130f8b439..d2b8c471eceb 100644 --- a/aws/resource_aws_ssm_resource_data_sync.go +++ b/aws/resource_aws_ssm_resource_data_sync.go @@ -105,6 +105,7 @@ func resourceAwsSsmResourceDataSyncCreate(d *schema.ResourceData, meta interface return err } } + d.SetId(d.Get("name").(string)) return resourceAwsSsmResourceDataSyncRead(d, meta) } diff --git a/aws/resource_aws_ssm_resource_data_sync_test.go b/aws/resource_aws_ssm_resource_data_sync_test.go index 473acf7639a7..9b44524a2466 100644 --- a/aws/resource_aws_ssm_resource_data_sync_test.go +++ b/aws/resource_aws_ssm_resource_data_sync_test.go @@ -52,13 +52,15 @@ func testAccCheckAWSSsmResourceDataSyncDestroy(s *terraform.State) error { found = true } } - if found || *resp.NextToken == "" { + if resp.NextToken != nil { + nextToken = *resp.NextToken + } + if found || nextToken == "" { break } - nextToken = *resp.NextToken } - if !found { - return fmt.Errorf("No Resource Data Sync found for SyncName: %s", rs.Primary.Attributes["name"]) + if found { + return fmt.Errorf("[DELETE ERROR] Resource Data Sync found for SyncName: %s", rs.Primary.Attributes["name"]) } } return nil @@ -71,7 +73,6 @@ func testAccCheckAWSSsmResourceDataSyncExists(name string) resource.TestCheckFun if !ok { return fmt.Errorf("Not found: %s", name) } - return nil } } diff --git a/website/aws.erb b/website/aws.erb index 7f18c1d57c84..81f917202bdb 100644 --- a/website/aws.erb +++ b/website/aws.erb @@ -1425,6 +1425,10 @@ aws_ssm_parameter + > + aws_ssm_resource_data_sync + + diff --git a/website/docs/r/ssm_resource_data_sync.html.markdown b/website/docs/r/ssm_resource_data_sync.html.markdown new file mode 100644 index 000000000000..63b8ad17da2b --- /dev/null +++ b/website/docs/r/ssm_resource_data_sync.html.markdown @@ -0,0 +1,78 @@ +--- +layout: "aws" +page_title: "AWS: aws_ssm_resource_data_sync" +sidebar_current: "docs-aws-resource-ssm-resource-data-sync" +description: |- + Provides a SSM resource data sync. +--- + +# aws_athena_database + +Provides a SSM resource data sync. + +## Example Usage + +```hcl +resource "aws_s3_bucket" "hoge" { + bucket = "tf-test-bucket-1234" + region = "us-east-1" +} + +resource "aws_s3_bucket_policy" "hoge" { + bucket = "${aws_s3_bucket.hoge.bucket}" + policy = < Date: Fri, 10 Nov 2017 11:18:06 +0900 Subject: [PATCH 3/6] Reflect 1st review --- aws/resource_aws_ssm_resource_data_sync.go | 156 ++++++++---------- ...esource_aws_ssm_resource_data_sync_test.go | 48 ++---- .../r/ssm_resource_data_sync.html.markdown | 15 +- 3 files changed, 91 insertions(+), 128 deletions(-) diff --git a/aws/resource_aws_ssm_resource_data_sync.go b/aws/resource_aws_ssm_resource_data_sync.go index d2b8c471eceb..4a27fc530076 100644 --- a/aws/resource_aws_ssm_resource_data_sync.go +++ b/aws/resource_aws_ssm_resource_data_sync.go @@ -1,15 +1,11 @@ package aws import ( - "bytes" "fmt" - "log" - "strings" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/ssm" - "github.com/hashicorp/terraform/helper/hashcode" "github.com/hashicorp/terraform/helper/schema" ) @@ -25,18 +21,18 @@ func resourceAwsSsmResourceDataSync() *schema.Resource { Required: true, ForceNew: true, }, - "destination": { - Type: schema.TypeSet, + "s3_destination": { + Type: schema.TypeList, Required: true, ForceNew: true, MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "key": { + "kms_key_arn": { Type: schema.TypeString, Optional: true, }, - "bucket": { + "bucket_name": { Type: schema.TypeString, Required: true, }, @@ -48,21 +44,13 @@ func resourceAwsSsmResourceDataSync() *schema.Resource { Type: schema.TypeString, Required: true, }, + "sync_format": { + Type: schema.TypeString, + Optional: true, + Default: ssm.ResourceDataSyncS3FormatJsonSerDe, + }, }, }, - Set: func(v interface{}) int { - var buf bytes.Buffer - m := v.(map[string]interface{}) - buf.WriteString(fmt.Sprintf("%s-", strings.ToLower(m["bucket"].(string)))) - buf.WriteString(fmt.Sprintf("%s-", strings.ToLower(m["region"].(string)))) - if val, ok := m["key"]; ok { - buf.WriteString(fmt.Sprintf("%s-", strings.ToLower(val.(string)))) - } - if val, ok := m["prefix"]; ok { - buf.WriteString(fmt.Sprintf("%s-", strings.ToLower(val.(string)))) - } - return hashcode.String(buf.String()) - }, }, }, } @@ -72,38 +60,13 @@ func resourceAwsSsmResourceDataSyncCreate(d *schema.ResourceData, meta interface conn := meta.(*AWSClient).ssmconn input := &ssm.CreateResourceDataSyncInput{ - S3Destination: &ssm.ResourceDataSyncS3Destination{ - SyncFormat: aws.String(ssm.ResourceDataSyncS3FormatJsonSerDe), - }, - SyncName: aws.String(d.Get("name").(string)), - } - destination := d.Get("destination").(*schema.Set).List() - for _, v := range destination { - dest := v.(map[string]interface{}) - input.S3Destination.SetBucketName(dest["bucket"].(string)) - input.S3Destination.SetRegion(dest["region"].(string)) - if val, ok := dest["key"].(string); ok && val != "" { - input.S3Destination.SetAWSKMSKeyARN(val) - } - if val, ok := dest["prefix"].(string); ok && val != "" { - input.S3Destination.SetPrefix(val) - } + S3Destination: expandSsmResourceDataSyncS3Destination(d), + SyncName: aws.String(d.Get("name").(string)), } _, err := conn.CreateResourceDataSync(input) if err != nil { - if aerr, ok := err.(awserr.Error); ok { - switch aerr.Code() { - case ssm.ErrCodeResourceDataSyncAlreadyExistsException: - if err := resourceAwsSsmResourceDataSyncDeleteAndCreate(meta, input); err != nil { - return err - } - default: - return err - } - } else { - return err - } + return err } d.SetId(d.Get("name").(string)) return resourceAwsSsmResourceDataSyncRead(d, meta) @@ -112,30 +75,16 @@ func resourceAwsSsmResourceDataSyncCreate(d *schema.ResourceData, meta interface func resourceAwsSsmResourceDataSyncRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).ssmconn - nextToken := "" - found := false - for { - input := &ssm.ListResourceDataSyncInput{} - if nextToken != "" { - input.NextToken = aws.String(nextToken) - } - resp, err := conn.ListResourceDataSync(input) - if err != nil { + syncItem, err := findResourceDataSyncItem(conn, d.Get("name").(string)) + if err != nil { + if _, ok := err.(awserr.Error); ok { return err + } else { + d.SetId("") + return nil } - for _, v := range resp.ResourceDataSyncItems { - if *v.SyncName == d.Get("name").(string) { - found = true - } - } - if found || *resp.NextToken == "" { - break - } - nextToken = *resp.NextToken - } - if !found { - log.Printf("[INFO] No Resource Data Sync found for SyncName: %s", d.Get("name").(string)) } + d.Set("s3_destination", flattenSsmResourceDataSyncS3Destination(syncItem.S3Destination)) return nil } @@ -148,33 +97,64 @@ func resourceAwsSsmResourceDataSyncDelete(d *schema.ResourceData, meta interface _, err := conn.DeleteResourceDataSync(input) if err != nil { - if aerr, ok := err.(awserr.Error); ok { - switch aerr.Code() { - case ssm.ErrCodeResourceDataSyncNotFoundException: - return nil - default: - return err - } + if isAWSErr(err, ssm.ErrCodeResourceDataSyncNotFoundException, "") { + return nil } return err } return nil } -func resourceAwsSsmResourceDataSyncDeleteAndCreate(meta interface{}, input *ssm.CreateResourceDataSyncInput) error { - conn := meta.(*AWSClient).ssmconn +func findResourceDataSyncItem(conn *ssm.SSM, name string) (*ssm.ResourceDataSyncItem, error) { + nextToken := "" + for { + input := &ssm.ListResourceDataSyncInput{} + if nextToken != "" { + input.NextToken = aws.String(nextToken) + } + resp, err := conn.ListResourceDataSync(input) + if err != nil { + return nil, err + } + for _, v := range resp.ResourceDataSyncItems { + if *v.SyncName == name { + return v, nil + } + } + if resp.NextToken == nil { + break + } + nextToken = *resp.NextToken + } + return nil, fmt.Errorf("Resource Data Sync (%s) not found", name) +} - delinput := &ssm.DeleteResourceDataSyncInput{ - SyncName: input.SyncName, +func flattenSsmResourceDataSyncS3Destination(dest *ssm.ResourceDataSyncS3Destination) []interface{} { + result := make(map[string]interface{}) + result["bucket_name"] = *dest.BucketName + result["region"] = *dest.Region + result["sync_format"] = *dest.SyncFormat + if dest.AWSKMSKeyARN != nil { + result["kms_key_arn"] = *dest.AWSKMSKeyARN + } + if dest.Prefix != nil { + result["prefix"] = *dest.Prefix } + return []interface{}{result} +} - _, err := conn.DeleteResourceDataSync(delinput) - if err != nil { - return err +func expandSsmResourceDataSyncS3Destination(d *schema.ResourceData) *ssm.ResourceDataSyncS3Destination { + raw := d.Get("s3_destination").([]interface{})[0].(map[string]interface{}) + s3dest := &ssm.ResourceDataSyncS3Destination{ + BucketName: aws.String(raw["bucket_name"].(string)), + Region: aws.String(raw["region"].(string)), + SyncFormat: aws.String(raw["sync_format"].(string)), } - _, err = conn.CreateResourceDataSync(input) - if err != nil { - return err + if v, ok := raw["kms_key_arn"].(string); ok && v != "" { + s3dest.AWSKMSKeyARN = aws.String(v) } - return nil + if v, ok := raw["prefix"].(string); ok && v != "" { + s3dest.Prefix = aws.String(v) + } + return s3dest } diff --git a/aws/resource_aws_ssm_resource_data_sync_test.go b/aws/resource_aws_ssm_resource_data_sync_test.go index 9b44524a2466..200632abb7a7 100644 --- a/aws/resource_aws_ssm_resource_data_sync_test.go +++ b/aws/resource_aws_ssm_resource_data_sync_test.go @@ -5,22 +5,20 @@ import ( "log" "testing" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ssm" + "github.com/aws/aws-sdk-go/aws/awserr" "github.com/hashicorp/terraform/helper/acctest" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/terraform" ) -func TestAccAWSSsmResourceDataSync(t *testing.T) { - rInt := acctest.RandInt() +func TestAccAWSSsmResourceDataSync_basic(t *testing.T) { resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, CheckDestroy: testAccCheckAWSSsmResourceDataSyncDestroy, Steps: []resource.TestStep{ { - Config: testAccSsmResourceDataSyncConfig(rInt), + Config: testAccSsmResourceDataSyncConfig(acctest.RandInt(), acctest.RandString(5)), Check: resource.ComposeTestCheckFunc( testAccCheckAWSSsmResourceDataSyncExists("aws_ssm_resource_data_sync.foo"), ), @@ -36,31 +34,15 @@ func testAccCheckAWSSsmResourceDataSyncDestroy(s *terraform.State) error { if rs.Type != "aws_ssm_resource_data_sync" { continue } - nextToken := "" - found := false - for { - input := &ssm.ListResourceDataSyncInput{} - if nextToken != "" { - input.NextToken = aws.String(nextToken) - } - resp, err := conn.ListResourceDataSync(input) - if err != nil { + _, err := findResourceDataSyncItem(conn, rs.Primary.Attributes["name"]) + if err != nil { + if _, ok := err.(awserr.Error); ok { return err + } else { + return nil } - for _, v := range resp.ResourceDataSyncItems { - if *v.SyncName == rs.Primary.Attributes["name"] { - found = true - } - } - if resp.NextToken != nil { - nextToken = *resp.NextToken - } - if found || nextToken == "" { - break - } - } - if found { - return fmt.Errorf("[DELETE ERROR] Resource Data Sync found for SyncName: %s", rs.Primary.Attributes["name"]) + } else { + return fmt.Errorf("Resource Data Sync (%s) found", rs.Primary.Attributes["name"]) } } return nil @@ -77,7 +59,7 @@ func testAccCheckAWSSsmResourceDataSyncExists(name string) resource.TestCheckFun } } -func testAccSsmResourceDataSyncConfig(randInt int) string { +func testAccSsmResourceDataSyncConfig(rInt int, rName string) string { return fmt.Sprintf(` resource "aws_s3_bucket" "hoge" { bucket = "tf-test-bucket-%d" @@ -120,11 +102,11 @@ func testAccSsmResourceDataSyncConfig(randInt int) string { } resource "aws_ssm_resource_data_sync" "foo" { - name = "foo" - destination = { - bucket = "${aws_s3_bucket.hoge.bucket}" + name = "tf-test-ssm-%s" + s3_destination = { + bucket_name = "${aws_s3_bucket.hoge.bucket}" region = "${aws_s3_bucket.hoge.region}" } } - `, randInt, randInt, randInt) + `, rInt, rInt, rInt, rName) } diff --git a/website/docs/r/ssm_resource_data_sync.html.markdown b/website/docs/r/ssm_resource_data_sync.html.markdown index 63b8ad17da2b..06abae2fd037 100644 --- a/website/docs/r/ssm_resource_data_sync.html.markdown +++ b/website/docs/r/ssm_resource_data_sync.html.markdown @@ -54,8 +54,8 @@ resource "aws_s3_bucket_policy" "hoge" { resource "aws_ssm_resource_data_sync" "foo" { name = "foo" - destination = { - bucket = "${aws_s3_bucket.hoge.bucket}" + s3_destination = { + bucket_name = "${aws_s3_bucket.hoge.bucket}" region = "${aws_s3_bucket.hoge.region}" } } @@ -66,13 +66,14 @@ resource "aws_ssm_resource_data_sync" "foo" { The following arguments are supported: * `name` - (Required) Name for the configuration. -* `destination` - (Required) Amazon S3 configuration details for the sync. +* `s3_destination` - (Required) Amazon S3 configuration details for the sync. -## destination +## s3_destination -`destination` supports the following: +`s3_destination` supports the following: -* `bucket` - (Required) Name of S3 bucket where the aggregated data is stored. +* `bucket_name` - (Required) Name of S3 bucket where the aggregated data is stored. * `region` - (Required) Region with the bucket targeted by the Resource Data Sync. -* `key` - (Optional) ARN of an encryption key for a destination in Amazon S3. +* `kms_key_arn` - (Optional) ARN of an encryption key for a destination in Amazon S3. * `prefix` - (Optional) Prefix for the bucket. +* `sync_format` - (Optional) A supported sync format. Only JsonSerDe is currently supported. Defaults to JsonSerDe. From 926668e03d117b00864152e17a4d16670bfcf1b1 Mon Sep 17 00:00:00 2001 From: Atsushi Ishibashi Date: Fri, 10 Nov 2017 15:53:49 +0900 Subject: [PATCH 4/6] Reflect 2nd review --- aws/resource_aws_ssm_resource_data_sync.go | 13 ++++++------- aws/resource_aws_ssm_resource_data_sync_test.go | 13 +++++-------- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/aws/resource_aws_ssm_resource_data_sync.go b/aws/resource_aws_ssm_resource_data_sync.go index 4a27fc530076..7c4a9ab1695f 100644 --- a/aws/resource_aws_ssm_resource_data_sync.go +++ b/aws/resource_aws_ssm_resource_data_sync.go @@ -77,12 +77,11 @@ func resourceAwsSsmResourceDataSyncRead(d *schema.ResourceData, meta interface{} syncItem, err := findResourceDataSyncItem(conn, d.Get("name").(string)) if err != nil { - if _, ok := err.(awserr.Error); ok { - return err - } else { - d.SetId("") - return nil - } + return err + } + if syncItem == nil { + d.SetId("") + return nil } d.Set("s3_destination", flattenSsmResourceDataSyncS3Destination(syncItem.S3Destination)) return nil @@ -126,7 +125,7 @@ func findResourceDataSyncItem(conn *ssm.SSM, name string) (*ssm.ResourceDataSync } nextToken = *resp.NextToken } - return nil, fmt.Errorf("Resource Data Sync (%s) not found", name) + return nil, nil } func flattenSsmResourceDataSyncS3Destination(dest *ssm.ResourceDataSyncS3Destination) []interface{} { diff --git a/aws/resource_aws_ssm_resource_data_sync_test.go b/aws/resource_aws_ssm_resource_data_sync_test.go index 200632abb7a7..d6e061555b62 100644 --- a/aws/resource_aws_ssm_resource_data_sync_test.go +++ b/aws/resource_aws_ssm_resource_data_sync_test.go @@ -34,14 +34,11 @@ func testAccCheckAWSSsmResourceDataSyncDestroy(s *terraform.State) error { if rs.Type != "aws_ssm_resource_data_sync" { continue } - _, err := findResourceDataSyncItem(conn, rs.Primary.Attributes["name"]) + syncItem, err := findResourceDataSyncItem(conn, rs.Primary.Attributes["name"]) if err != nil { - if _, ok := err.(awserr.Error); ok { - return err - } else { - return nil - } - } else { + return err + } + if syncItem != nil { return fmt.Errorf("Resource Data Sync (%s) found", rs.Primary.Attributes["name"]) } } @@ -63,7 +60,7 @@ func testAccSsmResourceDataSyncConfig(rInt int, rName string) string { return fmt.Sprintf(` resource "aws_s3_bucket" "hoge" { bucket = "tf-test-bucket-%d" - region = "us-east-1" + region = "us-west-2" force_destroy = true } From 879b0f85f82edc6c5a36180dc0cb5544c51466d9 Mon Sep 17 00:00:00 2001 From: Atsushi Ishibashi Date: Fri, 10 Nov 2017 17:46:38 +0900 Subject: [PATCH 5/6] goimports --- aws/resource_aws_ssm_resource_data_sync.go | 3 --- aws/resource_aws_ssm_resource_data_sync_test.go | 1 - 2 files changed, 4 deletions(-) diff --git a/aws/resource_aws_ssm_resource_data_sync.go b/aws/resource_aws_ssm_resource_data_sync.go index 7c4a9ab1695f..a47b1b85fd39 100644 --- a/aws/resource_aws_ssm_resource_data_sync.go +++ b/aws/resource_aws_ssm_resource_data_sync.go @@ -1,10 +1,7 @@ package aws import ( - "fmt" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/ssm" "github.com/hashicorp/terraform/helper/schema" ) diff --git a/aws/resource_aws_ssm_resource_data_sync_test.go b/aws/resource_aws_ssm_resource_data_sync_test.go index d6e061555b62..861c76d43086 100644 --- a/aws/resource_aws_ssm_resource_data_sync_test.go +++ b/aws/resource_aws_ssm_resource_data_sync_test.go @@ -5,7 +5,6 @@ import ( "log" "testing" - "github.com/aws/aws-sdk-go/aws/awserr" "github.com/hashicorp/terraform/helper/acctest" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/terraform" From 2e1236e3612b4c1dadf0d3d478b38bb2f51bb2e2 Mon Sep 17 00:00:00 2001 From: Radek Simko Date: Fri, 10 Nov 2017 09:47:17 +0000 Subject: [PATCH 6/6] Retry creation due S3 eventual consistency --- aws/resource_aws_ssm_resource_data_sync.go | 23 +++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/aws/resource_aws_ssm_resource_data_sync.go b/aws/resource_aws_ssm_resource_data_sync.go index a47b1b85fd39..7426e1e22307 100644 --- a/aws/resource_aws_ssm_resource_data_sync.go +++ b/aws/resource_aws_ssm_resource_data_sync.go @@ -1,8 +1,11 @@ package aws import ( + "time" + "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ssm" + "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" ) @@ -56,15 +59,25 @@ func resourceAwsSsmResourceDataSync() *schema.Resource { func resourceAwsSsmResourceDataSyncCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).ssmconn - input := &ssm.CreateResourceDataSyncInput{ - S3Destination: expandSsmResourceDataSyncS3Destination(d), - SyncName: aws.String(d.Get("name").(string)), - } + err := resource.Retry(1*time.Minute, func() *resource.RetryError { + input := &ssm.CreateResourceDataSyncInput{ + S3Destination: expandSsmResourceDataSyncS3Destination(d), + SyncName: aws.String(d.Get("name").(string)), + } + _, err := conn.CreateResourceDataSync(input) + if err != nil { + if isAWSErr(err, ssm.ErrCodeResourceDataSyncInvalidConfigurationException, "S3 write failed for bucket") { + return resource.RetryableError(err) + } + return resource.NonRetryableError(err) + } + return nil + }) - _, err := conn.CreateResourceDataSync(input) if err != nil { return err } + d.SetId(d.Get("name").(string)) return resourceAwsSsmResourceDataSyncRead(d, meta) }