From 955d3fe4f121fa8ec0e48d52bc2ec05994022265 Mon Sep 17 00:00:00 2001 From: kterada0509 Date: Mon, 13 May 2019 22:35:19 +0900 Subject: [PATCH 1/3] Add common tag resources method --- aws/tagsBeanstalk.go | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/aws/tagsBeanstalk.go b/aws/tagsBeanstalk.go index 57e26d3d967..6929103e8fb 100644 --- a/aws/tagsBeanstalk.go +++ b/aws/tagsBeanstalk.go @@ -6,8 +6,47 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/elasticbeanstalk" + "github.com/hashicorp/terraform/helper/schema" ) +// saveTagsBeanstalk is a helper to save the tags for a resource. It expects the +// tags field to be named "tags" +func saveTagsBeanstalk(conn *elasticbeanstalk.ElasticBeanstalk, d *schema.ResourceData, arn string) error { + resp, err := conn.ListTagsForResource(&elasticbeanstalk.ListTagsForResourceInput{ + ResourceArn: aws.String(arn), + }) + if err != nil { + return err + } + + if err := d.Set("tags", tagsToMapBeanstalk(resp.ResourceTags)); err != nil { + return err + } + + return nil +} + +// setTags is a helper to set the tags for a resource. It expects the +// tags field to be named "tags" +func setTagsBeanstalk(conn *elasticbeanstalk.ElasticBeanstalk, d *schema.ResourceData, arn string) error { + if d.HasChange("tags") { + oraw, nraw := d.GetChange("tags") + o := oraw.(map[string]interface{}) + n := nraw.(map[string]interface{}) + add, remove := diffTagsBeanstalk(tagsFromMapBeanstalk(o), tagsFromMapBeanstalk(n)) + + if _, err := conn.UpdateTagsForResource(&elasticbeanstalk.UpdateTagsForResourceInput{ + ResourceArn: aws.String(arn), + TagsToAdd: add, + TagsToRemove: remove, + }); err != nil { + return err + } + } + + return nil +} + // diffTags takes our tags locally and the ones remotely and returns // the set of tags that must be created, and the set of tags that must // be destroyed. From 6d337f5d7a3495ac11d54825e9ff7e0ed73188a7 Mon Sep 17 00:00:00 2001 From: kterada0509 Date: Mon, 13 May 2019 22:38:37 +0900 Subject: [PATCH 2/3] Add resource tag support for aws_beanstalk_application resource --- ...ource_aws_elastic_beanstalk_application.go | 15 ++++ ..._aws_elastic_beanstalk_application_test.go | 85 +++++++++++++++++++ ...lastic_beanstalk_application.html.markdown | 4 +- 3 files changed, 102 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_elastic_beanstalk_application.go b/aws/resource_aws_elastic_beanstalk_application.go index 2966c26e1dc..725343349c8 100644 --- a/aws/resource_aws_elastic_beanstalk_application.go +++ b/aws/resource_aws_elastic_beanstalk_application.go @@ -23,6 +23,10 @@ func resourceAwsElasticBeanstalkApplication() *schema.Resource { }, Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + }, "name": { Type: schema.TypeString, Required: true, @@ -58,6 +62,7 @@ func resourceAwsElasticBeanstalkApplication() *schema.Resource { }, }, }, + "tags": tagsSchema(), }, } } @@ -74,6 +79,7 @@ func resourceAwsElasticBeanstalkApplicationCreate(d *schema.ResourceData, meta i req := &elasticbeanstalk.CreateApplicationInput{ ApplicationName: aws.String(name), Description: aws.String(description), + Tags: tagsFromMapBeanstalk(d.Get("tags").(map[string]interface{})), } app, err := beanstalkConn.CreateApplication(req) @@ -105,6 +111,10 @@ func resourceAwsElasticBeanstalkApplicationUpdate(d *schema.ResourceData, meta i } } + if err := setTagsBeanstalk(beanstalkConn, d, d.Get("arn").(string)); err != nil { + return fmt.Errorf("error setting tags for %s: %s", d.Id(), err) + } + return resourceAwsElasticBeanstalkApplicationRead(d, meta) } @@ -223,6 +233,7 @@ func resourceAwsElasticBeanstalkApplicationRead(d *schema.ResourceData, meta int return err } + d.Set("arn", app.ApplicationArn) d.Set("name", app.ApplicationName) d.Set("description", app.Description) @@ -230,6 +241,10 @@ func resourceAwsElasticBeanstalkApplicationRead(d *schema.ResourceData, meta int d.Set("appversion_lifecycle", flattenResourceLifecycleConfig(app.ResourceLifecycleConfig)) } + if err := saveTagsBeanstalk(conn, d, aws.StringValue(app.ApplicationArn)); err != nil { + return fmt.Errorf("error saving tags for %s: %s", d.Id(), err) + } + return nil } diff --git a/aws/resource_aws_elastic_beanstalk_application_test.go b/aws/resource_aws_elastic_beanstalk_application_test.go index 560ac965675..0c9a8570fe0 100644 --- a/aws/resource_aws_elastic_beanstalk_application_test.go +++ b/aws/resource_aws_elastic_beanstalk_application_test.go @@ -169,6 +169,62 @@ func TestAccAWSBeanstalkApp_appversionlifecycle(t *testing.T) { }) } +func TestAccAWSBeanstalkApp_tags(t *testing.T) { + var app elasticbeanstalk.ApplicationDescription + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_elastic_beanstalk_application.tftest" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckBeanstalkAppDestroy, + Steps: []resource.TestStep{ + { + Config: testAccBeanstalkAppConfigWithTags(rName, "test1", "test2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckBeanstalkAppExists(resourceName, &app), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.firstTag", "test1"), + resource.TestCheckResourceAttr(resourceName, "tags.secondTag", "test2"), + ), + }, + { + Config: testAccBeanstalkAppConfigWithTags(rName, "updateTest1", "updateTest2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckBeanstalkAppExists(resourceName, &app), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.firstTag", "updateTest1"), + resource.TestCheckResourceAttr(resourceName, "tags.secondTag", "updateTest2"), + ), + }, + { + Config: testAccBeanstalkAppConfigWithAddTags(rName, "updateTest1", "updateTest2", "addTest3"), + Check: resource.ComposeTestCheckFunc( + testAccCheckBeanstalkAppExists(resourceName, &app), + resource.TestCheckResourceAttr(resourceName, "tags.%", "3"), + resource.TestCheckResourceAttr(resourceName, "tags.firstTag", "updateTest1"), + resource.TestCheckResourceAttr(resourceName, "tags.secondTag", "updateTest2"), + resource.TestCheckResourceAttr(resourceName, "tags.thirdTag", "addTest3"), + ), + }, + { + Config: testAccBeanstalkAppConfigWithTags(rName, "updateTest1", "updateTest2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckBeanstalkAppExists(resourceName, &app), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.firstTag", "updateTest1"), + resource.TestCheckResourceAttr(resourceName, "tags.secondTag", "updateTest2"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func testAccCheckBeanstalkAppDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).elasticbeanstalkconn @@ -320,3 +376,32 @@ resource "aws_elastic_beanstalk_application" "tftest" { } `, rName) } + +func testAccBeanstalkAppConfigWithTags(rName, tag1, tag2 string) string { + return fmt.Sprintf(` +resource "aws_elastic_beanstalk_application" "tftest" { + name = "%s" + description = "tf-test-desc" + + tags = { + firstTag = "%s" + secondTag = "%s" + } +} +`, rName, tag1, tag2) +} + +func testAccBeanstalkAppConfigWithAddTags(rName, tag1, tag2, tag3 string) string { + return fmt.Sprintf(` +resource "aws_elastic_beanstalk_application" "tftest" { + name = "%s" + description = "tf-test-desc" + + tags = { + firstTag = "%s" + secondTag = "%s" + thirdTag = "%s" + } +} +`, rName, tag1, tag2, tag3) +} diff --git a/website/docs/r/elastic_beanstalk_application.html.markdown b/website/docs/r/elastic_beanstalk_application.html.markdown index 46d0f09bd49..fa843994761 100644 --- a/website/docs/r/elastic_beanstalk_application.html.markdown +++ b/website/docs/r/elastic_beanstalk_application.html.markdown @@ -43,13 +43,13 @@ Application version lifecycle (`appversion_lifecycle`) supports the following se * `max_count` - (Optional) The maximum number of application versions to retain. * `max_age_in_days` - (Optional) The number of days to retain an application version. * `delete_source_from_s3` - (Optional) Set to `true` to delete a version's source bundle from S3 when the application version is deleted. +* `tags` - Key-value mapping of tags for the Elastic Beanstalk Application. ## Attributes Reference In addition to all arguments above, the following attributes are exported: -* `name` -* `description` +* `arn` - The ARN assigned by AWS for this Elastic Beanstalk Application. ## Import From ba7aff66bbfe86e5ae29e18b8d9fcbfebea902fc Mon Sep 17 00:00:00 2001 From: kterada0509 Date: Mon, 13 May 2019 22:57:26 +0900 Subject: [PATCH 3/3] Add resource tag support for aws_beanstalk_application_version resource --- ...s_elastic_beanstalk_application_version.go | 18 +++ ...stic_beanstalk_application_version_test.go | 113 ++++++++++++++++++ ...eanstalk_application_version.html.markdown | 3 +- 3 files changed, 133 insertions(+), 1 deletion(-) diff --git a/aws/resource_aws_elastic_beanstalk_application_version.go b/aws/resource_aws_elastic_beanstalk_application_version.go index ffe4c13a365..6fe0139846a 100644 --- a/aws/resource_aws_elastic_beanstalk_application_version.go +++ b/aws/resource_aws_elastic_beanstalk_application_version.go @@ -24,6 +24,10 @@ func resourceAwsElasticBeanstalkApplicationVersion() *schema.Resource { Required: true, ForceNew: true, }, + "arn": { + Type: schema.TypeString, + Computed: true, + }, "description": { Type: schema.TypeString, Optional: true, @@ -48,6 +52,7 @@ func resourceAwsElasticBeanstalkApplicationVersion() *schema.Resource { Optional: true, Default: false, }, + "tags": tagsSchema(), }, } } @@ -71,6 +76,7 @@ func resourceAwsElasticBeanstalkApplicationVersionCreate(d *schema.ResourceData, Description: aws.String(description), SourceBundle: &s3Location, VersionLabel: aws.String(name), + Tags: tagsFromMapBeanstalk(d.Get("tags").(map[string]interface{})), } log.Printf("[DEBUG] Elastic Beanstalk Application Version create opts: %s", createOpts) @@ -111,6 +117,14 @@ func resourceAwsElasticBeanstalkApplicationVersionRead(d *schema.ResourceData, m return err } + if err := d.Set("arn", resp.ApplicationVersions[0].ApplicationVersionArn); err != nil { + return err + } + + if err := saveTagsBeanstalk(conn, d, aws.StringValue(resp.ApplicationVersions[0].ApplicationVersionArn)); err != nil { + return fmt.Errorf("error saving tags for %s: %s", d.Id(), err) + } + return nil } @@ -123,6 +137,10 @@ func resourceAwsElasticBeanstalkApplicationVersionUpdate(d *schema.ResourceData, } } + if err := setTagsBeanstalk(conn, d, d.Get("arn").(string)); err != nil { + return fmt.Errorf("error setting tags for %s: %s", d.Id(), err) + } + return resourceAwsElasticBeanstalkApplicationVersionRead(d, meta) } diff --git a/aws/resource_aws_elastic_beanstalk_application_version_test.go b/aws/resource_aws_elastic_beanstalk_application_version_test.go index 81c5eeb6fcb..18630b348f0 100644 --- a/aws/resource_aws_elastic_beanstalk_application_version_test.go +++ b/aws/resource_aws_elastic_beanstalk_application_version_test.go @@ -51,6 +51,56 @@ func TestAccAWSBeanstalkAppVersion_duplicateLabels(t *testing.T) { }) } +func TestAccAWSBeanstalkAppVersion_tags(t *testing.T) { + var appVersion elasticbeanstalk.ApplicationVersionDescription + resourceName := "aws_elastic_beanstalk_application_version.default" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckApplicationVersionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccBeanstalkApplicationVersionConfigWithTags(acctest.RandInt(), "test1", "test2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckApplicationVersionExists(resourceName, &appVersion), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.firstTag", "test1"), + resource.TestCheckResourceAttr(resourceName, "tags.secondTag", "test2"), + ), + }, + { + Config: testAccBeanstalkApplicationVersionConfigWithTags(acctest.RandInt(), "updateTest1", "updateTest2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckApplicationVersionExists(resourceName, &appVersion), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.firstTag", "updateTest1"), + resource.TestCheckResourceAttr(resourceName, "tags.secondTag", "updateTest2"), + ), + }, + { + Config: testAccBeanstalkApplicationVersionConfigWithAddTags(acctest.RandInt(), "updateTest1", "updateTest2", "addTest3"), + Check: resource.ComposeTestCheckFunc( + testAccCheckApplicationVersionExists(resourceName, &appVersion), + resource.TestCheckResourceAttr(resourceName, "tags.%", "3"), + resource.TestCheckResourceAttr(resourceName, "tags.firstTag", "updateTest1"), + resource.TestCheckResourceAttr(resourceName, "tags.secondTag", "updateTest2"), + resource.TestCheckResourceAttr(resourceName, "tags.thirdTag", "addTest3"), + ), + }, + { + Config: testAccBeanstalkApplicationVersionConfigWithTags(acctest.RandInt(), "updateTest1", "updateTest2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckApplicationVersionExists(resourceName, &appVersion), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.firstTag", "updateTest1"), + resource.TestCheckResourceAttr(resourceName, "tags.secondTag", "updateTest2"), + ), + }, + }, + }) +} + func testAccCheckApplicationVersionDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).elasticbeanstalkconn @@ -179,3 +229,66 @@ resource "aws_elastic_beanstalk_application_version" "second" { } `, randInt, randInt, randInt, randInt, randInt) } + +func testAccBeanstalkApplicationVersionConfigWithTags(randInt int, tag1, tag2 string) string { + return fmt.Sprintf(` +resource "aws_s3_bucket" "default" { + bucket = "tftest.applicationversion.bucket-%[1]d" +} + +resource "aws_s3_bucket_object" "default" { + bucket = "${aws_s3_bucket.default.id}" + key = "beanstalk/python-v1.zip" + source = "test-fixtures/python-v1.zip" +} + +resource "aws_elastic_beanstalk_application" "default" { + name = "tf-test-name-%[1]d" + description = "tf-test-desc" +} + +resource "aws_elastic_beanstalk_application_version" "default" { + application = "${aws_elastic_beanstalk_application.default.name}" + name = "tf-test-version-label-%[1]d" + bucket = "${aws_s3_bucket.default.id}" + key = "${aws_s3_bucket_object.default.id}" + + tags = { + firstTag = "%[2]s" + secondTag = "%[3]s" + } +} + `, randInt, tag1, tag2) +} + +func testAccBeanstalkApplicationVersionConfigWithAddTags(randInt int, tag1, tag2, tag3 string) string { + return fmt.Sprintf(` +resource "aws_s3_bucket" "default" { + bucket = "tftest.applicationversion.bucket-%[1]d" +} + +resource "aws_s3_bucket_object" "default" { + bucket = "${aws_s3_bucket.default.id}" + key = "beanstalk/python-v1.zip" + source = "test-fixtures/python-v1.zip" +} + +resource "aws_elastic_beanstalk_application" "default" { + name = "tf-test-name-%[1]d" + description = "tf-test-desc" +} + +resource "aws_elastic_beanstalk_application_version" "default" { + application = "${aws_elastic_beanstalk_application.default.name}" + name = "tf-test-version-label-%[1]d" + bucket = "${aws_s3_bucket.default.id}" + key = "${aws_s3_bucket_object.default.id}" + + tags = { + firstTag = "%[2]s" + secondTag = "%[3]s" + thirdTag = "%[4]s" + } +} + `, randInt, tag1, tag2, tag3) +} diff --git a/website/docs/r/elastic_beanstalk_application_version.html.markdown b/website/docs/r/elastic_beanstalk_application_version.html.markdown index e67bd9a1592..4d77b7a9d01 100644 --- a/website/docs/r/elastic_beanstalk_application_version.html.markdown +++ b/website/docs/r/elastic_beanstalk_application_version.html.markdown @@ -63,9 +63,10 @@ The following arguments are supported: * `key` - (Required) S3 object that is the Application Version source bundle. * `force_delete` - (Optional) On delete, force an Application Version to be deleted when it may be in use by multiple Elastic Beanstalk Environments. +* `tags` - Key-value mapping of tags for the Elastic Beanstalk Application Version. ## Attributes Reference In addition to all arguments above, the following attributes are exported: -* `name` - The Application Version name. +* `arn` - The ARN assigned by AWS for this Elastic Beanstalk Application.