From 5dce6f890120fc241e4c6b996f68d09f6f384231 Mon Sep 17 00:00:00 2001 From: Kamil Turek Date: Mon, 25 Dec 2023 22:11:52 +0100 Subject: [PATCH 1/9] Add aws_imagebuilder_workflow resource --- .../imagebuilder/service_package_gen.go | 8 + internal/service/imagebuilder/workflow.go | 219 ++++++++++++++++++ 2 files changed, 227 insertions(+) create mode 100644 internal/service/imagebuilder/workflow.go diff --git a/internal/service/imagebuilder/service_package_gen.go b/internal/service/imagebuilder/service_package_gen.go index 353f7600a04..f6b72137467 100644 --- a/internal/service/imagebuilder/service_package_gen.go +++ b/internal/service/imagebuilder/service_package_gen.go @@ -138,6 +138,14 @@ func (p *servicePackage) SDKResources(ctx context.Context) []*types.ServicePacka IdentifierAttribute: "id", }, }, + { + Factory: ResourceWorkflow, + TypeName: "aws_imagebuilder_workflow", + Name: "Workflow", + Tags: &types.ServicePackageResourceTags{ + IdentifierAttribute: "id", + }, + }, } } diff --git a/internal/service/imagebuilder/workflow.go b/internal/service/imagebuilder/workflow.go new file mode 100644 index 00000000000..bb0da462f4b --- /dev/null +++ b/internal/service/imagebuilder/workflow.go @@ -0,0 +1,219 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package imagebuilder + +import ( + "context" + "log" + + "github.com/YakDriver/regexache" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/imagebuilder" + "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/id" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" + tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" + "github.com/hashicorp/terraform-provider-aws/internal/verify" + "github.com/hashicorp/terraform-provider-aws/names" +) + +// @SDKResource("aws_imagebuilder_workflow", name="Workflow") +// @Tags(identifierAttribute="id") +func ResourceWorkflow() *schema.Resource { + return &schema.Resource{ + CreateWithoutTimeout: resourceWorkflowCreate, + ReadWithoutTimeout: resourceWorkflowRead, + UpdateWithoutTimeout: resourceWorkflowUpdate, + DeleteWithoutTimeout: resourceWorkflowDelete, + + Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "change_description": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validation.StringLenBetween(1, 1024), + }, + "data": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + ExactlyOneOf: []string{"data", "uri"}, + ValidateFunc: validation.StringLenBetween(1, 16000), + }, + "date_created": { + Type: schema.TypeString, + Computed: true, + }, + "description": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validation.StringLenBetween(1, 1024), + }, + "kms_key_id": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validation.StringLenBetween(1, 1024), + }, + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringLenBetween(1, 128), + }, + "owner": { + Type: schema.TypeString, + Computed: true, + }, + names.AttrTags: tftags.TagsSchema(), + names.AttrTagsAll: tftags.TagsSchemaComputed(), + "type": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice(imagebuilder.WorkflowType_Values(), false), + }, + "uri": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ExactlyOneOf: []string{"data", "uri"}, + }, + "version": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringMatch(regexache.MustCompile(`^[0-9]+\.[0-9]+\.[0-9]+$`), "valid semantic version must be provided"), + }, + }, + + CustomizeDiff: verify.SetTagsDiff, + } +} + +func resourceWorkflowCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + var diags diag.Diagnostics + conn := meta.(*conns.AWSClient).ImageBuilderConn(ctx) + + input := &imagebuilder.CreateWorkflowInput{ + ClientToken: aws.String(id.UniqueId()), + Name: aws.String(d.Get("name").(string)), + SemanticVersion: aws.String(d.Get("version").(string)), + Type: aws.String(d.Get("type").(string)), + Tags: getTagsIn(ctx), + } + + if v, ok := d.GetOk("change_description"); ok { + input.ChangeDescription = aws.String(v.(string)) + } + + if v, ok := d.GetOk("data"); ok { + input.Data = aws.String(v.(string)) + } + + if v, ok := d.GetOk("description"); ok { + input.Description = aws.String(v.(string)) + } + + if v, ok := d.GetOk("kms_key_id"); ok { + input.KmsKeyId = aws.String(v.(string)) + } + + if v, ok := d.GetOk("uri"); ok { + input.Uri = aws.String(v.(string)) + } + + output, err := conn.CreateWorkflowWithContext(ctx, input) + + if err != nil { + return sdkdiag.AppendErrorf(diags, "creating Image Builder Workflow: %s", err) + } + + if output == nil { + return sdkdiag.AppendErrorf(diags, "creating Image Builder Workflow: empty response") + } + + d.SetId(aws.StringValue(output.WorkflowBuildVersionArn)) + + return append(diags, resourceWorkflowRead(ctx, d, meta)...) +} + +func resourceWorkflowRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + var diags diag.Diagnostics + conn := meta.(*conns.AWSClient).ImageBuilderConn(ctx) + + input := &imagebuilder.GetWorkflowInput{ + WorkflowBuildVersionArn: aws.String(d.Id()), + } + + output, err := conn.GetWorkflowWithContext(ctx, input) + + if !d.IsNewResource() && tfawserr.ErrCodeEquals(err, imagebuilder.ErrCodeResourceNotFoundException) { + log.Printf("[WARN] Image Builder Workflow (%s) not found, removing from state", d.Id()) + d.SetId("") + return diags + } + + if output == nil || output.Workflow == nil { + return sdkdiag.AppendErrorf(diags, "getting Image Builder Workflow (%s): empty response", d.Id()) + } + + workflow := output.Workflow + + d.Set("arn", workflow.Arn) + d.Set("change_description", workflow.ChangeDescription) + d.Set("data", workflow.Data) + d.Set("date_created", workflow.DateCreated) + d.Set("description", workflow.Description) + d.Set("name", workflow.Name) + d.Set("kms_key_id", workflow.KmsKeyId) + d.Set("owner", workflow.Owner) + + setTagsOut(ctx, workflow.Tags) + + d.Set("type", workflow.Type) + d.Set("version", workflow.Version) + + return diags +} + +func resourceWorkflowUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + var diags diag.Diagnostics + + // Tags only. + + return append(diags, resourceWorkflowRead(ctx, d, meta)...) +} + +func resourceWorkflowDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + var diags diag.Diagnostics + conn := meta.(*conns.AWSClient).ImageBuilderConn(ctx) + + input := &imagebuilder.DeleteWorkflowInput{ + WorkflowBuildVersionArn: aws.String(d.Id()), + } + + _, err := conn.DeleteWorkflowWithContext(ctx, input) + + if tfawserr.ErrCodeEquals(err, imagebuilder.ErrCodeResourceNotFoundException) { + return diags + } + + if err != nil { + return sdkdiag.AppendErrorf(diags, "deleting Image Builder Workflow (%s): %s", d.Id(), err) + } + + return diags +} From ca6c86643aae6722acd8c5da05802270a4db4a68 Mon Sep 17 00:00:00 2001 From: Kamil Turek Date: Fri, 29 Dec 2023 16:11:20 +0100 Subject: [PATCH 2/9] Support import --- internal/service/imagebuilder/workflow.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/internal/service/imagebuilder/workflow.go b/internal/service/imagebuilder/workflow.go index bb0da462f4b..75c51084910 100644 --- a/internal/service/imagebuilder/workflow.go +++ b/internal/service/imagebuilder/workflow.go @@ -31,6 +31,9 @@ func ResourceWorkflow() *schema.Resource { ReadWithoutTimeout: resourceWorkflowRead, UpdateWithoutTimeout: resourceWorkflowUpdate, DeleteWithoutTimeout: resourceWorkflowDelete, + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, Schema: map[string]*schema.Schema{ "arn": { From 29e6be43a2376b4769351f5a06f5824bee2db10f Mon Sep 17 00:00:00 2001 From: Kamil Turek Date: Fri, 29 Dec 2023 16:11:28 +0100 Subject: [PATCH 3/9] Add acceptance tests --- .../service/imagebuilder/workflow_test.go | 595 ++++++++++++++++++ 1 file changed, 595 insertions(+) create mode 100644 internal/service/imagebuilder/workflow_test.go diff --git a/internal/service/imagebuilder/workflow_test.go b/internal/service/imagebuilder/workflow_test.go new file mode 100644 index 00000000000..2abb90a4adc --- /dev/null +++ b/internal/service/imagebuilder/workflow_test.go @@ -0,0 +1,595 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package imagebuilder_test + +import ( + "context" + "fmt" + "testing" + + "github.com/YakDriver/regexache" + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/imagebuilder" + "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" + sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/terraform" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + tfimagebuilder "github.com/hashicorp/terraform-provider-aws/internal/service/imagebuilder" +) + +func TestAccImageBuilderWorkflow_basic(t *testing.T) { + ctx := acctest.Context(t) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_imagebuilder_workflow.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, imagebuilder.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckWorkflowDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccWorkflowConfig_name(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckWorkflowExists(ctx, resourceName), + acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "imagebuilder", regexache.MustCompile(fmt.Sprintf("workflow/test/%s/1.0.0/[1-9][0-9]*", rName))), + resource.TestCheckResourceAttr(resourceName, "change_description", ""), + resource.TestMatchResourceAttr(resourceName, "data", regexache.MustCompile(`schemaVersion`)), + acctest.CheckResourceAttrRFC3339(resourceName, "date_created"), + resource.TestCheckResourceAttr(resourceName, "description", ""), + resource.TestCheckResourceAttr(resourceName, "kms_key_id", ""), + resource.TestCheckResourceAttr(resourceName, "name", rName), + acctest.CheckResourceAttrAccountID(resourceName, "owner"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + resource.TestCheckResourceAttr(resourceName, "type", imagebuilder.WorkflowTypeTest), + resource.TestCheckResourceAttr(resourceName, "version", "1.0.0"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccImageBuilderWorkflow_disappears(t *testing.T) { + ctx := acctest.Context(t) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_imagebuilder_workflow.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, imagebuilder.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckWorkflowDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccWorkflowConfig_name(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckWorkflowExists(ctx, resourceName), + acctest.CheckResourceDisappears(ctx, acctest.Provider, tfimagebuilder.ResourceWorkflow(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func TestAccImageBuilderWorkflow_changeDescription(t *testing.T) { + ctx := acctest.Context(t) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_imagebuilder_workflow.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, imagebuilder.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckWorkflowDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccWorkflowConfig_changeDescription(rName, "description1"), + Check: resource.ComposeTestCheckFunc( + testAccCheckWorkflowExists(ctx, resourceName), + resource.TestCheckResourceAttr(resourceName, "change_description", "description1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccImageBuilderWorkflow_description(t *testing.T) { + ctx := acctest.Context(t) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_imagebuilder_workflow.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, imagebuilder.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckWorkflowDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccWorkflowConfig_description(rName, "description1"), + Check: resource.ComposeTestCheckFunc( + testAccCheckWorkflowExists(ctx, resourceName), + resource.TestCheckResourceAttr(resourceName, "description", "description1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccImageBuilderWorkflow_kmsKeyID(t *testing.T) { + ctx := acctest.Context(t) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_imagebuilder_workflow.test" + kmsKeyResourceName := "aws_kms_key.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, imagebuilder.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckWorkflowDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccWorkflowConfig_kmsKeyID(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckWorkflowExists(ctx, resourceName), + resource.TestCheckResourceAttrPair(resourceName, "kms_key_id", kmsKeyResourceName, "arn"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccImageBuilderWorkflow_tags(t *testing.T) { + ctx := acctest.Context(t) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_imagebuilder_workflow.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, imagebuilder.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckWorkflowDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccWorkflowConfig_tags1(rName, "key1", "value1"), + Check: resource.ComposeTestCheckFunc( + testAccCheckWorkflowExists(ctx, resourceName), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccWorkflowConfig_tags2(rName, "key1", "value1updated", "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckWorkflowExists(ctx, resourceName), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + { + Config: testAccWorkflowConfig_tags1(rName, "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckWorkflowExists(ctx, resourceName), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + }, + }) +} + +func TestAccImageBuilderWorkflow_uri(t *testing.T) { + ctx := acctest.Context(t) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_imagebuilder_workflow.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, imagebuilder.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckWorkflowDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccWorkflowConfig_uri(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckWorkflowExists(ctx, resourceName), + resource.TestCheckResourceAttrSet(resourceName, "data"), + resource.TestCheckResourceAttrSet(resourceName, "uri"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"uri"}, + }, + }, + }) +} + +func testAccCheckWorkflowDestroy(ctx context.Context) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := acctest.Provider.Meta().(*conns.AWSClient).ImageBuilderConn(ctx) + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_imagebuilder_workflow" { + continue + } + + input := &imagebuilder.GetWorkflowInput{ + WorkflowBuildVersionArn: aws.String(rs.Primary.ID), + } + + output, err := conn.GetWorkflowWithContext(ctx, input) + + if tfawserr.ErrCodeEquals(err, imagebuilder.ErrCodeResourceNotFoundException) { + continue + } + + if err != nil { + return fmt.Errorf("error getting Image Builder Workflow (%s): %w", rs.Primary.ID, err) + } + + if output != nil { + return fmt.Errorf("Image Builder Workflow (%s) still exists", rs.Primary.ID) + } + } + + return nil + } +} + +func testAccCheckWorkflowExists(ctx context.Context, resourceName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("resource not found: %s", resourceName) + } + + conn := acctest.Provider.Meta().(*conns.AWSClient).ImageBuilderConn(ctx) + + input := &imagebuilder.GetWorkflowInput{ + WorkflowBuildVersionArn: aws.String(rs.Primary.ID), + } + + _, err := conn.GetWorkflowWithContext(ctx, input) + + if err != nil { + return fmt.Errorf("error getting Image Builder Workflow (%s): %w", rs.Primary.ID, err) + } + + return nil + } +} + +func testAccWorkflowConfig_name(rName string) string { + return fmt.Sprintf(` +resource "aws_imagebuilder_workflow" "test" { + name = %[1]q + version = "1.0.0" + type = "TEST" + + data = <<-EOT + name: test-image + description: Workflow to test an image + schemaVersion: 1.0 + + parameters: + - name: waitForActionAtEnd + type: boolean + + steps: + - name: LaunchTestInstance + action: LaunchInstance + onFailure: Abort + inputs: + waitFor: "ssmAgent" + + - name: TerminateTestInstance + action: TerminateInstance + onFailure: Continue + inputs: + instanceId.$: "$.stepOutputs.LaunchTestInstance.instanceId" + + - name: WaitForActionAtEnd + action: WaitForAction + if: + booleanEquals: true + value: "$.parameters.waitForActionAtEnd" + EOT +} +`, rName) +} + +func testAccWorkflowConfig_changeDescription(rName, changeDescription string) string { + return fmt.Sprintf(` +resource "aws_imagebuilder_workflow" "test" { + name = %[1]q + version = "1.0.0" + type = "TEST" + + change_description = %[2]q + + data = <<-EOT + name: test-image + description: Workflow to test an image + schemaVersion: 1.0 + + parameters: + - name: waitForActionAtEnd + type: boolean + + steps: + - name: LaunchTestInstance + action: LaunchInstance + onFailure: Abort + inputs: + waitFor: "ssmAgent" + + - name: TerminateTestInstance + action: TerminateInstance + onFailure: Continue + inputs: + instanceId.$: "$.stepOutputs.LaunchTestInstance.instanceId" + + - name: WaitForActionAtEnd + action: WaitForAction + if: + booleanEquals: true + value: "$.parameters.waitForActionAtEnd" + EOT +} +`, rName, changeDescription) +} + +func testAccWorkflowConfig_description(rName, description string) string { + return fmt.Sprintf(` +resource "aws_imagebuilder_workflow" "test" { + name = %[1]q + version = "1.0.0" + type = "TEST" + + description = %[2]q + + data = <<-EOT + name: test-image + description: Workflow to test an image + schemaVersion: 1.0 + + parameters: + - name: waitForActionAtEnd + type: boolean + + steps: + - name: LaunchTestInstance + action: LaunchInstance + onFailure: Abort + inputs: + waitFor: "ssmAgent" + + - name: TerminateTestInstance + action: TerminateInstance + onFailure: Continue + inputs: + instanceId.$: "$.stepOutputs.LaunchTestInstance.instanceId" + + - name: WaitForActionAtEnd + action: WaitForAction + if: + booleanEquals: true + value: "$.parameters.waitForActionAtEnd" + EOT +} +`, rName, description) +} + +func testAccWorkflowConfig_kmsKeyID(rName string) string { + return fmt.Sprintf(` +resource "aws_kms_key" "test" { + deletion_window_in_days = 7 +} + +resource "aws_imagebuilder_workflow" "test" { + name = %[1]q + version = "1.0.0" + type = "TEST" + + kms_key_id = aws_kms_key.test.arn + + data = <<-EOT + name: test-image + description: Workflow to test an image + schemaVersion: 1.0 + + parameters: + - name: waitForActionAtEnd + type: boolean + + steps: + - name: LaunchTestInstance + action: LaunchInstance + onFailure: Abort + inputs: + waitFor: "ssmAgent" + + - name: TerminateTestInstance + action: TerminateInstance + onFailure: Continue + inputs: + instanceId.$: "$.stepOutputs.LaunchTestInstance.instanceId" + + - name: WaitForActionAtEnd + action: WaitForAction + if: + booleanEquals: true + value: "$.parameters.waitForActionAtEnd" + EOT +} +`, rName) +} + +func testAccWorkflowConfig_tags1(rName string, tagKey1 string, tagValue1 string) string { + return fmt.Sprintf(` +resource "aws_imagebuilder_workflow" "test" { + name = %[1]q + version = "1.0.0" + type = "TEST" + + tags = { + %[2]q = %[3]q + } + + data = <<-EOT + name: test-image + description: Workflow to test an image + schemaVersion: 1.0 + + parameters: + - name: waitForActionAtEnd + type: boolean + + steps: + - name: LaunchTestInstance + action: LaunchInstance + onFailure: Abort + inputs: + waitFor: "ssmAgent" + + - name: TerminateTestInstance + action: TerminateInstance + onFailure: Continue + inputs: + instanceId.$: "$.stepOutputs.LaunchTestInstance.instanceId" + + - name: WaitForActionAtEnd + action: WaitForAction + if: + booleanEquals: true + value: "$.parameters.waitForActionAtEnd" + EOT +} +`, rName, tagKey1, tagValue1) +} + +func testAccWorkflowConfig_tags2(rName string, tagKey1 string, tagValue1 string, tagKey2 string, tagValue2 string) string { + return fmt.Sprintf(` +resource "aws_imagebuilder_workflow" "test" { + name = %[1]q + version = "1.0.0" + type = "TEST" + + tags = { + %[2]q = %[3]q + %[4]q = %[5]q + } + + data = <<-EOT + name: test-image + description: Workflow to test an image + schemaVersion: 1.0 + + parameters: + - name: waitForActionAtEnd + type: boolean + + steps: + - name: LaunchTestInstance + action: LaunchInstance + onFailure: Abort + inputs: + waitFor: "ssmAgent" + + - name: TerminateTestInstance + action: TerminateInstance + onFailure: Continue + inputs: + instanceId.$: "$.stepOutputs.LaunchTestInstance.instanceId" + + - name: WaitForActionAtEnd + action: WaitForAction + if: + booleanEquals: true + value: "$.parameters.waitForActionAtEnd" + EOT +} +`, rName, tagKey1, tagValue1, tagKey2, tagValue2) +} + +func testAccWorkflowConfig_uri(rName string) string { + return fmt.Sprintf(` +resource "aws_s3_bucket" "test" { + bucket = %[1]q +} + +resource "aws_s3_object" "test" { + bucket = aws_s3_bucket.test.bucket + key = "test.yml" + + content = <<-EOT + name: test-image + description: Workflow to test an image + schemaVersion: 1.0 + + parameters: + - name: waitForActionAtEnd + type: boolean + + steps: + - name: LaunchTestInstance + action: LaunchInstance + onFailure: Abort + inputs: + waitFor: "ssmAgent" + + - name: TerminateTestInstance + action: TerminateInstance + onFailure: Continue + inputs: + instanceId.$: "$.stepOutputs.LaunchTestInstance.instanceId" + + - name: WaitForActionAtEnd + action: WaitForAction + if: + booleanEquals: true + value: "$.parameters.waitForActionAtEnd" + EOT +} + +resource "aws_imagebuilder_workflow" "test" { + name = %[1]q + version = "1.0.0" + type = "TEST" + + uri = "s3://${aws_s3_bucket.test.bucket}/${aws_s3_object.test.key}" +} +`, rName) +} From ffdc964d0c44d55dda579eb54632b2e0310c8920 Mon Sep 17 00:00:00 2001 From: Kamil Turek Date: Sat, 30 Dec 2023 11:49:15 +0100 Subject: [PATCH 4/9] Add docs --- .../r/imagebuilder_workflow.html.markdown | 95 +++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 website/docs/r/imagebuilder_workflow.html.markdown diff --git a/website/docs/r/imagebuilder_workflow.html.markdown b/website/docs/r/imagebuilder_workflow.html.markdown new file mode 100644 index 00000000000..f5b6d320cfb --- /dev/null +++ b/website/docs/r/imagebuilder_workflow.html.markdown @@ -0,0 +1,95 @@ +--- +subcategory: "EC2 Image Builder" +layout: "aws" +page_title: "AWS: aws_imagebuilder_workflow" +description: |- + Terraform resource for managing an AWS EC2 Image Builder Workflow. +--- +# Resource: aws_imagebuilder_workflow + +Terraform resource for managing an AWS EC2 Image Builder Workflow. + +## Example Usage + +### Basic Usage + +```terraform +resource "aws_imagebuilder_workflow" "example" { + name = "example" + version = "1.0.0" + type = "TEST" + + data = <<-EOT + name: example + description: Workflow to test an image + schemaVersion: 1.0 + + parameters: + - name: waitForActionAtEnd + type: boolean + + steps: + - name: LaunchTestInstance + action: LaunchInstance + onFailure: Abort + inputs: + waitFor: "ssmAgent" + + - name: TerminateTestInstance + action: TerminateInstance + onFailure: Continue + inputs: + instanceId.$: "$.stepOutputs.LaunchTestInstance.instanceId" + + - name: WaitForActionAtEnd + action: WaitForAction + if: + booleanEquals: true + value: "$.parameters.waitForActionAtEnd" + EOT +} +``` + +## Argument Reference + +The following arguments are required: + +* `name` - (Required) Name of the workflow. +* `type` - (Required) Type of the workflow. Valid values: `BUILD`, `TEST`, `DISTRIBUTION`. +* `version` - (Required) Version of the workflow. + +The following arguments are optional: + +* `change_description` - (Optional) Change description of the workflow. +* `data` - (Optional) Inline YAML string with data of the workflow. Exactly one of `data` and `uri` can be specified. +* `description` - (Optional) Description of the workflow. +* `kms_key_id` - (Optional) Amazon Resource Name (ARN) of the Key Management Service (KMS) Key used to encrypt the workflow. +* `tags` - (Optional) Key-value map of resource tags for the component. If configured with a provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. +* `uri` - (Optional) S3 URI with data of the component. Exactly one of `data` and `uri` can be specified. + +## Attribute Reference + +This resource exports the following attributes in addition to the arguments above: + +* `arn` - Amazon Resource Name (ARN) of the workflow. +* `date_created` - Date the workflow was created. +* `owner` - Owner of the workflow. + +## Import + +In Terraform v1.5.0 and later, use an [`import` block](https://developer.hashicorp.com/terraform/language/import) to import EC2 Image Builder Workflow using the `example_id_arg`. For example: + +```terraform +import { + to = aws_imagebuilder_workflow.example + id = "workflow-id-12345678" +} +``` + +Using `terraform import`, import EC2 Image Builder Workflow using the `example_id_arg`. For example: + +```console +% terraform import aws_imagebuilder_workflow.example arn:aws:imagebuilder:us-east-1:aws:workflow/test/example/1.0.1/1 +``` + +Certain resource arguments, such as `uri`, cannot be read via the API and imported into Terraform. Terraform will display a difference for these arguments the first run after import if declared in the Terraform configuration for an imported resource. From a53659d5f8105cfd43e3357863185fb31801d9a6 Mon Sep 17 00:00:00 2001 From: Kamil Turek Date: Sat, 30 Dec 2023 11:58:11 +0100 Subject: [PATCH 5/9] Replace component references from docs --- website/docs/r/imagebuilder_workflow.html.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/docs/r/imagebuilder_workflow.html.markdown b/website/docs/r/imagebuilder_workflow.html.markdown index f5b6d320cfb..7486b12aaf1 100644 --- a/website/docs/r/imagebuilder_workflow.html.markdown +++ b/website/docs/r/imagebuilder_workflow.html.markdown @@ -64,8 +64,8 @@ The following arguments are optional: * `data` - (Optional) Inline YAML string with data of the workflow. Exactly one of `data` and `uri` can be specified. * `description` - (Optional) Description of the workflow. * `kms_key_id` - (Optional) Amazon Resource Name (ARN) of the Key Management Service (KMS) Key used to encrypt the workflow. -* `tags` - (Optional) Key-value map of resource tags for the component. If configured with a provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. -* `uri` - (Optional) S3 URI with data of the component. Exactly one of `data` and `uri` can be specified. +* `tags` - (Optional) Key-value map of resource tags for the workflow. If configured with a provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. +* `uri` - (Optional) S3 URI with data of the workflow. Exactly one of `data` and `uri` can be specified. ## Attribute Reference From f8c6029dba25fcb5deec360f724935aa95db2ad0 Mon Sep 17 00:00:00 2001 From: Kamil Turek Date: Sat, 30 Dec 2023 12:17:48 +0100 Subject: [PATCH 6/9] Fix terrafmt issues --- .../service/imagebuilder/workflow_test.go | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/internal/service/imagebuilder/workflow_test.go b/internal/service/imagebuilder/workflow_test.go index 2abb90a4adc..e60dfae1175 100644 --- a/internal/service/imagebuilder/workflow_test.go +++ b/internal/service/imagebuilder/workflow_test.go @@ -294,9 +294,9 @@ func testAccCheckWorkflowExists(ctx context.Context, resourceName string) resour func testAccWorkflowConfig_name(rName string) string { return fmt.Sprintf(` resource "aws_imagebuilder_workflow" "test" { - name = %[1]q - version = "1.0.0" - type = "TEST" + name = %[1]q + version = "1.0.0" + type = "TEST" data = <<-EOT name: test-image @@ -333,9 +333,9 @@ resource "aws_imagebuilder_workflow" "test" { func testAccWorkflowConfig_changeDescription(rName, changeDescription string) string { return fmt.Sprintf(` resource "aws_imagebuilder_workflow" "test" { - name = %[1]q - version = "1.0.0" - type = "TEST" + name = %[1]q + version = "1.0.0" + type = "TEST" change_description = %[2]q @@ -374,9 +374,9 @@ resource "aws_imagebuilder_workflow" "test" { func testAccWorkflowConfig_description(rName, description string) string { return fmt.Sprintf(` resource "aws_imagebuilder_workflow" "test" { - name = %[1]q - version = "1.0.0" - type = "TEST" + name = %[1]q + version = "1.0.0" + type = "TEST" description = %[2]q @@ -419,9 +419,9 @@ resource "aws_kms_key" "test" { } resource "aws_imagebuilder_workflow" "test" { - name = %[1]q - version = "1.0.0" - type = "TEST" + name = %[1]q + version = "1.0.0" + type = "TEST" kms_key_id = aws_kms_key.test.arn @@ -460,9 +460,9 @@ resource "aws_imagebuilder_workflow" "test" { func testAccWorkflowConfig_tags1(rName string, tagKey1 string, tagValue1 string) string { return fmt.Sprintf(` resource "aws_imagebuilder_workflow" "test" { - name = %[1]q - version = "1.0.0" - type = "TEST" + name = %[1]q + version = "1.0.0" + type = "TEST" tags = { %[2]q = %[3]q @@ -503,9 +503,9 @@ resource "aws_imagebuilder_workflow" "test" { func testAccWorkflowConfig_tags2(rName string, tagKey1 string, tagValue1 string, tagKey2 string, tagValue2 string) string { return fmt.Sprintf(` resource "aws_imagebuilder_workflow" "test" { - name = %[1]q - version = "1.0.0" - type = "TEST" + name = %[1]q + version = "1.0.0" + type = "TEST" tags = { %[2]q = %[3]q @@ -585,9 +585,9 @@ resource "aws_s3_object" "test" { } resource "aws_imagebuilder_workflow" "test" { - name = %[1]q - version = "1.0.0" - type = "TEST" + name = %[1]q + version = "1.0.0" + type = "TEST" uri = "s3://${aws_s3_bucket.test.bucket}/${aws_s3_object.test.key}" } From e878450b0eb463cbbb236bf6dd07232b6459798a Mon Sep 17 00:00:00 2001 From: Kamil Turek Date: Sat, 30 Dec 2023 12:19:22 +0100 Subject: [PATCH 7/9] Fix more terrafmt issues --- website/docs/r/imagebuilder_workflow.html.markdown | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/website/docs/r/imagebuilder_workflow.html.markdown b/website/docs/r/imagebuilder_workflow.html.markdown index 7486b12aaf1..56bd76fc2ee 100644 --- a/website/docs/r/imagebuilder_workflow.html.markdown +++ b/website/docs/r/imagebuilder_workflow.html.markdown @@ -15,9 +15,9 @@ Terraform resource for managing an AWS EC2 Image Builder Workflow. ```terraform resource "aws_imagebuilder_workflow" "example" { - name = "example" - version = "1.0.0" - type = "TEST" + name = "example" + version = "1.0.0" + type = "TEST" data = <<-EOT name: example From 59c5ca243151b78bd7ba202ad5ad08750ee119f3 Mon Sep 17 00:00:00 2001 From: Kamil Turek Date: Sat, 30 Dec 2023 12:19:57 +0100 Subject: [PATCH 8/9] Add changelog --- .changelog/35097.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/35097.txt diff --git a/.changelog/35097.txt b/.changelog/35097.txt new file mode 100644 index 00000000000..5fc7483e84b --- /dev/null +++ b/.changelog/35097.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_imagebuilder_workflow +``` From ef23e3bebce95e5a33ea29a8deab7659e752a8ac Mon Sep 17 00:00:00 2001 From: Kamil Turek Date: Sat, 30 Dec 2023 12:33:22 +0100 Subject: [PATCH 9/9] Fix imports --- internal/service/imagebuilder/workflow.go | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/service/imagebuilder/workflow.go b/internal/service/imagebuilder/workflow.go index 75c51084910..28a6bcadb70 100644 --- a/internal/service/imagebuilder/workflow.go +++ b/internal/service/imagebuilder/workflow.go @@ -8,7 +8,6 @@ import ( "log" "github.com/YakDriver/regexache" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/imagebuilder" "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr"