diff --git a/.changelog/22837.txt b/.changelog/22837.txt new file mode 100644 index 00000000000..911b55f42e5 --- /dev/null +++ b/.changelog/22837.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_imagebuilder_image_recipe: Add `parameter` argument to the `component` configuration block +``` diff --git a/internal/service/imagebuilder/image_recipe.go b/internal/service/imagebuilder/image_recipe.go index ac813d8426d..a0b9e07dd4f 100644 --- a/internal/service/imagebuilder/image_recipe.go +++ b/internal/service/imagebuilder/image_recipe.go @@ -134,6 +134,23 @@ func ResourceImageRecipe() *schema.Resource { Required: true, ValidateFunc: verify.ValidARN, }, + "parameter": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 256), + }, + "value": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, }, }, }, @@ -367,6 +384,56 @@ func expandComponentConfiguration(tfMap map[string]interface{}) *imagebuilder.Co apiObject.ComponentArn = aws.String(v) } + if v, ok := tfMap["parameter"].(*schema.Set); ok && v.Len() > 0 { + apiObject.Parameters = expandComponentParameters(v.List()) + } + + return apiObject +} + +func expandComponentParameters(tfList []interface{}) []*imagebuilder.ComponentParameter { + if len(tfList) == 0 { + return nil + } + + var apiObjects []*imagebuilder.ComponentParameter + + for _, tfMapRaw := range tfList { + tfMap, ok := tfMapRaw.(map[string]interface{}) + + if !ok { + continue + } + + apiObject := expandComponentParameter(tfMap) + + if apiObject == nil { + continue + } + + apiObjects = append(apiObjects, apiObject) + } + + return apiObjects +} + +func expandComponentParameter(tfMap map[string]interface{}) *imagebuilder.ComponentParameter { + if tfMap == nil { + return nil + } + + apiObject := &imagebuilder.ComponentParameter{} + + 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 } @@ -499,6 +566,48 @@ func flattenComponentConfiguration(apiObject *imagebuilder.ComponentConfiguratio tfMap["component_arn"] = aws.StringValue(v) } + if v := apiObject.Parameters; v != nil { + tfMap["parameter"] = flattenComponentParameters(v) + } + + return tfMap +} + +func flattenComponentParameters(apiObjects []*imagebuilder.ComponentParameter) []interface{} { + if len(apiObjects) == 0 { + return nil + } + + var tfList []interface{} + + for _, apiObject := range apiObjects { + if apiObject == nil { + continue + } + + tfList = append(tfList, flattenComponentParameter(apiObject)) + } + + return tfList +} + +func flattenComponentParameter(apiObject *imagebuilder.ComponentParameter) 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 } diff --git a/internal/service/imagebuilder/image_recipe_test.go b/internal/service/imagebuilder/image_recipe_test.go index 97e64a4654d..0f139b91910 100644 --- a/internal/service/imagebuilder/image_recipe_test.go +++ b/internal/service/imagebuilder/image_recipe_test.go @@ -421,6 +421,32 @@ func TestAccImageBuilderImageRecipe_component(t *testing.T) { }) } +func TestAccImageBuilderImageRecipe_componentParameter(t *testing.T) { + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_imagebuilder_image_recipe.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, imagebuilder.EndpointsID), + Providers: acctest.Providers, + CheckDestroy: testAccCheckImageRecipeDestroy, + Steps: []resource.TestStep{ + { + Config: testAccImageRecipeComponentParameterConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckImageRecipeExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "component.#", "1"), + resource.TestCheckResourceAttr(resourceName, "component.0.parameter.#", "2"), + resource.TestCheckResourceAttr(resourceName, "component.0.parameter.0.name", "Parameter1"), + resource.TestCheckResourceAttr(resourceName, "component.0.parameter.0.value", "Value1"), + resource.TestCheckResourceAttr(resourceName, "component.0.parameter.1.name", "Parameter2"), + resource.TestCheckResourceAttr(resourceName, "component.0.parameter.1.value", "Value2"), + ), + }, + }, + }) +} + func TestAccImageBuilderImageRecipe_description(t *testing.T) { rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_imagebuilder_image_recipe.test" @@ -910,6 +936,58 @@ resource "aws_imagebuilder_image_recipe" "test" { `, rName)) } +func testAccImageRecipeComponentParameterConfig(rName string) string { + return fmt.Sprintf(` +data "aws_region" "current" {} + +data "aws_partition" "current" {} + +resource "aws_imagebuilder_component" "test" { + data = <