Skip to content

Commit

Permalink
Merge pull request #36953 from thatderek/f-imagebuilder-image-workflows
Browse files Browse the repository at this point in the history
r/imagebuilder_image: adds workflow functionality
  • Loading branch information
ewbankkit authored Apr 18, 2024
2 parents 624d56a + c249f58 commit 70718c6
Show file tree
Hide file tree
Showing 5 changed files with 537 additions and 17 deletions.
3 changes: 3 additions & 0 deletions .changelog/36953.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
resource/aws_imagebuilder_image: Add `execution_role` and `workflow` arguments
```
190 changes: 190 additions & 0 deletions internal/service/imagebuilder/flex.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package imagebuilder

import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/imagebuilder"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func flattenWorkflowParameter(apiObject *imagebuilder.WorkflowParameter) map[string]interface{} {
if apiObject == nil {
return nil
}

tfMap := map[string]interface{}{}

if v := apiObject.Name; v != nil {
tfMap["name"] = aws.StringValue(v)
}

if v := apiObject.Value; v != nil {
// ImageBuilder API quirk
// Even though Value is a slice, only one element is accepted.
tfMap["value"] = aws.StringValueSlice(v)[0]
}

return tfMap
}

func flattenWorkflowParameters(apiObjects []*imagebuilder.WorkflowParameter) []interface{} {
if len(apiObjects) == 0 {
return nil
}

var tfList []interface{}

for _, apiObject := range apiObjects {
if apiObject == nil {
continue
}

tfList = append(tfList, flattenWorkflowParameter(apiObject))
}

return tfList
}

func flattenWorkflowConfiguration(apiObject *imagebuilder.WorkflowConfiguration) map[string]interface{} {
if apiObject == nil {
return nil
}

tfMap := map[string]interface{}{}

if v := apiObject.OnFailure; v != nil {
tfMap["on_failure"] = aws.String(*v)
}

if v := apiObject.ParallelGroup; v != nil {
tfMap["parallel_group"] = aws.String(*v)
}

if v := apiObject.Parameters; v != nil {
tfMap["parameter"] = flattenWorkflowParameters(v)
}

if v := apiObject.WorkflowArn; v != nil {
tfMap["workflow_arn"] = aws.StringValue(v)
}

return tfMap
}

func flattenWorkflowConfigurations(apiObjects []*imagebuilder.WorkflowConfiguration) []interface{} {
if len(apiObjects) == 0 {
return nil
}

var tfList []interface{}

for _, apiObject := range apiObjects {
if apiObjects == nil {
continue
}

tfList = append(tfList, flattenWorkflowConfiguration(apiObject))
}

return tfList
}

func expandWorkflowParameter(tfMap map[string]interface{}) *imagebuilder.WorkflowParameter {
if tfMap == nil {
return nil
}

apiObject := &imagebuilder.WorkflowParameter{}

if v, ok := tfMap["name"].(string); ok && v != "" {
apiObject.Name = aws.String(v)
}

if v, ok := tfMap["value"].(string); ok && v != "" {
// ImageBuilder API quirk
// Even though Value is a slice, only one element is accepted.
apiObject.Value = aws.StringSlice([]string{v})
}

return apiObject
}

func expandWorkflowParameters(tfList []interface{}) []*imagebuilder.WorkflowParameter {
if len(tfList) == 0 {
return nil
}

var apiObjects []*imagebuilder.WorkflowParameter

for _, tfMapRaw := range tfList {
tfMap, ok := tfMapRaw.(map[string]interface{})

if !ok {
continue
}

apiObject := expandWorkflowParameter(tfMap)

if apiObject == nil {
continue
}

apiObjects = append(apiObjects, apiObject)
}

return apiObjects
}

func expandWorkflowConfiguration(tfMap map[string]interface{}) *imagebuilder.WorkflowConfiguration {
if tfMap == nil {
return nil
}

apiObject := &imagebuilder.WorkflowConfiguration{}

if v, ok := tfMap["on_failure"].(string); ok && v != "" {
apiObject.OnFailure = aws.String(v)
}

if v, ok := tfMap["parallel_group"].(string); ok && v != "" {
apiObject.ParallelGroup = aws.String(v)
}

if v, ok := tfMap["parameter"].(*schema.Set); ok && v.Len() > 0 {
apiObject.Parameters = expandWorkflowParameters(v.List())
}

if v, ok := tfMap["workflow_arn"].(string); ok && v != "" {
apiObject.WorkflowArn = aws.String(v)
}

return apiObject
}

func expandWorkflowConfigurations(tfList []interface{}) []*imagebuilder.WorkflowConfiguration {
if len(tfList) == 0 {
return nil
}

var apiObjects []*imagebuilder.WorkflowConfiguration

for _, tfMapRaw := range tfList {
tfMap, ok := tfMapRaw.(map[string]interface{})

if !ok {
continue
}

apiObject := expandWorkflowConfiguration(tfMap)

if apiObject == nil {
continue
}

apiObjects = append(apiObjects, apiObject)
}

return apiObjects
}
92 changes: 75 additions & 17 deletions internal/service/imagebuilder/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func ResourceImage() *schema.Resource {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
ValidateFunc: validation.StringMatch(regexache.MustCompile(`^arn:aws[^:]*:imagebuilder:[^:]+:(?:\d{12}|aws):container-recipe/[0-9a-z_-]+/\d+\.\d+\.\d+$`), "valid container recipe ARN must be provided"),
ValidateFunc: verify.ValidARN,
ExactlyOneOf: []string{"container_recipe_arn", "image_recipe_arn"},
},
"date_created": {
Expand All @@ -60,19 +60,25 @@ func ResourceImage() *schema.Resource {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
ValidateFunc: validation.StringMatch(regexache.MustCompile(`^arn:aws[^:]*:imagebuilder:[^:]+:(?:\d{12}|aws):distribution-configuration/[0-9a-z_-]+$`), "valid distribution configuration ARN must be provided"),
ValidateFunc: verify.ValidARN,
},
"enhanced_image_metadata_enabled": {
Type: schema.TypeBool,
Optional: true,
ForceNew: true,
Default: true,
},
"execution_role": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ValidateFunc: verify.ValidARN,
},
"image_recipe_arn": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
ValidateFunc: validation.StringMatch(regexache.MustCompile(`^arn:aws[^:]*:imagebuilder:[^:]+:(?:\d{12}|aws):image-recipe/[0-9a-z_-]+/\d+\.\d+\.\d+$`), "valid image recipe ARN must be provided"),
ValidateFunc: verify.ValidARN,
ExactlyOneOf: []string{"container_recipe_arn", "image_recipe_arn"},
},
"image_scanning_configuration": {
Expand Down Expand Up @@ -139,7 +145,7 @@ func ResourceImage() *schema.Resource {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validation.StringMatch(regexache.MustCompile(`^arn:aws[^:]*:imagebuilder:[^:]+:(?:\d{12}|aws):infrastructure-configuration/[0-9a-z_-]+$`), "valid infrastructure configuration ARN must be provided"),
ValidateFunc: verify.ValidARN,
},
"name": {
Type: schema.TypeString,
Expand Down Expand Up @@ -212,6 +218,54 @@ func ResourceImage() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},
"workflow": {
Type: schema.TypeSet,
Computed: true,
Optional: true,
ForceNew: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"on_failure": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
ValidateFunc: validation.StringInSlice(imagebuilder.OnWorkflowFailure_Values(), false),
},
"parallel_group": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
ValidateFunc: validation.StringMatch(regexache.MustCompile(`^[A-Za-z0-9][A-Za-z0-9-_+#]{0,99}$`), "valid parallel group string must be provider"),
},
"parameter": {
Type: schema.TypeSet,
Optional: true,
ForceNew: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validation.StringLenBetween(1, 128),
},
"value": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
},
},
},
"workflow_arn": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: verify.ValidARN,
},
},
},
},
},

CustomizeDiff: verify.SetTagsDiff,
Expand All @@ -236,6 +290,10 @@ func resourceImageCreate(ctx context.Context, d *schema.ResourceData, meta inter
input.DistributionConfigurationArn = aws.String(v.(string))
}

if v, ok := d.GetOk("execution_role"); ok {
input.ExecutionRole = aws.String(v.(string))
}

if v, ok := d.GetOk("image_recipe_arn"); ok {
input.ImageRecipeArn = aws.String(v.(string))
}
Expand All @@ -252,6 +310,10 @@ func resourceImageCreate(ctx context.Context, d *schema.ResourceData, meta inter
input.InfrastructureConfigurationArn = aws.String(v.(string))
}

if v, ok := d.GetOk("workflow"); ok && len(v.(*schema.Set).List()) > 0 {
input.Workflows = expandWorkflowConfigurations(v.(*schema.Set).List())
}

output, err := conn.CreateImageWithContext(ctx, input)

if err != nil {
Expand Down Expand Up @@ -298,52 +360,48 @@ func resourceImageRead(ctx context.Context, d *schema.ResourceData, meta interfa
image := output.Image

d.Set("arn", image.Arn)
d.Set("date_created", image.DateCreated)

if image.ContainerRecipe != nil {
d.Set("container_recipe_arn", image.ContainerRecipe.Arn)
}

d.Set("date_created", image.DateCreated)
if image.DistributionConfiguration != nil {
d.Set("distribution_configuration_arn", image.DistributionConfiguration.Arn)
}

d.Set("enhanced_image_metadata_enabled", image.EnhancedImageMetadataEnabled)

d.Set("execution_role", image.ExecutionRole)
if image.ImageRecipe != nil {
d.Set("image_recipe_arn", image.ImageRecipe.Arn)
}

if image.ImageScanningConfiguration != nil {
d.Set("image_scanning_configuration", []interface{}{flattenImageScanningConfiguration(image.ImageScanningConfiguration)})
} else {
d.Set("image_scanning_configuration", nil)
}

if image.ImageTestsConfiguration != nil {
d.Set("image_tests_configuration", []interface{}{flattenImageTestsConfiguration(image.ImageTestsConfiguration)})
} else {
d.Set("image_tests_configuration", nil)
}

if image.InfrastructureConfiguration != nil {
d.Set("infrastructure_configuration_arn", image.InfrastructureConfiguration.Arn)
}

d.Set("name", image.Name)
d.Set("platform", image.Platform)
d.Set("os_version", image.OsVersion)

if image.OutputResources != nil {
d.Set("output_resources", []interface{}{flattenOutputResources(image.OutputResources)})
} else {
d.Set("output_resources", nil)
}
d.Set("platform", image.Platform)
d.Set("version", image.Version)
if image.Workflows != nil {
d.Set("workflow", flattenWorkflowConfigurations(image.Workflows))
} else {
d.Set("workflow", nil)
}

setTagsOut(ctx, image.Tags)

d.Set("version", image.Version)

return diags
}

Expand Down
Loading

0 comments on commit 70718c6

Please sign in to comment.