Skip to content

Commit

Permalink
Merge pull request hashicorp#37155 from michaeljneely/feature/37153
Browse files Browse the repository at this point in the history
Feature/37153: Add custom_image to code_editor_app_settings in Sagemaker user profile and domain
  • Loading branch information
ewbankkit authored Jun 21, 2024
2 parents ccfd07d + e1ddcfb commit 651c941
Show file tree
Hide file tree
Showing 12 changed files with 342 additions and 26 deletions.
8 changes: 8 additions & 0 deletions .changelog/37153.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

```release-note:enhancement
resource/aws_sagemaker_domain: Add `default_user_settings.code_editor_app_settings.custom_image` configuration block
```

```release-note:enhancement
resource/aws_sagemaker_user_profile: Add `user_settings.code_editor_app_settings.custom_image` configuration block
```
29 changes: 29 additions & 0 deletions internal/service/sagemaker/domain.go
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,27 @@ func ResourceDomain() *schema.Resource {
ValidateFunc: verify.ValidARN,
},
},
"custom_image": {
Type: schema.TypeList,
Optional: true,
MaxItems: 200,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"app_image_config_name": {
Type: schema.TypeString,
Required: true,
},
"image_name": {
Type: schema.TypeString,
Required: true,
},
"image_version_number": {
Type: schema.TypeInt,
Optional: true,
},
},
},
},
},
},
},
Expand Down Expand Up @@ -1373,6 +1394,10 @@ func expandDomainCodeEditorAppSettings(l []interface{}) *sagemaker.CodeEditorApp

config := &sagemaker.CodeEditorAppSettings{}

if v, ok := m["custom_image"].([]interface{}); ok && len(v) > 0 {
config.CustomImages = expandDomainCustomImages(v)
}

if v, ok := m["default_resource_spec"].([]interface{}); ok && len(v) > 0 {
config.DefaultResourceSpec = expandResourceSpec(v)
}
Expand Down Expand Up @@ -1949,6 +1974,10 @@ func flattenDomainCodeEditorAppSettings(config *sagemaker.CodeEditorAppSettings)

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

if config.CustomImages != nil {
m["custom_image"] = flattenDomainCustomImages(config.CustomImages)
}

if config.DefaultResourceSpec != nil {
m["default_resource_spec"] = flattenResourceSpec(config.DefaultResourceSpec)
}
Expand Down
168 changes: 168 additions & 0 deletions internal/service/sagemaker/domain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -654,6 +654,85 @@ func testAccDomain_codeEditorAppSettings(t *testing.T) {
})
}

func testAccDomain_codeEditorAppSettings_customImage(t *testing.T) {
ctx := acctest.Context(t)
if os.Getenv("SAGEMAKER_IMAGE_VERSION_BASE_IMAGE") == "" {
t.Skip("Environment variable SAGEMAKER_IMAGE_VERSION_BASE_IMAGE is not set")
}

var domain sagemaker.DescribeDomainOutput
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
resourceName := "aws_sagemaker_domain.test"
baseImage := os.Getenv("SAGEMAKER_IMAGE_VERSION_BASE_IMAGE")

resource.Test(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(ctx, t) },
ErrorCheck: acctest.ErrorCheck(t, names.SageMakerServiceID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckDomainDestroy(ctx),
Steps: []resource.TestStep{
{
Config: testAccDomainConfig_codeEditorAppSettingsCustomImage(rName, baseImage),
Check: resource.ComposeTestCheckFunc(
testAccCheckDomainExists(ctx, resourceName, &domain),
resource.TestCheckResourceAttr(resourceName, "default_user_settings.#", acctest.Ct1),
resource.TestCheckResourceAttr(resourceName, "default_user_settings.0.code_editor_app_settings.#", acctest.Ct1),
resource.TestCheckResourceAttr(resourceName, "default_user_settings.0.code_editor_app_settings.0.default_resource_spec.#", acctest.Ct0),
resource.TestCheckResourceAttr(resourceName, "default_user_settings.0.code_editor_app_settings.0.custom_image.#", acctest.Ct1),
resource.TestCheckResourceAttrPair(resourceName, "default_user_settings.0.code_editor_app_settings.0.custom_image.0.app_image_config_name", "aws_sagemaker_app_image_config.test", "app_image_config_name"),
resource.TestCheckResourceAttrPair(resourceName, "default_user_settings.0.code_editor_app_settings.0.custom_image.0.image_name", "aws_sagemaker_image.test", "image_name"),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"retention_policy"},
},
},
})
}

func testAccDomain_codeEditorAppSettings_defaultResourceSpecAndCustomImage(t *testing.T) {
ctx := acctest.Context(t)
if os.Getenv("SAGEMAKER_IMAGE_VERSION_BASE_IMAGE") == "" {
t.Skip("Environment variable SAGEMAKER_IMAGE_VERSION_BASE_IMAGE is not set")
}

var domain sagemaker.DescribeDomainOutput
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
resourceName := "aws_sagemaker_domain.test"
baseImage := os.Getenv("SAGEMAKER_IMAGE_VERSION_BASE_IMAGE")

resource.Test(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(ctx, t) },
ErrorCheck: acctest.ErrorCheck(t, names.SageMakerServiceID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckDomainDestroy(ctx),
Steps: []resource.TestStep{
{
Config: testAccDomainConfig_codeEditorAppSettingsDefaultResourceSpecAndCustomImage(rName, baseImage),
Check: resource.ComposeTestCheckFunc(
testAccCheckDomainExists(ctx, resourceName, &domain),
resource.TestCheckResourceAttr(resourceName, "default_user_settings.#", acctest.Ct1),
resource.TestCheckResourceAttr(resourceName, "default_user_settings.0.code_editor_app_settings.#", acctest.Ct1),
resource.TestCheckResourceAttr(resourceName, "default_user_settings.0.code_editor_app_settings.0.default_resource_spec.#", acctest.Ct1),
resource.TestCheckResourceAttr(resourceName, "default_user_settings.0.code_editor_app_settings.0.custom_image.#", acctest.Ct1),
resource.TestCheckResourceAttrPair(resourceName, "default_user_settings.0.code_editor_app_settings.0.default_resource_spec.0.sagemaker_image_version_arn", "aws_sagemaker_image_version.test", names.AttrARN),
resource.TestCheckResourceAttrPair(resourceName, "default_user_settings.0.code_editor_app_settings.0.custom_image.0.app_image_config_name", "aws_sagemaker_app_image_config.test", "app_image_config_name"),
resource.TestCheckResourceAttrPair(resourceName, "default_user_settings.0.code_editor_app_settings.0.custom_image.0.image_name", "aws_sagemaker_image.test", "image_name"),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"retention_policy"},
},
},
})
}

func testAccDomain_jupyterLabAppSettings(t *testing.T) {
ctx := acctest.Context(t)
var domain sagemaker.DescribeDomainOutput
Expand Down Expand Up @@ -1765,6 +1844,95 @@ resource "aws_sagemaker_domain" "test" {
`, rName))
}

func testAccDomainConfig_codeEditorAppSettingsCustomImage(rName, baseImage string) string {
return acctest.ConfigCompose(testAccDomainConfig_base(rName), fmt.Sprintf(`
resource "aws_sagemaker_image" "test" {
image_name = %[1]q
role_arn = aws_iam_role.test.arn
depends_on = [aws_iam_role_policy_attachment.test]
}
resource "aws_sagemaker_app_image_config" "test" {
app_image_config_name = %[1]q
}
resource "aws_sagemaker_image_version" "test" {
image_name = aws_sagemaker_image.test.id
base_image = %[2]q
}
resource "aws_sagemaker_domain" "test" {
domain_name = %[1]q
auth_mode = "IAM"
vpc_id = aws_vpc.test.id
subnet_ids = aws_subnet.test[*].id
default_user_settings {
execution_role = aws_iam_role.test.arn
code_editor_app_settings {
custom_image {
app_image_config_name = aws_sagemaker_app_image_config.test.app_image_config_name
image_name = aws_sagemaker_image_version.test.image_name
}
}
}
retention_policy {
home_efs_file_system = "Delete"
}
}
`, rName, baseImage))
}

func testAccDomainConfig_codeEditorAppSettingsDefaultResourceSpecAndCustomImage(rName, baseImage string) string {
return acctest.ConfigCompose(testAccDomainConfig_base(rName), fmt.Sprintf(`
resource "aws_sagemaker_image" "test" {
image_name = %[1]q
role_arn = aws_iam_role.test.arn
depends_on = [aws_iam_role_policy_attachment.test]
}
resource "aws_sagemaker_app_image_config" "test" {
app_image_config_name = %[1]q
}
resource "aws_sagemaker_image_version" "test" {
image_name = aws_sagemaker_image.test.id
base_image = %[2]q
}
resource "aws_sagemaker_domain" "test" {
domain_name = %[1]q
auth_mode = "IAM"
vpc_id = aws_vpc.test.id
subnet_ids = aws_subnet.test[*].id
default_user_settings {
execution_role = aws_iam_role.test.arn
code_editor_app_settings {
default_resource_spec {
instance_type = "ml.t3.micro"
sagemaker_image_version_arn = aws_sagemaker_image_version.test.arn
}
custom_image {
app_image_config_name = aws_sagemaker_app_image_config.test.app_image_config_name
image_name = aws_sagemaker_image_version.test.image_name
}
}
}
retention_policy {
home_efs_file_system = "Delete"
}
}
`, rName, baseImage))
}

func testAccDomainConfig_kernelGatewayAppSettings(rName string) string {
return acctest.ConfigCompose(testAccDomainConfig_base(rName), fmt.Sprintf(`
resource "aws_sagemaker_domain" "test" {
Expand Down
47 changes: 25 additions & 22 deletions internal/service/sagemaker/sagemaker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,28 +46,30 @@ func TestAccSageMaker_serial(t *testing.T) {
"kernelGatewayAppSettings": testAccDomain_kernelGatewayAppSettings,
"kernelGatewayAppSettings_customImage": testAccDomain_kernelGatewayAppSettings_customImage,
"kernelGatewayAppSettings_lifecycleConfig": testAccDomain_kernelGatewayAppSettings_lifecycleConfig,
"kernelGatewayAppSettings_defaultResourceAndCustomImage": testAccDomain_kernelGatewayAppSettings_defaultResourceSpecAndCustomImage,
"jupyterServerAppSettings": testAccDomain_jupyterServerAppSettings,
"codeEditorAppSettings": testAccDomain_codeEditorAppSettings,
"jupyterLabAppSettings": testAccDomain_jupyterLabAppSettings,
"kms": testAccDomain_kms,
"securityGroup": testAccDomain_securityGroup,
"sharingSettings": testAccDomain_sharingSettings,
"defaultUserSettingsUpdated": testAccDomain_defaultUserSettingsUpdated,
"canvas": testAccDomain_canvasAppSettings,
"modelRegisterSettings": testAccDomain_modelRegisterSettings,
"identityProviderOauthSettings": testAccDomain_identityProviderOAuthSettings,
"directDeploySettings": testAccDomain_directDeploySettings,
"kendraSettings": testAccDomain_kendraSettings,
"workspaceSettings": testAccDomain_workspaceSettings,
"domainSettings": testAccDomain_domainSettings,
"rSessionAppSettings": testAccDomain_rSessionAppSettings,
"rStudioServerProAppSettings": testAccDomain_rStudioServerProAppSettings,
"spaceSettingsKernelGatewayAppSettings": testAccDomain_spaceSettingsKernelGatewayAppSettings,
"code": testAccDomain_jupyterServerAppSettings_code,
"efs": testAccDomain_efs,
"posix": testAccDomain_posix,
"spaceStorageSettings": testAccDomain_spaceStorageSettings,
"kernelGatewayAppSettings_defaultResourceAndCustomImage": testAccDomain_kernelGatewayAppSettings_defaultResourceSpecAndCustomImage,
"jupyterServerAppSettings": testAccDomain_jupyterServerAppSettings,
"codeEditorAppSettings": testAccDomain_codeEditorAppSettings,
"codeEditorAppSettings_customImage": testAccDomain_codeEditorAppSettings_customImage,
"codeEditorAppSettings_defaultResourceSpecAndCustomImage": testAccDomain_codeEditorAppSettings_defaultResourceSpecAndCustomImage,
"jupyterLabAppSettings": testAccDomain_jupyterLabAppSettings,
"kms": testAccDomain_kms,
"securityGroup": testAccDomain_securityGroup,
"sharingSettings": testAccDomain_sharingSettings,
"defaultUserSettingsUpdated": testAccDomain_defaultUserSettingsUpdated,
"canvas": testAccDomain_canvasAppSettings,
"modelRegisterSettings": testAccDomain_modelRegisterSettings,
"identityProviderOauthSettings": testAccDomain_identityProviderOAuthSettings,
"directDeploySettings": testAccDomain_directDeploySettings,
"kendraSettings": testAccDomain_kendraSettings,
"workspaceSettings": testAccDomain_workspaceSettings,
"domainSettings": testAccDomain_domainSettings,
"rSessionAppSettings": testAccDomain_rSessionAppSettings,
"rStudioServerProAppSettings": testAccDomain_rStudioServerProAppSettings,
"spaceSettingsKernelGatewayAppSettings": testAccDomain_spaceSettingsKernelGatewayAppSettings,
"code": testAccDomain_jupyterServerAppSettings_code,
"efs": testAccDomain_efs,
"posix": testAccDomain_posix,
"spaceStorageSettings": testAccDomain_spaceStorageSettings,
},
"FlowDefinition": {
acctest.CtBasic: testAccFlowDefinition_basic,
Expand Down Expand Up @@ -98,6 +100,7 @@ func TestAccSageMaker_serial(t *testing.T) {
"kernelGatewayAppSettings": testAccUserProfile_kernelGatewayAppSettings,
"kernelGatewayAppSettings_lifecycleConfig": testAccUserProfile_kernelGatewayAppSettings_lifecycleconfig,
"kernelGatewayAppSettings_imageConfig": testAccUserProfile_kernelGatewayAppSettings_imageconfig,
"codeEditorAppSettings_customImage": testAccUserProfile_codeEditorAppSettings_customImage,
"jupyterServerAppSettings": testAccUserProfile_jupyterServerAppSettings,
},
"Workforce": {
Expand Down
21 changes: 21 additions & 0 deletions internal/service/sagemaker/user_profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,27 @@ func ResourceUserProfile() *schema.Resource {
ValidateFunc: verify.ValidARN,
},
},
"custom_image": {
Type: schema.TypeList,
Optional: true,
MaxItems: 200,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"app_image_config_name": {
Type: schema.TypeString,
Required: true,
},
"image_name": {
Type: schema.TypeString,
Required: true,
},
"image_version_number": {
Type: schema.TypeInt,
Optional: true,
},
},
},
},
},
},
},
Expand Down
Loading

0 comments on commit 651c941

Please sign in to comment.