From d4621a800114c8a2c5117806abd8b7d867500b7a Mon Sep 17 00:00:00 2001 From: deepakbshetty Date: Sat, 20 Jul 2024 19:03:49 +0100 Subject: [PATCH 1/2] sagemaker_domain add docker_settings & fix domain_settings update --- .changelog/35416.txt | 7 ++ internal/service/sagemaker/domain.go | 106 ++++++++++++++++++ internal/service/sagemaker/domain_test.go | 92 ++++++++++----- internal/service/sagemaker/sagemaker_test.go | 3 +- website/docs/r/sagemaker_domain.html.markdown | 6 + 5 files changed, 188 insertions(+), 26 deletions(-) create mode 100644 .changelog/35416.txt diff --git a/.changelog/35416.txt b/.changelog/35416.txt new file mode 100644 index 00000000000..cfc94d81cd3 --- /dev/null +++ b/.changelog/35416.txt @@ -0,0 +1,7 @@ +```release-note:enhancement +resource/aws_sagemaker_domain: Add `default_user_settings.domain_settings.docker_settings` block +``` + +```release-note:bug +resource/aws_sagemaker_domain: Fix update for `default_user_settings.domain_settings` to include missing `security_group_ids` and `r_studio_server_pro_domain_settings` block +``` diff --git a/internal/service/sagemaker/domain.go b/internal/service/sagemaker/domain.go index 6b2658b18a2..0e23cff9911 100644 --- a/internal/service/sagemaker/domain.go +++ b/internal/service/sagemaker/domain.go @@ -909,6 +909,29 @@ func resourceDomain() *schema.Resource { MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ + "docker_settings": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "enable_docker_access": { + Type: schema.TypeString, + Optional: true, + ValidateDiagFunc: enum.Validate[awstypes.FeatureStatus](), + }, + "vpc_only_trusted_accounts": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: verify.ValidAccountID, + }, + MaxItems: 20, + }, + }, + }, + }, "execution_role_identity_config": { Type: schema.TypeString, Optional: true, @@ -1231,6 +1254,10 @@ func expandDomainSettings(l []interface{}) *awstypes.DomainSettings { config := &awstypes.DomainSettings{} + if v, ok := m["docker_settings"].([]interface{}); ok && len(v) > 0 { + config.DockerSettings = expandDockerSettings(v) + } + if v, ok := m["execution_role_identity_config"].(string); ok && v != "" { config.ExecutionRoleIdentityConfig = awstypes.ExecutionRoleIdentityConfig(v) } @@ -1246,6 +1273,26 @@ func expandDomainSettings(l []interface{}) *awstypes.DomainSettings { return config } +func expandDockerSettings(l []interface{}) *awstypes.DockerSettings { + if len(l) == 0 || l[0] == nil { + return nil + } + + m := l[0].(map[string]interface{}) + + config := &awstypes.DockerSettings{} + + if v, ok := m["enable_docker_access"].(string); ok && v != "" { + config.EnableDockerAccess = awstypes.FeatureStatus(v) + } + + if v, ok := m["vpc_only_trusted_accounts"].(*schema.Set); ok && v.Len() > 0 { + config.VpcOnlyTrustedAccounts = flex.ExpandStringValueSet(v) + } + + return config +} + func expandRStudioServerProDomainSettings(l []interface{}) *awstypes.RStudioServerProDomainSettings { if len(l) == 0 || l[0] == nil { return nil @@ -1283,10 +1330,50 @@ func expandDomainSettingsUpdate(l []interface{}) *awstypes.DomainSettingsForUpda config := &awstypes.DomainSettingsForUpdate{} + if v, ok := m["docker_settings"].([]interface{}); ok && len(v) > 0 { + config.DockerSettings = expandDockerSettings(v) + } + if v, ok := m["execution_role_identity_config"].(string); ok && v != "" { config.ExecutionRoleIdentityConfig = awstypes.ExecutionRoleIdentityConfig(v) } + if v, ok := m[names.AttrSecurityGroupIDs].(*schema.Set); ok && v.Len() > 0 { + config.SecurityGroupIds = flex.ExpandStringValueSet(v) + } + + if v, ok := m["r_studio_server_pro_domain_settings"].([]interface{}); ok && len(v) > 0 { + config.RStudioServerProDomainSettingsForUpdate = expandRStudioServerProDomainSettingsUpdate(v) + } + + return config +} + +func expandRStudioServerProDomainSettingsUpdate(l []interface{}) *awstypes.RStudioServerProDomainSettingsForUpdate { + if len(l) == 0 || l[0] == nil { + return nil + } + + m := l[0].(map[string]interface{}) + + config := &awstypes.RStudioServerProDomainSettingsForUpdate{} + + if v, ok := m["default_resource_spec"].([]interface{}); ok && len(v) > 0 { + config.DefaultResourceSpec = expandResourceSpec(v) + } + + if v, ok := m["domain_execution_role_arn"].(string); ok && v != "" { + config.DomainExecutionRoleArn = aws.String(v) + } + + if v, ok := m["r_studio_connect_url"].(string); ok && v != "" { + config.RStudioConnectUrl = aws.String(v) + } + + if v, ok := m["r_studio_package_manager_url"].(string); ok && v != "" { + config.RStudioPackageManagerUrl = aws.String(v) + } + return config } @@ -2265,6 +2352,7 @@ func flattenDomainSettings(config *awstypes.DomainSettings) []map[string]interfa } m := map[string]interface{}{ + "docker_settings": flattenDockerSettings(config.DockerSettings), "execution_role_identity_config": config.ExecutionRoleIdentityConfig, "r_studio_server_pro_domain_settings": flattenRStudioServerProDomainSettings(config.RStudioServerProDomainSettings), names.AttrSecurityGroupIDs: flex.FlattenStringValueSet(config.SecurityGroupIds), @@ -2273,6 +2361,24 @@ func flattenDomainSettings(config *awstypes.DomainSettings) []map[string]interfa return []map[string]interface{}{m} } +func flattenDockerSettings(config *awstypes.DockerSettings) []map[string]interface{} { + if config == nil { + return []map[string]interface{}{} + } + + m := map[string]interface{}{} + + if config.EnableDockerAccess != "" { + m["enable_docker_access"] = config.EnableDockerAccess + } + + if config.VpcOnlyTrustedAccounts != nil { + m["vpc_only_trusted_accounts"] = flex.FlattenStringValueSet(config.VpcOnlyTrustedAccounts) + } + + return []map[string]interface{}{m} +} + func flattenRStudioServerProDomainSettings(config *awstypes.RStudioServerProDomainSettings) []map[string]interface{} { if config == nil { return []map[string]interface{}{} diff --git a/internal/service/sagemaker/domain_test.go b/internal/service/sagemaker/domain_test.go index a9a2bd4c4a7..d3b904ea635 100644 --- a/internal/service/sagemaker/domain_test.go +++ b/internal/service/sagemaker/domain_test.go @@ -100,6 +100,48 @@ func testAccDomain_domainSettings(t *testing.T) { }) } +func testAccDomain_domainSettingsDockerSettingsUpdated(t *testing.T) { + ctx := acctest.Context(t) + var domain sagemaker.DescribeDomainOutput + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_sagemaker_domain.test" + + 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_domainSettingsDockerSettings(rName, "DISABLED"), + Check: resource.ComposeTestCheckFunc( + testAccCheckDomainExists(ctx, resourceName, &domain), + resource.TestCheckResourceAttr(resourceName, "domain_settings.#", acctest.Ct1), + resource.TestCheckResourceAttr(resourceName, "domain_settings.0.docker_settings.#", acctest.Ct1), + resource.TestCheckResourceAttr(resourceName, "domain_settings.0.docker_settings.0.enable_docker_access", "DISABLED"), + resource.TestCheckResourceAttr(resourceName, "domain_settings.0.docker_settings.0.vpc_only_trusted_accounts.#", acctest.Ct1), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"retention_policy"}, + }, + { + Config: testAccDomainConfig_domainSettingsDockerSettings(rName, "ENABLED"), + Check: resource.ComposeTestCheckFunc( + testAccCheckDomainExists(ctx, resourceName, &domain), + resource.TestCheckResourceAttr(resourceName, "domain_settings.#", acctest.Ct1), + resource.TestCheckResourceAttr(resourceName, "domain_settings.0.docker_settings.#", acctest.Ct1), + resource.TestCheckResourceAttr(resourceName, "domain_settings.0.docker_settings.0.enable_docker_access", "ENABLED"), + resource.TestCheckResourceAttr(resourceName, "domain_settings.0.docker_settings.0.vpc_only_trusted_accounts.#", acctest.Ct1), + ), + }, + }, + }) +} + func testAccDomain_kms(t *testing.T) { ctx := acctest.Context(t) var domain sagemaker.DescribeDomainOutput @@ -176,7 +218,7 @@ func testAccDomain_tags(t *testing.T) { }) } -func testAccDomain_securityGroup(t *testing.T) { +func testAccDomain_defaultUserSettingsSecurityGroupUpdated(t *testing.T) { ctx := acctest.Context(t) var domain sagemaker.DescribeDomainOutput rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -189,7 +231,7 @@ func testAccDomain_securityGroup(t *testing.T) { CheckDestroy: testAccCheckDomainDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccDomainConfig_securityGroup1(rName), + Config: testAccDomainConfig_defaultUserSettingsSecurityGroupUpdated(rName, 1), Check: resource.ComposeTestCheckFunc( testAccCheckDomainExists(ctx, resourceName, &domain), resource.TestCheckResourceAttr(resourceName, "default_user_settings.#", acctest.Ct1), @@ -203,7 +245,7 @@ func testAccDomain_securityGroup(t *testing.T) { ImportStateVerifyIgnore: []string{"retention_policy"}, }, { - Config: testAccDomainConfig_securityGroup2(rName), + Config: testAccDomainConfig_defaultUserSettingsSecurityGroupUpdated(rName, 2), Check: resource.ComposeTestCheckFunc( testAccCheckDomainExists(ctx, resourceName, &domain), resource.TestCheckResourceAttr(resourceName, "default_user_settings.#", acctest.Ct1), @@ -1380,41 +1422,41 @@ resource "aws_sagemaker_domain" "test" { `, rName, config)) } -func testAccDomainConfig_kms(rName string) string { +func testAccDomainConfig_domainSettingsDockerSettings(rName, config string) string { return acctest.ConfigCompose(testAccDomainConfig_base(rName), fmt.Sprintf(` -resource "aws_kms_key" "test" { - description = %[1]q - deletion_window_in_days = 7 -} +data "aws_caller_identity" "current" {} resource "aws_sagemaker_domain" "test" { domain_name = %[1]q auth_mode = "IAM" vpc_id = aws_vpc.test.id subnet_ids = aws_subnet.test[*].id - kms_key_id = aws_kms_key.test.key_id default_user_settings { execution_role = aws_iam_role.test.arn } + app_network_access_type = "VpcOnly" + + domain_settings { + docker_settings { + enable_docker_access = %[2]q + vpc_only_trusted_accounts = [data.aws_caller_identity.current.account_id] + } + } + retention_policy { home_efs_file_system = "Delete" } } -`, rName)) +`, rName, config)) } -func testAccDomainConfig_securityGroup1(rName string) string { +func testAccDomainConfig_kms(rName string) string { return acctest.ConfigCompose(testAccDomainConfig_base(rName), fmt.Sprintf(` -resource "aws_security_group" "test" { - count = 1 - - name = "%[1]s-${count.index}" - - tags = { - Name = %[1]q - } +resource "aws_kms_key" "test" { + description = %[1]q + deletion_window_in_days = 7 } resource "aws_sagemaker_domain" "test" { @@ -1422,10 +1464,10 @@ resource "aws_sagemaker_domain" "test" { auth_mode = "IAM" vpc_id = aws_vpc.test.id subnet_ids = aws_subnet.test[*].id + kms_key_id = aws_kms_key.test.key_id default_user_settings { - execution_role = aws_iam_role.test.arn - security_groups = aws_security_group.test[*].id + execution_role = aws_iam_role.test.arn } retention_policy { @@ -1435,15 +1477,15 @@ resource "aws_sagemaker_domain" "test" { `, rName)) } -func testAccDomainConfig_securityGroup2(rName string) string { +func testAccDomainConfig_defaultUserSettingsSecurityGroupUpdated(rName string, sgCount int) string { return acctest.ConfigCompose(testAccDomainConfig_base(rName), fmt.Sprintf(` resource "aws_security_group" "test" { - count = 2 + count = %[2]d name = "%[1]s-${count.index}" tags = { - Name = %[1]q + Name = "%[1]s-${count.index}" } } @@ -1462,7 +1504,7 @@ resource "aws_sagemaker_domain" "test" { home_efs_file_system = "Delete" } } -`, rName)) +`, rName, sgCount)) } func testAccDomainConfig_tags1(rName, tagKey1, tagValue1 string) string { diff --git a/internal/service/sagemaker/sagemaker_test.go b/internal/service/sagemaker/sagemaker_test.go index 9550a5ccc6d..81ba315867d 100644 --- a/internal/service/sagemaker/sagemaker_test.go +++ b/internal/service/sagemaker/sagemaker_test.go @@ -55,7 +55,7 @@ func TestAccSageMaker_serial(t *testing.T) { "codeEditorAppSettings_defaultResourceSpecAndCustomImage": testAccDomain_codeEditorAppSettings_defaultResourceSpecAndCustomImage, "jupyterLabAppSettings": testAccDomain_jupyterLabAppSettings, "kms": testAccDomain_kms, - "securityGroup": testAccDomain_securityGroup, + "defaultUserSettingsSecurityGroupUpdated": testAccDomain_defaultUserSettingsSecurityGroupUpdated, "sharingSettings": testAccDomain_sharingSettings, "defaultUserSettingsUpdated": testAccDomain_defaultUserSettingsUpdated, "canvas": testAccDomain_canvasAppSettings, @@ -66,6 +66,7 @@ func TestAccSageMaker_serial(t *testing.T) { "kendraSettings": testAccDomain_kendraSettings, "workspaceSettings": testAccDomain_workspaceSettings, "domainSettings": testAccDomain_domainSettings, + "domainSettingsDockerSettingsUpdated": testAccDomain_domainSettingsDockerSettingsUpdated, "rSessionAppSettings": testAccDomain_rSessionAppSettings, "rStudioServerProAppSettings": testAccDomain_rStudioServerProAppSettings, "rStudioServerProDomainSettings": testAccDomain_rStudioServerProDomainSettings, diff --git a/website/docs/r/sagemaker_domain.html.markdown b/website/docs/r/sagemaker_domain.html.markdown index 2b94d3793a7..c1f6cde7f88 100644 --- a/website/docs/r/sagemaker_domain.html.markdown +++ b/website/docs/r/sagemaker_domain.html.markdown @@ -258,10 +258,16 @@ The following arguments are optional: ### `domain_settings` Block +* `docker_settings` - (Optional) A collection of settings that configure the domain’s Docker interaction. see [`docker_settings` Block](#docker_settings-block) below. * `execution_role_identity_config` - (Optional) The configuration for attaching a SageMaker user profile name to the execution role as a sts:SourceIdentity key [AWS Docs](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_control-access_monitor.html). Valid values are `USER_PROFILE_NAME` and `DISABLED`. * `r_studio_server_pro_domain_settings` - (Optional) A collection of settings that configure the RStudioServerPro Domain-level app. see [`r_studio_server_pro_domain_settings` Block](#r_studio_server_pro_domain_settings-block) below. * `security_group_ids` - (Optional) The security groups for the Amazon Virtual Private Cloud that the Domain uses for communication between Domain-level apps and user apps. +#### `docker_settings` Block + +* `enable_docker_access` - (Optional) Indicates whether the domain can access Docker. Valid values are `ENABLED` and `DISABLED`. +* `vpc_only_trusted_accounts` - (Optional) The list of Amazon Web Services accounts that are trusted when the domain is created in VPC-only mode. + #### `r_studio_server_pro_domain_settings` Block * `default_resource_spec` - (Optional) The default instance type and the Amazon Resource Name (ARN) of the SageMaker image created on the instance. see [`default_resource_spec` Block](#default_resource_spec-block) above. From 14f77a4111c7e2a598e8692c0494dbd83af97fd8 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 12 Sep 2024 12:29:17 -0400 Subject: [PATCH 2/2] Tweak CHANGELOG entries. --- .changelog/35416.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.changelog/35416.txt b/.changelog/35416.txt index cfc94d81cd3..850eedc1b37 100644 --- a/.changelog/35416.txt +++ b/.changelog/35416.txt @@ -1,7 +1,7 @@ ```release-note:enhancement -resource/aws_sagemaker_domain: Add `default_user_settings.domain_settings.docker_settings` block +resource/aws_sagemaker_domain: Add `default_user_settings.domain_settings.docker_settings` configuration block ``` ```release-note:bug -resource/aws_sagemaker_domain: Fix update for `default_user_settings.domain_settings` to include missing `security_group_ids` and `r_studio_server_pro_domain_settings` block +resource/aws_sagemaker_domain: Fix update for `default_user_settings.domain_settings` to include missing `security_group_ids` and `r_studio_server_pro_domain_settings` values ```