Skip to content
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

r/sagemaker_image_version - new resource #17141

Merged
merged 9 commits into from
Jan 20, 2021
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
23 changes: 21 additions & 2 deletions aws/internal/service/sagemaker/finder/finder.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ func CodeRepositoryByName(conn *sagemaker.SageMaker, name string) (*sagemaker.De
return output, nil
}

// ImageByName returns the code repository corresponding to the specified name.
// Returns nil if no code repository is found.
// ImageByName returns the Image corresponding to the specified name.
// Returns nil if no Image is found.
func ImageByName(conn *sagemaker.SageMaker, name string) (*sagemaker.DescribeImageOutput, error) {
input := &sagemaker.DescribeImageInput{
ImageName: aws.String(name),
Expand All @@ -43,6 +43,25 @@ func ImageByName(conn *sagemaker.SageMaker, name string) (*sagemaker.DescribeIma
return output, nil
}

// ImageVersionByName returns the Image Version corresponding to the specified name.
// Returns nil if no Image Version is found.
func ImageVersionByName(conn *sagemaker.SageMaker, name string) (*sagemaker.DescribeImageVersionOutput, error) {
input := &sagemaker.DescribeImageVersionInput{
ImageName: aws.String(name),
}

output, err := conn.DescribeImageVersion(input)
if err != nil {
return nil, err
}

if output == nil {
return nil, nil
}

return output, nil
}

// DomainByName returns the domain corresponding to the specified domain id.
// Returns nil if no domain is found.
func DomainByName(conn *sagemaker.SageMaker, domainID string) (*sagemaker.DescribeDomainOutput, error) {
Expand Down
31 changes: 31 additions & 0 deletions aws/internal/service/sagemaker/waiter/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ const (
SagemakerNotebookInstanceStatusNotFound = "NotFound"
SagemakerImageStatusNotFound = "NotFound"
SagemakerImageStatusFailed = "Failed"
SagemakerImageVersionStatusNotFound = "NotFound"
SagemakerImageVersionStatusFailed = "Failed"
SagemakerDomainStatusNotFound = "NotFound"
SagemakerFeatureGroupStatusNotFound = "NotFound"
SagemakerFeatureGroupStatusUnknown = "Unknown"
Expand Down Expand Up @@ -73,6 +75,35 @@ func ImageStatus(conn *sagemaker.SageMaker, name string) resource.StateRefreshFu
}
}

// ImageVersionStatus fetches the ImageVersion and its Status
func ImageVersionStatus(conn *sagemaker.SageMaker, name string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
input := &sagemaker.DescribeImageVersionInput{
ImageName: aws.String(name),
}

output, err := conn.DescribeImageVersion(input)

if tfawserr.ErrMessageContains(err, sagemaker.ErrCodeResourceNotFound, "No ImageVersion with the name") {
return nil, SagemakerImageVersionStatusNotFound, nil
}

if err != nil {
return nil, SagemakerImageVersionStatusFailed, err
}

if output == nil {
return nil, SagemakerImageVersionStatusNotFound, nil
}

if aws.StringValue(output.ImageVersionStatus) == sagemaker.ImageVersionStatusCreateFailed {
return output, sagemaker.ImageVersionStatusCreateFailed, fmt.Errorf("%s", aws.StringValue(output.FailureReason))
}

return output, aws.StringValue(output.ImageVersionStatus), nil
}
}

// DomainStatus fetches the Domain and its Status
func DomainStatus(conn *sagemaker.SageMaker, domainID string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
Expand Down
40 changes: 40 additions & 0 deletions aws/internal/service/sagemaker/waiter/waiter.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ const (
NotebookInstanceDeletedTimeout = 10 * time.Minute
ImageCreatedTimeout = 10 * time.Minute
ImageDeletedTimeout = 10 * time.Minute
ImageVersionCreatedTimeout = 10 * time.Minute
ImageVersionDeletedTimeout = 10 * time.Minute
DomainInServiceTimeout = 10 * time.Minute
DomainDeletedTimeout = 10 * time.Minute
FeatureGroupCreatedTimeout = 10 * time.Minute
Expand Down Expand Up @@ -122,6 +124,44 @@ func ImageDeleted(conn *sagemaker.SageMaker, name string) (*sagemaker.DescribeIm
return nil, err
}

// ImageVersionCreated waits for a ImageVersion to return Created
func ImageVersionCreated(conn *sagemaker.SageMaker, name string) (*sagemaker.DescribeImageVersionOutput, error) {
stateConf := &resource.StateChangeConf{
Pending: []string{
sagemaker.ImageVersionStatusCreating,
},
Target: []string{sagemaker.ImageVersionStatusCreated},
Refresh: ImageVersionStatus(conn, name),
Timeout: ImageVersionCreatedTimeout,
}

outputRaw, err := stateConf.WaitForState()

if output, ok := outputRaw.(*sagemaker.DescribeImageVersionOutput); ok {
return output, err
}

return nil, err
}

// ImageVersionDeleted waits for a ImageVersion to return Deleted
func ImageVersionDeleted(conn *sagemaker.SageMaker, name string) (*sagemaker.DescribeImageVersionOutput, error) {
stateConf := &resource.StateChangeConf{
Pending: []string{sagemaker.ImageVersionStatusDeleting},
Target: []string{},
Refresh: ImageVersionStatus(conn, name),
Timeout: ImageVersionDeletedTimeout,
}

outputRaw, err := stateConf.WaitForState()

if output, ok := outputRaw.(*sagemaker.DescribeImageVersionOutput); ok {
return output, err
}

return nil, err
}

// DomainInService waits for a Domain to return InService
func DomainInService(conn *sagemaker.SageMaker, domainID string) (*sagemaker.DescribeDomainOutput, error) {
stateConf := &resource.StateChangeConf{
Expand Down
1 change: 1 addition & 0 deletions aws/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -881,6 +881,7 @@ func Provider() *schema.Provider {
"aws_sagemaker_endpoint_configuration": resourceAwsSagemakerEndpointConfiguration(),
"aws_sagemaker_feature_group": resourceAwsSagemakerFeatureGroup(),
"aws_sagemaker_image": resourceAwsSagemakerImage(),
"aws_sagemaker_image_version": resourceAwsSagemakerImageVersion(),
"aws_sagemaker_model": resourceAwsSagemakerModel(),
"aws_sagemaker_notebook_instance_lifecycle_configuration": resourceAwsSagemakerNotebookInstanceLifeCycleConfiguration(),
"aws_sagemaker_notebook_instance": resourceAwsSagemakerNotebookInstance(),
Expand Down
2 changes: 1 addition & 1 deletion aws/resource_aws_sagemaker_image.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ func resourceAwsSagemakerImageRead(d *schema.ResourceData, meta interface{}) err

image, err := finder.ImageByName(conn, d.Id())
if err != nil {
if isAWSErr(err, sagemaker.ErrCodeResourceNotFound, "No Image with the name") {
if isAWSErr(err, sagemaker.ErrCodeResourceNotFound, "does not exist") {
d.SetId("")
log.Printf("[WARN] Unable to find SageMaker Image (%s); removing from state", d.Id())
return nil
Expand Down
124 changes: 124 additions & 0 deletions aws/resource_aws_sagemaker_image_version.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package aws

import (
"fmt"
"log"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/sagemaker"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/service/sagemaker/finder"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/service/sagemaker/waiter"
)

func resourceAwsSagemakerImageVersion() *schema.Resource {
return &schema.Resource{
Create: resourceAwsSagemakerImageVersionCreate,
Read: resourceAwsSagemakerImageVersionRead,
Delete: resourceAwsSagemakerImageVersionDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

Schema: map[string]*schema.Schema{
"arn": {
Type: schema.TypeString,
Computed: true,
},
"base_image": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"container_image": {
Type: schema.TypeString,
Computed: true,
},
"image_arn": {
Type: schema.TypeString,
Computed: true,
},
"image_name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"version": {
Type: schema.TypeInt,
Computed: true,
},
},
}
}

func resourceAwsSagemakerImageVersionCreate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).sagemakerconn

name := d.Get("image_name").(string)
input := &sagemaker.CreateImageVersionInput{
ImageName: aws.String(name),
BaseImage: aws.String(d.Get("base_image").(string)),
}

_, err := conn.CreateImageVersion(input)
if err != nil {
return fmt.Errorf("error creating Sagemaker Image Version %s: %w", name, err)
}

d.SetId(name)

if _, err := waiter.ImageVersionCreated(conn, d.Id()); err != nil {
return fmt.Errorf("error waiting for SageMaker Image Version (%s) to be created: %w", d.Id(), err)
}

return resourceAwsSagemakerImageVersionRead(d, meta)
}

func resourceAwsSagemakerImageVersionRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).sagemakerconn

image, err := finder.ImageVersionByName(conn, d.Id())
if err != nil {
if isAWSErr(err, sagemaker.ErrCodeResourceNotFound, "does not exist") {
d.SetId("")
log.Printf("[WARN] Unable to find Sagemaker Image Version (%s); removing from state", d.Id())
return nil
}
return fmt.Errorf("error reading Sagemaker Image Version (%s): %w", d.Id(), err)

}

d.Set("arn", image.ImageVersionArn)
d.Set("base_image", image.BaseImage)
d.Set("image_arn", image.ImageArn)
d.Set("container_image", image.ContainerImage)
d.Set("version", image.Version)
d.Set("image_name", d.Id())

return nil
}

func resourceAwsSagemakerImageVersionDelete(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).sagemakerconn

input := &sagemaker.DeleteImageVersionInput{
ImageName: aws.String(d.Id()),
Version: aws.Int64(int64(d.Get("version").(int))),
}

if _, err := conn.DeleteImageVersion(input); err != nil {
if isAWSErr(err, sagemaker.ErrCodeResourceNotFound, "does not exist") {
return nil
}
return fmt.Errorf("error deleting Sagemaker Image Version (%s): %w", d.Id(), err)
}

if _, err := waiter.ImageVersionDeleted(conn, d.Id()); err != nil {
if isAWSErr(err, sagemaker.ErrCodeResourceNotFound, "does not exist") {
return nil
}
return fmt.Errorf("error waiting for SageMaker Image Version (%s) to delete: %w", d.Id(), err)
}

return nil
}
Loading