From 0f5b874656802a53684ed2fcf3f450e54c856b16 Mon Sep 17 00:00:00 2001 From: DrFaust92 Date: Sat, 29 Aug 2020 22:11:47 +0300 Subject: [PATCH 1/5] add support for glue workflow tags and arn --- aws/resource_aws_glue_workflow.go | 94 +++++++++++++------ aws/resource_aws_glue_workflow_test.go | 100 ++++++++++++++++++++- website/docs/r/glue_workflow.html.markdown | 4 +- 3 files changed, 168 insertions(+), 30 deletions(-) diff --git a/aws/resource_aws_glue_workflow.go b/aws/resource_aws_glue_workflow.go index 2f9caa78bc5..f5ccfca6e43 100644 --- a/aws/resource_aws_glue_workflow.go +++ b/aws/resource_aws_glue_workflow.go @@ -2,11 +2,14 @@ package aws import ( "fmt" + "log" + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/arn" "github.com/aws/aws-sdk-go/service/glue" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - "log" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" ) func resourceAwsGlueWorkflow() *schema.Resource { @@ -20,6 +23,10 @@ func resourceAwsGlueWorkflow() *schema.Resource { }, Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + }, "default_run_properties": { Type: schema.TypeMap, Optional: true, @@ -29,12 +36,17 @@ func resourceAwsGlueWorkflow() *schema.Resource { Type: schema.TypeString, Optional: true, }, + "max_concurrent_runs": { + Type: schema.TypeInt, + Optional: true, + }, "name": { Type: schema.TypeString, Optional: true, ForceNew: true, ValidateFunc: validation.NoZeroValues, }, + "tags": tagsSchema(), }, } } @@ -45,24 +57,25 @@ func resourceAwsGlueWorkflowCreate(d *schema.ResourceData, meta interface{}) err input := &glue.CreateWorkflowInput{ Name: aws.String(name), + Tags: keyvaluetags.New(d.Get("tags").(map[string]interface{})).IgnoreAws().GlueTags(), } if kv, ok := d.GetOk("default_run_properties"); ok { - defaultRunPropertiesMap := make(map[string]string) - for k, v := range kv.(map[string]interface{}) { - defaultRunPropertiesMap[k] = v.(string) - } - input.DefaultRunProperties = aws.StringMap(defaultRunPropertiesMap) + input.DefaultRunProperties = stringMapToPointers(kv.(map[string]interface{})) } if v, ok := d.GetOk("description"); ok { input.Description = aws.String(v.(string)) } + if v, ok := d.GetOk("max_concurrent_runs"); ok { + input.MaxConcurrentRuns = aws.Int64(int64(v.(int))) + } + log.Printf("[DEBUG] Creating Glue Workflow: %s", input) _, err := conn.CreateWorkflow(input) if err != nil { - return fmt.Errorf("error creating Glue Trigger (%s): %s", name, err) + return fmt.Errorf("error creating Glue Trigger (%s): %w", name, err) } d.SetId(name) @@ -71,12 +84,13 @@ func resourceAwsGlueWorkflowCreate(d *schema.ResourceData, meta interface{}) err func resourceAwsGlueWorkflowRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).glueconn + ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig input := &glue.GetWorkflowInput{ Name: aws.String(d.Id()), } - log.Printf("[DEBUG] Reading Glue Workflow: %s", input) + log.Printf("[DEBUG] Reading Glue Workflow: %#v", input) output, err := conn.GetWorkflow(input) if err != nil { if isAWSErr(err, glue.ErrCodeEntityNotFoundException, "") { @@ -84,7 +98,7 @@ func resourceAwsGlueWorkflowRead(d *schema.ResourceData, meta interface{}) error d.SetId("") return nil } - return fmt.Errorf("error reading Glue Workflow (%s): %s", d.Id(), err) + return fmt.Errorf("error reading Glue Workflow (%s): %w", d.Id(), err) } workflow := output.Workflow @@ -94,38 +108,66 @@ func resourceAwsGlueWorkflowRead(d *schema.ResourceData, meta interface{}) error return nil } + workFlowArn := arn.ARN{ + Partition: meta.(*AWSClient).partition, + Service: "glue", + Region: meta.(*AWSClient).region, + AccountID: meta.(*AWSClient).accountid, + Resource: fmt.Sprintf("workflow/%s", d.Id()), + }.String() + d.Set("arn", workFlowArn) + if err := d.Set("default_run_properties", aws.StringValueMap(workflow.DefaultRunProperties)); err != nil { - return fmt.Errorf("error setting default_run_properties: %s", err) + return fmt.Errorf("error setting default_run_properties: %w", err) } d.Set("description", workflow.Description) d.Set("name", workflow.Name) + tags, err := keyvaluetags.GlueListTags(conn, workFlowArn) + + if err != nil { + return fmt.Errorf("error listing tags for Glue Workflow (%s): %w", workFlowArn, err) + } + + if err := d.Set("tags", tags.IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { + return fmt.Errorf("error setting tags: %w", err) + } + return nil } func resourceAwsGlueWorkflowUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).glueconn - input := &glue.UpdateWorkflowInput{ - Name: aws.String(d.Get("name").(string)), - } + if d.HasChanges("default_run_properties", "description", "max_concurrent_runs") { + input := &glue.UpdateWorkflowInput{ + Name: aws.String(d.Get("name").(string)), + } - if kv, ok := d.GetOk("default_run_properties"); ok { - defaultRunPropertiesMap := make(map[string]string) - for k, v := range kv.(map[string]interface{}) { - defaultRunPropertiesMap[k] = v.(string) + if kv, ok := d.GetOk("default_run_properties"); ok { + input.DefaultRunProperties = stringMapToPointers(kv.(map[string]interface{})) } - input.DefaultRunProperties = aws.StringMap(defaultRunPropertiesMap) - } - if v, ok := d.GetOk("description"); ok { - input.Description = aws.String(v.(string)) + if v, ok := d.GetOk("description"); ok { + input.Description = aws.String(v.(string)) + } + + if v, ok := d.GetOk("max_concurrent_runs"); ok { + input.MaxConcurrentRuns = aws.Int64(int64(v.(int))) + } + + log.Printf("[DEBUG] Updating Glue Workflow: %#v", input) + _, err := conn.UpdateWorkflow(input) + if err != nil { + return fmt.Errorf("error updating Glue Workflow (%s): %w", d.Id(), err) + } } - log.Printf("[DEBUG] Updating Glue Workflow: %s", input) - _, err := conn.UpdateWorkflow(input) - if err != nil { - return fmt.Errorf("error updating Glue Workflow (%s): %s", d.Id(), err) + if d.HasChange("tags") { + o, n := d.GetChange("tags") + if err := keyvaluetags.GlueUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { + return fmt.Errorf("error updating tags: %s", err) + } } return resourceAwsGlueWorkflowRead(d, meta) @@ -137,7 +179,7 @@ func resourceAwsGlueWorkflowDelete(d *schema.ResourceData, meta interface{}) err log.Printf("[DEBUG] Deleting Glue Workflow: %s", d.Id()) err := deleteWorkflow(conn, d.Id()) if err != nil { - return fmt.Errorf("error deleting Glue Workflow (%s): %s", d.Id(), err) + return fmt.Errorf("error deleting Glue Workflow (%s): %w", d.Id(), err) } return nil diff --git a/aws/resource_aws_glue_workflow_test.go b/aws/resource_aws_glue_workflow_test.go index 49d784e219e..198f387138a 100644 --- a/aws/resource_aws_glue_workflow_test.go +++ b/aws/resource_aws_glue_workflow_test.go @@ -47,7 +47,7 @@ func testSweepGlueWorkflow(region string) error { func TestAccAWSGlueWorkflow_basic(t *testing.T) { var workflow glue.Workflow - rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(5)) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_glue_workflow.test" resource.ParallelTest(t, resource.TestCase{ @@ -59,7 +59,9 @@ func TestAccAWSGlueWorkflow_basic(t *testing.T) { Config: testAccAWSGlueWorkflowConfig_Required(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSGlueWorkflowExists(resourceName, &workflow), + testAccCheckResourceAttrRegionalARN(resourceName, "arn", "glue", fmt.Sprintf("workflow/%s", rName)), resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, { @@ -74,7 +76,7 @@ func TestAccAWSGlueWorkflow_basic(t *testing.T) { func TestAccAWSGlueWorkflow_DefaultRunProperties(t *testing.T) { var workflow glue.Workflow - rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(5)) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_glue_workflow.test" resource.ParallelTest(t, resource.TestCase{ @@ -103,7 +105,7 @@ func TestAccAWSGlueWorkflow_DefaultRunProperties(t *testing.T) { func TestAccAWSGlueWorkflow_Description(t *testing.T) { var workflow glue.Workflow - rName := fmt.Sprintf("tf-acc-test-%s", acctest.RandString(5)) + rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_glue_workflow.test" resource.ParallelTest(t, resource.TestCase{ @@ -134,6 +136,73 @@ func TestAccAWSGlueWorkflow_Description(t *testing.T) { }) } +func TestAccAWSGlueWorkflow_Tags(t *testing.T) { + var workflow glue.Workflow + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_glue_workflow.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSGlueWorkflow(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSGlueWorkflowDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSGlueWorkflowConfigTags1(rName, "key1", "value1"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSGlueWorkflowExists(resourceName, &workflow), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSGlueWorkflowConfigTags2(rName, "key1", "value1updated", "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSGlueWorkflowExists(resourceName, &workflow), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + { + Config: testAccAWSGlueWorkflowConfigTags1(rName, "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSGlueWorkflowExists(resourceName, &workflow), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + }, + }) +} + +func TestAccAWSGlueWorkflow_disappears(t *testing.T) { + var workflow glue.Workflow + + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_glue_workflow.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSGlueWorkflow(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSGlueWorkflowDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSGlueWorkflowConfig_Required(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSGlueWorkflowExists(resourceName, &workflow), + testAccCheckResourceDisappears(testAccProvider, resourceAwsGlueWorkflow(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + func testAccPreCheckAWSGlueWorkflow(t *testing.T) { conn := testAccProvider.Meta().(*AWSClient).glueconn @@ -241,3 +310,28 @@ resource "aws_glue_workflow" "test" { } `, rName) } + +func testAccAWSGlueWorkflowConfigTags1(rName, tagKey1, tagValue1 string) string { + return fmt.Sprintf(` +resource "aws_glue_workflow" "test" { + name = %[1]q + + tags = { + %[2]q = %[3]q + } +} +`, rName, tagKey1, tagValue1) +} + +func testAccAWSGlueWorkflowConfigTags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { + return fmt.Sprintf(` +resource "aws_glue_workflow" "test" { + name = %[1]q + + tags = { + %[2]q = %[3]q + %[4]q = %[5]q + } +} +`, rName, tagKey1, tagValue1, tagKey2, tagValue2) +} diff --git a/website/docs/r/glue_workflow.html.markdown b/website/docs/r/glue_workflow.html.markdown index 30a139e5f9a..4fba84dc348 100644 --- a/website/docs/r/glue_workflow.html.markdown +++ b/website/docs/r/glue_workflow.html.markdown @@ -3,7 +3,7 @@ subcategory: "Glue" layout: "aws" page_title: "AWS: aws_glue_workflow" description: |- - Provides an Glue Workflow resource. + Provides a Glue Workflow resource. --- # Resource: aws_glue_workflow @@ -54,11 +54,13 @@ The following arguments are supported: * `default_run_properties` – (Optional) A map of default run properties for this workflow. These properties are passed to all jobs associated to the workflow. * `description` – (Optional) Description of the workflow. * `name` – (Required) The name you assign to this workflow. +* `tags` - (Optional) Key-value map of resource tags ## Attributes Reference In addition to all arguments above, the following attributes are exported: +* `arn` - Amazon Resource Name (ARN) of Glue Workflow * `id` - Workflow name ## Import From b98aa639c6c293d786a50b9dfb6fa6790c91a66f Mon Sep 17 00:00:00 2001 From: DrFaust92 Date: Sat, 29 Aug 2020 22:18:15 +0300 Subject: [PATCH 2/5] add support for max concurrent runs --- aws/resource_aws_glue_workflow_test.go | 50 ++++++++++++++++++++++ website/docs/r/glue_workflow.html.markdown | 3 +- 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/aws/resource_aws_glue_workflow_test.go b/aws/resource_aws_glue_workflow_test.go index 198f387138a..12bdd1fcfd6 100644 --- a/aws/resource_aws_glue_workflow_test.go +++ b/aws/resource_aws_glue_workflow_test.go @@ -73,6 +73,47 @@ func TestAccAWSGlueWorkflow_basic(t *testing.T) { }) } +func TestAccAWSGlueWorkflow_maxConcurrentRuns(t *testing.T) { + var workflow glue.Workflow + + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_glue_workflow.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSGlueWorkflow(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSGlueWorkflowDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSGlueWorkflowConfigMaxConcurrentRuns(rName, 1), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSGlueWorkflowExists(resourceName, &workflow), + resource.TestCheckResourceAttr(resourceName, "max_concurrent_runs", "1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSGlueWorkflowConfigMaxConcurrentRuns(rName, 2), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSGlueWorkflowExists(resourceName, &workflow), + resource.TestCheckResourceAttr(resourceName, "max_concurrent_runs", "2"), + ), + }, + { + Config: testAccAWSGlueWorkflowConfigMaxConcurrentRuns(rName, 1), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSGlueWorkflowExists(resourceName, &workflow), + resource.TestCheckResourceAttr(resourceName, "max_concurrent_runs", "1"), + ), + }, + }, + }) +} + func TestAccAWSGlueWorkflow_DefaultRunProperties(t *testing.T) { var workflow glue.Workflow @@ -311,6 +352,15 @@ resource "aws_glue_workflow" "test" { `, rName) } +func testAccAWSGlueWorkflowConfigMaxConcurrentRuns(rName string, runs int) string { + return fmt.Sprintf(` +resource "aws_glue_workflow" "test" { + name = %[1]q + max_concurrent_runs = %[2]d +} +`, rName, runs) +} + func testAccAWSGlueWorkflowConfigTags1(rName, tagKey1, tagValue1 string) string { return fmt.Sprintf(` resource "aws_glue_workflow" "test" { diff --git a/website/docs/r/glue_workflow.html.markdown b/website/docs/r/glue_workflow.html.markdown index 4fba84dc348..9be2664fb67 100644 --- a/website/docs/r/glue_workflow.html.markdown +++ b/website/docs/r/glue_workflow.html.markdown @@ -51,9 +51,10 @@ resource "aws_glue_trigger" "example-inner" { The following arguments are supported: +* `name` – (Required) The name you assign to this workflow. * `default_run_properties` – (Optional) A map of default run properties for this workflow. These properties are passed to all jobs associated to the workflow. * `description` – (Optional) Description of the workflow. -* `name` – (Required) The name you assign to this workflow. +* `max_concurrent_runs` - (Optional) Prevents exceeding the maximum number of concurrent runs of any of the component jobs. If you leave this parameter blank, there is no limit to the number of concurrent workflow runs. * `tags` - (Optional) Key-value map of resource tags ## Attributes Reference From 517098a67a3fdaa8c939900cafbcb08eee97824b Mon Sep 17 00:00:00 2001 From: DrFaust92 Date: Sat, 29 Aug 2020 22:18:54 +0300 Subject: [PATCH 3/5] update main arn doc --- website/docs/index.html.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/website/docs/index.html.markdown b/website/docs/index.html.markdown index 2a024fc7a18..9c9d0edf32c 100644 --- a/website/docs/index.html.markdown +++ b/website/docs/index.html.markdown @@ -266,6 +266,7 @@ for more information about connecting to alternate AWS endpoints or AWS compatib - [`aws_glue_job` resource](/docs/providers/aws/r/glue_job.html) - [`aws_glue_trigger` resource](/docs/providers/aws/r/glue_trigger.html) - [`aws_glue_user_defined_function` resource](/docs/providers/aws/r/glue_user_defined_function.html) + - [`aws_glue_workflow` resource](/docs/providers/aws/r/glue_workflow.html) - [`aws_guardduty_detector` resource](/docs/providers/aws/r/guardduty_detector.html) - [`aws_guardduty_ipset` resource](/docs/providers/aws/r/guardduty_ipset.html) - [`aws_guardduty_threatintelset` resource](/docs/providers/aws/r/guardduty_threatintelset.html) From 7d7820f086abe71a45d9f45179de76ec5db70184 Mon Sep 17 00:00:00 2001 From: DrFaust92 Date: Sat, 29 Aug 2020 22:24:21 +0300 Subject: [PATCH 4/5] validate name len --- aws/resource_aws_glue_workflow.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_glue_workflow.go b/aws/resource_aws_glue_workflow.go index f5ccfca6e43..89c390c158d 100644 --- a/aws/resource_aws_glue_workflow.go +++ b/aws/resource_aws_glue_workflow.go @@ -44,7 +44,7 @@ func resourceAwsGlueWorkflow() *schema.Resource { Type: schema.TypeString, Optional: true, ForceNew: true, - ValidateFunc: validation.NoZeroValues, + ValidateFunc: validation.StringLenBetween(1, 255), }, "tags": tagsSchema(), }, From a21cc55476b33b427778bb57a43f69ac82d93eb8 Mon Sep 17 00:00:00 2001 From: DrFaust92 Date: Fri, 4 Sep 2020 13:47:42 +0300 Subject: [PATCH 5/5] fix docs --- website/docs/index.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/index.html.markdown b/website/docs/index.html.markdown index 9c9d0edf32c..9e35a76bda8 100644 --- a/website/docs/index.html.markdown +++ b/website/docs/index.html.markdown @@ -266,7 +266,7 @@ for more information about connecting to alternate AWS endpoints or AWS compatib - [`aws_glue_job` resource](/docs/providers/aws/r/glue_job.html) - [`aws_glue_trigger` resource](/docs/providers/aws/r/glue_trigger.html) - [`aws_glue_user_defined_function` resource](/docs/providers/aws/r/glue_user_defined_function.html) - - [`aws_glue_workflow` resource](/docs/providers/aws/r/glue_workflow.html) + - [`aws_glue_workflow` resource](/docs/providers/aws/r/glue_workflow.html) - [`aws_guardduty_detector` resource](/docs/providers/aws/r/guardduty_detector.html) - [`aws_guardduty_ipset` resource](/docs/providers/aws/r/guardduty_ipset.html) - [`aws_guardduty_threatintelset` resource](/docs/providers/aws/r/guardduty_threatintelset.html)