Skip to content

aws_sagemaker_image_version - add support for alias fixes #35931 #42610

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changelog/42610.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
resource/aws_sagemaker_image_version: Add `aliases` argument
```
69 changes: 66 additions & 3 deletions internal/service/sagemaker/image_version.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,13 @@ func resourceImageVersion() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},
"aliases": {
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"base_image": {
Type: schema.TypeString,
Required: true,
Expand Down Expand Up @@ -153,6 +160,10 @@ func resourceImageVersionCreate(ctx context.Context, d *schema.ResourceData, met
input.ProgrammingLang = aws.String(v.(string))
}

if v, ok := d.GetOk("aliases"); ok && v.(*schema.Set).Len() > 0 {
input.Aliases = flex.ExpandStringValueSet(v.(*schema.Set))
}

if _, err := conn.CreateImageVersion(ctx, &input); err != nil {
return sdkdiag.AppendErrorf(diags, "creating SageMaker AI Image Version %s: %s", name, err)
}
Expand Down Expand Up @@ -208,6 +219,17 @@ func resourceImageVersionRead(ctx context.Context, d *schema.ResourceData, meta
d.Set("ml_framework", image.MLFramework)
d.Set("programming_lang", image.ProgrammingLang)

// The DescribeImageVersion API response does not include aliases, so these must
// be fetched separately using the ListAliases API
aliases, err := findImageVersionAliasesByTwoPartKey(ctx, conn, name, version)
if err != nil {
return sdkdiag.AppendErrorf(diags, "reading aliases for SageMaker AI Image Version (%s): %s", d.Id(), err)
}

if err := d.Set("aliases", aliases); err != nil {
return sdkdiag.AppendErrorf(diags, "setting aliases: %s", err)
}

return diags
}

Expand Down Expand Up @@ -251,6 +273,21 @@ func resourceImageVersionUpdate(ctx context.Context, d *schema.ResourceData, met
input.ProgrammingLang = aws.String(d.Get("programming_lang").(string))
}

if d.HasChange("aliases") {
// For UpdateImageVersion, we need to use AliasesToAdd and AliasesToDelete
// instead of Aliases directly
o, n := d.GetChange("aliases")
os, ns := o.(*schema.Set), n.(*schema.Set)
add, del := flex.ExpandStringValueSet(ns.Difference(os)), flex.ExpandStringValueSet(os.Difference(ns))

if len(add) > 0 {
input.AliasesToAdd = add
}
if len(del) > 0 {
input.AliasesToDelete = del
}
}

if _, err := conn.UpdateImageVersion(ctx, &input); err != nil {
return sdkdiag.AppendErrorf(diags, "updating SageMaker AI Image Version (%s): %s", d.Id(), err)
}
Expand All @@ -265,12 +302,12 @@ func resourceImageVersionDelete(ctx context.Context, d *schema.ResourceData, met
name := d.Get("image_name").(string)
version := d.Get(names.AttrVersion).(int)

input := &sagemaker.DeleteImageVersionInput{
input := sagemaker.DeleteImageVersionInput{
ImageName: aws.String(name),
Version: aws.Int32(int32(version)),
}

if _, err := conn.DeleteImageVersion(ctx, input); err != nil {
if _, err := conn.DeleteImageVersion(ctx, &input); err != nil {
if errs.IsAErrorMessageContains[*awstypes.ResourceNotFound](err, "does not exist") {
return diags
}
Expand Down Expand Up @@ -342,6 +379,32 @@ func findImageVersionByTwoPartKey(ctx context.Context, conn *sagemaker.Client, n
return output, nil
}

func findImageVersionAliasesByTwoPartKey(ctx context.Context, conn *sagemaker.Client, name string, version int) ([]string, error) {
input := sagemaker.ListAliasesInput{
ImageName: aws.String(name),
Version: aws.Int32(int32(version)),
}

output, err := conn.ListAliases(ctx, &input)

if errs.IsAErrorMessageContains[*awstypes.ResourceNotFound](err, "does not exist") {
return nil, &retry.NotFoundError{
LastError: err,
LastRequest: input,
}
}

if err != nil {
return nil, err
}

if output == nil {
return nil, tfresource.NewEmptyResultError(input)
}

return output.SageMakerImageVersionAliases, nil
}

// expandImageVersionResourceID wraps flex.ExpandResourceId and handles conversion
// of the version portion to an integer
func expandImageVersionResourceID(id string) (string, int, error) {
Expand All @@ -353,7 +416,7 @@ func expandImageVersionResourceID(id string) (string, int, error) {
name := parts[0]
version, err := strconv.Atoi(parts[1])
if err != nil {
return name, version, err
return name, 0, err
}

return name, version, nil
Expand Down
66 changes: 66 additions & 0 deletions internal/service/sagemaker/image_version_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,60 @@ func TestAccSageMakerImageVersion_multiple(t *testing.T) {
})
}

func TestAccSageMakerImageVersion_aliases(t *testing.T) {
ctx := acctest.Context(t)

var image sagemaker.DescribeImageVersionOutput
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
resourceName := "aws_sagemaker_image_version.test"
baseImage := acctest.SkipIfEnvVarNotSet(t, imageVersionBaseImageEnvVar)

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(ctx, t) },
ErrorCheck: acctest.ErrorCheck(t, names.SageMakerServiceID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckImageVersionDestroy(ctx),
Steps: []resource.TestStep{
{
Config: testAccImageVersionConfig_aliases(rName, baseImage),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckImageVersionExists(ctx, resourceName, &image),
resource.TestCheckResourceAttr(resourceName, "image_name", rName),
resource.TestCheckResourceAttr(resourceName, "base_image", baseImage),
resource.TestCheckResourceAttr(resourceName, "aliases.#", "2"),
resource.TestCheckTypeSetElemAttr(resourceName, "aliases.*", "latest"),
resource.TestCheckTypeSetElemAttr(resourceName, "aliases.*", "stable"),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
{
Config: testAccImageVersionConfig_basic(rName, baseImage),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckImageVersionExists(ctx, resourceName, &image),
resource.TestCheckResourceAttr(resourceName, "image_name", rName),
resource.TestCheckResourceAttr(resourceName, "base_image", baseImage),
resource.TestCheckResourceAttr(resourceName, "aliases.#", "0"),
),
},
{
Config: testAccImageVersionConfig_aliases(rName, baseImage),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckImageVersionExists(ctx, resourceName, &image),
resource.TestCheckResourceAttr(resourceName, "image_name", rName),
resource.TestCheckResourceAttr(resourceName, "base_image", baseImage),
resource.TestCheckResourceAttr(resourceName, "aliases.#", "2"),
resource.TestCheckTypeSetElemAttr(resourceName, "aliases.*", "latest"),
resource.TestCheckTypeSetElemAttr(resourceName, "aliases.*", "stable"),
),
},
},
})
}

func TestAccSageMakerImageVersion_upgrade_V5_98_0(t *testing.T) {
ctx := acctest.Context(t)

Expand Down Expand Up @@ -423,3 +477,15 @@ resource "aws_sagemaker_image_version" "test_v2" {
}
`, baseImage))
}

func testAccImageVersionConfig_aliases(rName, baseImage string) string {
return acctest.ConfigCompose(
testAccImageVersionConfigBase(rName),
fmt.Sprintf(`
resource "aws_sagemaker_image_version" "test" {
image_name = aws_sagemaker_image.test.id
base_image = %[1]q
aliases = ["latest", "stable"]
}
`, baseImage))
}
11 changes: 11 additions & 0 deletions website/docs/r/sagemaker_image_version.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,23 @@ resource "aws_sagemaker_image_version" "example" {
}
```

### With Aliases

```terraform
resource "aws_sagemaker_image_version" "test" {
image_name = aws_sagemaker_image.test.id
base_image = "012345678912.dkr.ecr.us-west-2.amazonaws.com/image:latest"
aliases = ["latest", "stable"]
}
```

## Argument Reference

This resource supports the following arguments:

* `image_name` - (Required) The name of the image. Must be unique to your account.
* `base_image` - (Required) The registry path of the container image on which this image version is based.
* `aliases` - (Optional) A list of aliases for the image version.
* `horovod` - (Optional) Indicates Horovod compatibility.
* `job_type` - (Optional) Indicates SageMaker AI job type compatibility. Valid values are: `TRAINING`, `INFERENCE`, and `NOTEBOOK_KERNEL`.
* `ml_framework` - (Optional) The machine learning framework vended in the image version.
Expand Down
Loading