From 1ffe176c63f3bd6930c0fc0a37eef51d1b695271 Mon Sep 17 00:00:00 2001 From: deepakbshetty Date: Sun, 21 Jul 2024 01:11:32 +0100 Subject: [PATCH 1/2] r/aws_sagemaker_domain: add studio_web_portal_settings and default_space_settings additional blocks --- .changelog/38457.txt | 7 + internal/service/sagemaker/domain.go | 259 +++++++++ internal/service/sagemaker/domain_test.go | 502 ++++++++++++++++++ internal/service/sagemaker/sagemaker_test.go | 6 + website/docs/r/sagemaker_domain.html.markdown | 10 + 5 files changed, 784 insertions(+) create mode 100644 .changelog/38457.txt diff --git a/.changelog/38457.txt b/.changelog/38457.txt new file mode 100644 index 00000000000..e9ebf40162b --- /dev/null +++ b/.changelog/38457.txt @@ -0,0 +1,7 @@ +```release-note:enhancement +resource/aws_sagemaker_domain: Add `default_user_settings.studio_web_portal_settings` block +resource/aws_sagemaker_domain: Add `default_space_settings.jupyter_lab_app_settings` block +resource/aws_sagemaker_domain: Add `default_space_settings.space_storage_settings` block +resource/aws_sagemaker_domain: Add `default_space_settings.custom_posix_user_config` block +resource/aws_sagemaker_domain: Add `default_space_settings.custom_file_system_config` block +``` \ No newline at end of file diff --git a/internal/service/sagemaker/domain.go b/internal/service/sagemaker/domain.go index 6b2658b18a2..a4a7b52d3b5 100644 --- a/internal/service/sagemaker/domain.go +++ b/internal/service/sagemaker/domain.go @@ -216,6 +216,162 @@ func resourceDomain() *schema.Resource { MaxItems: 5, Elem: &schema.Schema{Type: schema.TypeString}, }, + "jupyter_lab_app_settings": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "code_repository": { + Type: schema.TypeSet, + Optional: true, + MaxItems: 10, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "repository_url": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 1024), + }, + }, + }, + }, + "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, + }, + }, + }, + }, + "default_resource_spec": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + names.AttrInstanceType: { + Type: schema.TypeString, + Optional: true, + ValidateDiagFunc: enum.Validate[awstypes.AppInstanceType](), + }, + "lifecycle_config_arn": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: verify.ValidARN, + }, + "sagemaker_image_arn": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: verify.ValidARN, + }, + "sagemaker_image_version_alias": { + Type: schema.TypeString, + Optional: true, + }, + "sagemaker_image_version_arn": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: verify.ValidARN, + }, + }, + }, + }, + "lifecycle_config_arns": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: verify.ValidARN, + }, + }, + }, + }, + }, + "space_storage_settings": { + Type: schema.TypeList, + Optional: true, + Computed: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "default_ebs_storage_settings": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "default_ebs_volume_size_in_gb": { + Type: schema.TypeInt, + Required: true, + }, + "maximum_ebs_volume_size_in_gb": { + Type: schema.TypeInt, + Required: true, + }, + }, + }, + }, + }, + }, + }, + "custom_file_system_config": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "efs_file_system_config": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + names.AttrFileSystemID: { + Type: schema.TypeString, + Required: true, + }, + "file_system_path": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + }, + }, + }, + "custom_posix_user_config": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "gid": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IntAtLeast(1001), + }, + "uid": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IntAtLeast(10000), + }, + }, + }, + }, }, }, }, @@ -891,6 +1047,31 @@ func resourceDomain() *schema.Resource { }, }, }, + "studio_web_portal_settings": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "hidden_app_types": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateDiagFunc: enum.Validate[awstypes.AppType](), + }, + }, + "hidden_ml_tools": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateDiagFunc: enum.Validate[awstypes.MlTools](), + }, + }, + }, + }, + }, }, }, }, @@ -1379,6 +1560,10 @@ func expandUserSettings(l []interface{}) *awstypes.UserSettings { config.RStudioServerProAppSettings = expandRStudioServerProAppSettings(v) } + if v, ok := m["studio_web_portal_settings"].([]interface{}); ok && len(v) > 0 { + config.StudioWebPortalSettings = expandStudioWebPortalSettings(v) + } + return config } @@ -1839,6 +2024,26 @@ func expandDomainCustomImages(l []interface{}) []awstypes.CustomImage { return images } +func expandStudioWebPortalSettings(l []interface{}) *awstypes.StudioWebPortalSettings { + if len(l) == 0 || l[0] == nil { + return nil + } + + m := l[0].(map[string]interface{}) + + config := &awstypes.StudioWebPortalSettings{} + + if v, ok := m["hidden_app_types"].(*schema.Set); ok && v.Len() > 0 { + config.HiddenAppTypes = flex.ExpandStringyValueSet[awstypes.AppType](v) + } + + if v, ok := m["hidden_ml_tools"].(*schema.Set); ok && v.Len() > 0 { + config.HiddenMlTools = flex.ExpandStringyValueSet[awstypes.MlTools](v) + } + + return config +} + func flattenUserSettings(config *awstypes.UserSettings) []map[string]interface{} { if config == nil { return []map[string]interface{}{} @@ -1908,6 +2113,10 @@ func flattenUserSettings(config *awstypes.UserSettings) []map[string]interface{} m["r_studio_server_pro_app_settings"] = flattenRStudioServerProAppSettings(config.RStudioServerProAppSettings) } + if config.StudioWebPortalSettings != nil { + m["studio_web_portal_settings"] = flattenStudioWebPortalSettings(config.StudioWebPortalSettings) + } + return []map[string]interface{}{m} } @@ -2342,6 +2551,22 @@ func expanDefaultSpaceSettings(l []interface{}) *awstypes.DefaultSpaceSettings { config.SecurityGroups = flex.ExpandStringValueSet(v) } + if v, ok := m["jupyter_lab_app_settings"].([]interface{}); ok && len(v) > 0 { + config.JupyterLabAppSettings = expandDomainJupyterLabAppSettings(v) + } + + if v, ok := m["space_storage_settings"].([]interface{}); ok && len(v) > 0 { + config.SpaceStorageSettings = expandDefaultSpaceStorageSettings(v) + } + + if v, ok := m["custom_file_system_config"].([]interface{}); ok && len(v) > 0 { + config.CustomFileSystemConfigs = expandCustomFileSystemConfigs(v) + } + + if v, ok := m["custom_posix_user_config"].([]interface{}); ok && len(v) > 0 { + config.CustomPosixUserConfig = expandCustomPOSIXUserConfig(v) + } + return config } @@ -2368,6 +2593,22 @@ func flattenDefaultSpaceSettings(config *awstypes.DefaultSpaceSettings) []map[st m[names.AttrSecurityGroups] = flex.FlattenStringValueSet(config.SecurityGroups) } + if config.JupyterLabAppSettings != nil { + m["jupyter_lab_app_settings"] = flattenDomainJupyterLabAppSettings(config.JupyterLabAppSettings) + } + + if config.SpaceStorageSettings != nil { + m["space_storage_settings"] = flattenDefaultSpaceStorageSettings(config.SpaceStorageSettings) + } + + if config.CustomFileSystemConfigs != nil { + m["custom_file_system_config"] = flattenCustomFileSystemConfigs(config.CustomFileSystemConfigs) + } + + if config.CustomPosixUserConfig != nil { + m["custom_posix_user_config"] = flattenCustomPOSIXUserConfig(config.CustomPosixUserConfig) + } + return []map[string]interface{}{m} } @@ -2508,3 +2749,21 @@ func flattenEFSFileSystemConfig(apiObject awstypes.EFSFileSystemConfig) []map[st return []map[string]interface{}{tfMap} } + +func flattenStudioWebPortalSettings(config *awstypes.StudioWebPortalSettings) []map[string]interface{} { + if config == nil { + return []map[string]interface{}{} + } + + m := map[string]interface{}{} + + if config.HiddenAppTypes != nil { + m["hidden_app_types"] = flex.FlattenStringyValueSet[awstypes.AppType](config.HiddenAppTypes) + } + + if config.HiddenMlTools != nil { + m["hidden_ml_tools"] = flex.FlattenStringyValueSet[awstypes.MlTools](config.HiddenMlTools) + } + + return []map[string]interface{}{m} +} diff --git a/internal/service/sagemaker/domain_test.go b/internal/service/sagemaker/domain_test.go index a9a2bd4c4a7..baf0b63489a 100644 --- a/internal/service/sagemaker/domain_test.go +++ b/internal/service/sagemaker/domain_test.go @@ -1238,6 +1238,298 @@ func testAccDomain_efs(t *testing.T) { }) } +func testAccDomain_studioWebPortalSettings_hiddenAppTypes(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_studioWebPortalSettings_hiddenAppTypes(rName, []string{"JupyterServer", "KernelGateway"}), + Check: resource.ComposeTestCheckFunc( + testAccCheckDomainExists(ctx, resourceName, &domain), + resource.TestCheckResourceAttr(resourceName, "default_user_settings.#", acctest.Ct1), + resource.TestCheckResourceAttr(resourceName, "default_user_settings.0.studio_web_portal_settings.#", acctest.Ct1), + resource.TestCheckTypeSetElemAttr(resourceName, "default_user_settings.0.studio_web_portal_settings.0.hidden_app_types.*", "JupyterServer"), + resource.TestCheckTypeSetElemAttr(resourceName, "default_user_settings.0.studio_web_portal_settings.0.hidden_app_types.*", "KernelGateway"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"retention_policy"}, + }, + { + Config: testAccDomainConfig_studioWebPortalSettings_hiddenAppTypes(rName, []string{"JupyterServer", "KernelGateway", "CodeEditor"}), + Check: resource.ComposeTestCheckFunc( + testAccCheckDomainExists(ctx, resourceName, &domain), + resource.TestCheckResourceAttr(resourceName, "default_user_settings.#", acctest.Ct1), + resource.TestCheckResourceAttr(resourceName, "default_user_settings.0.studio_web_portal_settings.#", acctest.Ct1), + resource.TestCheckTypeSetElemAttr(resourceName, "default_user_settings.0.studio_web_portal_settings.0.hidden_app_types.*", "JupyterServer"), + resource.TestCheckTypeSetElemAttr(resourceName, "default_user_settings.0.studio_web_portal_settings.0.hidden_app_types.*", "KernelGateway"), + resource.TestCheckTypeSetElemAttr(resourceName, "default_user_settings.0.studio_web_portal_settings.0.hidden_app_types.*", "CodeEditor"), + ), + }, + }, + }) +} + +func testAccDomain_studioWebPortalSettings_hiddenMlTools(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_studioWebPortalSettings_hiddenMlTools(rName, []string{"DataWrangler", "FeatureStore"}), + Check: resource.ComposeTestCheckFunc( + testAccCheckDomainExists(ctx, resourceName, &domain), + resource.TestCheckResourceAttr(resourceName, "default_user_settings.#", acctest.Ct1), + resource.TestCheckResourceAttr(resourceName, "default_user_settings.0.studio_web_portal_settings.#", acctest.Ct1), + resource.TestCheckTypeSetElemAttr(resourceName, "default_user_settings.0.studio_web_portal_settings.0.hidden_ml_tools.*", "DataWrangler"), + resource.TestCheckTypeSetElemAttr(resourceName, "default_user_settings.0.studio_web_portal_settings.0.hidden_ml_tools.*", "FeatureStore"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"retention_policy"}, + }, + { + Config: testAccDomainConfig_studioWebPortalSettings_hiddenMlTools(rName, []string{"DataWrangler", "FeatureStore", "EmrClusters"}), + Check: resource.ComposeTestCheckFunc( + testAccCheckDomainExists(ctx, resourceName, &domain), + resource.TestCheckResourceAttr(resourceName, "default_user_settings.#", acctest.Ct1), + resource.TestCheckResourceAttr(resourceName, "default_user_settings.0.studio_web_portal_settings.#", acctest.Ct1), + resource.TestCheckTypeSetElemAttr(resourceName, "default_user_settings.0.studio_web_portal_settings.0.hidden_ml_tools.*", "DataWrangler"), + resource.TestCheckTypeSetElemAttr(resourceName, "default_user_settings.0.studio_web_portal_settings.0.hidden_ml_tools.*", "FeatureStore"), + resource.TestCheckTypeSetElemAttr(resourceName, "default_user_settings.0.studio_web_portal_settings.0.hidden_ml_tools.*", "EmrClusters"), + ), + }, + }, + }) +} + +func testAccDomain_spaceSettingsJupyterLabAppSettings(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_spaceSettingsJupyterLabAppSettings(rName, "ml.t3.micro", "ml.t3.small"), + Check: resource.ComposeTestCheckFunc( + testAccCheckDomainExists(ctx, resourceName, &domain), + resource.TestCheckResourceAttr(resourceName, "default_user_settings.#", acctest.Ct1), + resource.TestCheckResourceAttr(resourceName, "default_user_settings.0.jupyter_lab_app_settings.#", acctest.Ct1), + resource.TestCheckResourceAttr(resourceName, "default_user_settings.0.jupyter_lab_app_settings.0.default_resource_spec.#", acctest.Ct1), + resource.TestCheckResourceAttr(resourceName, "default_user_settings.0.jupyter_lab_app_settings.0.default_resource_spec.0.instance_type", "ml.t3.micro"), + resource.TestCheckResourceAttr(resourceName, "default_space_settings.#", acctest.Ct1), + resource.TestCheckResourceAttr(resourceName, "default_space_settings.0.jupyter_lab_app_settings.#", acctest.Ct1), + resource.TestCheckResourceAttr(resourceName, "default_space_settings.0.jupyter_lab_app_settings.0.default_resource_spec.#", acctest.Ct1), + resource.TestCheckResourceAttr(resourceName, "default_space_settings.0.jupyter_lab_app_settings.0.default_resource_spec.0.instance_type", "ml.t3.small"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"retention_policy"}, + }, + { + Config: testAccDomainConfig_spaceSettingsJupyterLabAppSettings(rName, "ml.t3.small", "ml.t3.micro"), + Check: resource.ComposeTestCheckFunc( + testAccCheckDomainExists(ctx, resourceName, &domain), + resource.TestCheckResourceAttr(resourceName, "default_user_settings.#", acctest.Ct1), + resource.TestCheckResourceAttr(resourceName, "default_user_settings.0.jupyter_lab_app_settings.#", acctest.Ct1), + resource.TestCheckResourceAttr(resourceName, "default_user_settings.0.jupyter_lab_app_settings.0.default_resource_spec.#", acctest.Ct1), + resource.TestCheckResourceAttr(resourceName, "default_user_settings.0.jupyter_lab_app_settings.0.default_resource_spec.0.instance_type", "ml.t3.small"), + resource.TestCheckResourceAttr(resourceName, "default_space_settings.#", acctest.Ct1), + resource.TestCheckResourceAttr(resourceName, "default_space_settings.0.jupyter_lab_app_settings.#", acctest.Ct1), + resource.TestCheckResourceAttr(resourceName, "default_space_settings.0.jupyter_lab_app_settings.0.default_resource_spec.#", acctest.Ct1), + resource.TestCheckResourceAttr(resourceName, "default_space_settings.0.jupyter_lab_app_settings.0.default_resource_spec.0.instance_type", "ml.t3.micro"), + ), + }, + }, + }) +} + +func testAccDomain_spaceSettingsSpaceStorageSettings(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_spaceSettingsSpaceStorageSettings(rName, "100", "200"), + Check: resource.ComposeTestCheckFunc( + testAccCheckDomainExists(ctx, resourceName, &domain), + resource.TestCheckResourceAttr(resourceName, names.AttrDomainName, rName), + resource.TestCheckResourceAttr(resourceName, "default_user_settings.#", acctest.Ct1), + resource.TestCheckResourceAttr(resourceName, "default_user_settings.0.space_storage_settings.#", acctest.Ct1), + resource.TestCheckResourceAttr(resourceName, "default_user_settings.0.space_storage_settings.0.default_ebs_storage_settings.#", acctest.Ct1), + resource.TestCheckResourceAttr(resourceName, "default_user_settings.0.space_storage_settings.0.default_ebs_storage_settings.0.default_ebs_volume_size_in_gb", acctest.Ct10), + resource.TestCheckResourceAttr(resourceName, "default_user_settings.0.space_storage_settings.0.default_ebs_storage_settings.0.maximum_ebs_volume_size_in_gb", "100"), + resource.TestCheckResourceAttr(resourceName, "default_space_settings.#", acctest.Ct1), + resource.TestCheckResourceAttr(resourceName, "default_space_settings.0.space_storage_settings.#", acctest.Ct1), + resource.TestCheckResourceAttr(resourceName, "default_space_settings.0.space_storage_settings.0.default_ebs_storage_settings.#", acctest.Ct1), + resource.TestCheckResourceAttr(resourceName, "default_space_settings.0.space_storage_settings.0.default_ebs_storage_settings.0.default_ebs_volume_size_in_gb", acctest.Ct10), + resource.TestCheckResourceAttr(resourceName, "default_space_settings.0.space_storage_settings.0.default_ebs_storage_settings.0.maximum_ebs_volume_size_in_gb", "200"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"retention_policy"}, + }, + { + Config: testAccDomainConfig_spaceSettingsSpaceStorageSettings(rName, "150", "250"), + Check: resource.ComposeTestCheckFunc( + testAccCheckDomainExists(ctx, resourceName, &domain), + resource.TestCheckResourceAttr(resourceName, names.AttrDomainName, rName), + resource.TestCheckResourceAttr(resourceName, "default_user_settings.#", acctest.Ct1), + resource.TestCheckResourceAttr(resourceName, "default_user_settings.0.space_storage_settings.#", acctest.Ct1), + resource.TestCheckResourceAttr(resourceName, "default_user_settings.0.space_storage_settings.0.default_ebs_storage_settings.#", acctest.Ct1), + resource.TestCheckResourceAttr(resourceName, "default_user_settings.0.space_storage_settings.0.default_ebs_storage_settings.0.default_ebs_volume_size_in_gb", acctest.Ct10), + resource.TestCheckResourceAttr(resourceName, "default_user_settings.0.space_storage_settings.0.default_ebs_storage_settings.0.maximum_ebs_volume_size_in_gb", "150"), + resource.TestCheckResourceAttr(resourceName, "default_space_settings.#", acctest.Ct1), + resource.TestCheckResourceAttr(resourceName, "default_space_settings.0.space_storage_settings.#", acctest.Ct1), + resource.TestCheckResourceAttr(resourceName, "default_space_settings.0.space_storage_settings.0.default_ebs_storage_settings.#", acctest.Ct1), + resource.TestCheckResourceAttr(resourceName, "default_space_settings.0.space_storage_settings.0.default_ebs_storage_settings.0.default_ebs_volume_size_in_gb", acctest.Ct10), + resource.TestCheckResourceAttr(resourceName, "default_space_settings.0.space_storage_settings.0.default_ebs_storage_settings.0.maximum_ebs_volume_size_in_gb", "250"), + ), + }, + }, + }) +} + +func testAccDomain_spaceSettingsCustomPOSIXUserConfig(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_spaceSettingsCustomPOSIXUserConfig(rName, "1001", "10000", "1002", "20000"), + Check: resource.ComposeTestCheckFunc( + testAccCheckDomainExists(ctx, resourceName, &domain), + resource.TestCheckResourceAttr(resourceName, names.AttrDomainName, rName), + resource.TestCheckResourceAttr(resourceName, "default_user_settings.0.custom_posix_user_config.#", acctest.Ct1), + resource.TestCheckResourceAttr(resourceName, "default_user_settings.0.custom_posix_user_config.0.gid", "1001"), + resource.TestCheckResourceAttr(resourceName, "default_user_settings.0.custom_posix_user_config.0.uid", "10000"), + resource.TestCheckResourceAttr(resourceName, "default_space_settings.0.custom_posix_user_config.#", acctest.Ct1), + resource.TestCheckResourceAttr(resourceName, "default_space_settings.0.custom_posix_user_config.0.gid", "1002"), + resource.TestCheckResourceAttr(resourceName, "default_space_settings.0.custom_posix_user_config.0.uid", "20000"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"retention_policy"}, + }, + { + Config: testAccDomainConfig_spaceSettingsCustomPOSIXUserConfig(rName, "2001", "20000", "2002", "40000"), + Check: resource.ComposeTestCheckFunc( + testAccCheckDomainExists(ctx, resourceName, &domain), + resource.TestCheckResourceAttr(resourceName, names.AttrDomainName, rName), + resource.TestCheckResourceAttr(resourceName, "default_user_settings.0.custom_posix_user_config.#", acctest.Ct1), + resource.TestCheckResourceAttr(resourceName, "default_user_settings.0.custom_posix_user_config.0.gid", "2001"), + resource.TestCheckResourceAttr(resourceName, "default_user_settings.0.custom_posix_user_config.0.uid", "20000"), + resource.TestCheckResourceAttr(resourceName, "default_space_settings.0.custom_posix_user_config.#", acctest.Ct1), + resource.TestCheckResourceAttr(resourceName, "default_space_settings.0.custom_posix_user_config.0.gid", "2002"), + resource.TestCheckResourceAttr(resourceName, "default_space_settings.0.custom_posix_user_config.0.uid", "40000"), + ), + }, + }, + }) +} + +func testAccDomain_spaceSettingsCustomFileSystemConfigs(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_spaceSettingsCustomFileSystemConfigs(rName, "test-1"), + Check: resource.ComposeTestCheckFunc( + testAccCheckDomainExists(ctx, resourceName, &domain), + resource.TestCheckResourceAttr(resourceName, names.AttrDomainName, rName), + resource.TestCheckResourceAttrPair(resourceName, "default_user_settings.0.execution_role", "aws_iam_role.test", names.AttrARN), + resource.TestCheckResourceAttr(resourceName, "default_user_settings.0.custom_file_system_config.#", acctest.Ct1), + resource.TestCheckResourceAttr(resourceName, "default_user_settings.0.custom_file_system_config.0.efs_file_system_config.#", acctest.Ct1), + resource.TestCheckResourceAttrPair(resourceName, "default_user_settings.0.custom_file_system_config.0.efs_file_system_config.0.file_system_id", "aws_efs_file_system.test", names.AttrID), + resource.TestCheckResourceAttrPair(resourceName, "default_space_settings.0.execution_role", "aws_iam_role.test", names.AttrARN), + resource.TestCheckResourceAttr(resourceName, "default_space_settings.0.custom_file_system_config.#", acctest.Ct1), + resource.TestCheckResourceAttr(resourceName, "default_space_settings.0.custom_file_system_config.0.efs_file_system_config.#", acctest.Ct1), + resource.TestCheckResourceAttrPair(resourceName, "default_space_settings.0.custom_file_system_config.0.efs_file_system_config.0.file_system_id", "aws_efs_file_system.test", names.AttrID), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"retention_policy"}, + }, + { + Config: testAccDomainConfig_spaceSettingsCustomFileSystemConfigs(rName, "test-2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckDomainExists(ctx, resourceName, &domain), + resource.TestCheckResourceAttr(resourceName, names.AttrDomainName, rName), + resource.TestCheckResourceAttrPair(resourceName, "default_user_settings.0.execution_role", "aws_iam_role.test", names.AttrARN), + resource.TestCheckResourceAttr(resourceName, "default_user_settings.0.custom_file_system_config.#", acctest.Ct1), + resource.TestCheckResourceAttr(resourceName, "default_user_settings.0.custom_file_system_config.0.efs_file_system_config.#", acctest.Ct1), + resource.TestCheckResourceAttrPair(resourceName, "default_user_settings.0.custom_file_system_config.0.efs_file_system_config.0.file_system_id", "aws_efs_file_system.test", names.AttrID), + resource.TestCheckResourceAttrPair(resourceName, "default_space_settings.0.execution_role", "aws_iam_role.test", names.AttrARN), + resource.TestCheckResourceAttr(resourceName, "default_space_settings.0.custom_file_system_config.#", acctest.Ct1), + resource.TestCheckResourceAttr(resourceName, "default_space_settings.0.custom_file_system_config.0.efs_file_system_config.#", acctest.Ct1), + resource.TestCheckResourceAttrPair(resourceName, "default_space_settings.0.custom_file_system_config.0.efs_file_system_config.0.file_system_id", "aws_efs_file_system.test", names.AttrID), + ), + }, + }, + }) +} + func testAccCheckDomainDestroy(ctx context.Context) resource.TestCheckFunc { return func(s *terraform.State) error { conn := acctest.Provider.Meta().(*conns.AWSClient).SageMakerClient(ctx) @@ -2382,3 +2674,213 @@ resource "aws_sagemaker_domain" "test" { } `, rName)) } + +func testAccDomainConfig_studioWebPortalSettings_hiddenAppTypes(rName string, hiddenAppTypes []string) string { + var hiddenAppTypesString string + for i, appType := range hiddenAppTypes { + if i > 0 { + hiddenAppTypesString += ", " + } + hiddenAppTypesString += fmt.Sprintf("%q", appType) + } + return acctest.ConfigCompose(testAccDomainConfig_base(rName), fmt.Sprintf(` +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 + + studio_web_portal_settings { + hidden_app_types = [%[2]s] + } + } + + retention_policy { + home_efs_file_system = "Delete" + } +} +`, rName, hiddenAppTypesString)) +} + +func testAccDomainConfig_studioWebPortalSettings_hiddenMlTools(rName string, hiddenMlTools []string) string { + var hiddenMlToolsString string + for i, mlTool := range hiddenMlTools { + if i > 0 { + hiddenMlToolsString += ", " + } + hiddenMlToolsString += fmt.Sprintf("%q", mlTool) + } + return acctest.ConfigCompose(testAccDomainConfig_base(rName), fmt.Sprintf(` +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 + + studio_web_portal_settings { + hidden_ml_tools = [%[2]s] + } + } + + retention_policy { + home_efs_file_system = "Delete" + } +} +`, rName, hiddenMlToolsString)) +} + +func testAccDomainConfig_spaceSettingsJupyterLabAppSettings(rName string, defaultUserSettingsinstanceType string, defaultSpaceSettingsinstanceType string) string { + return acctest.ConfigCompose(testAccDomainConfig_base(rName), fmt.Sprintf(` +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 + + jupyter_lab_app_settings { + default_resource_spec { + instance_type = %[2]q + } + } + } + + default_space_settings { + execution_role = aws_iam_role.test.arn + + jupyter_lab_app_settings { + default_resource_spec { + instance_type = %[3]q + } + } + } + + retention_policy { + home_efs_file_system = "Delete" + } +} +`, rName, defaultUserSettingsinstanceType, defaultSpaceSettingsinstanceType)) +} + +func testAccDomainConfig_spaceSettingsSpaceStorageSettings(rName string, defaultUserSettingsMaxEbsVolumeSize string, defaultSpaceSettingsMaxEbsVolumeSize string) string { + return acctest.ConfigCompose(testAccDomainConfig_base(rName), fmt.Sprintf(` +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 + space_storage_settings { + default_ebs_storage_settings { + default_ebs_volume_size_in_gb = 10 + maximum_ebs_volume_size_in_gb = %[2]q + } + } + } + + default_space_settings { + execution_role = aws_iam_role.test.arn + space_storage_settings { + default_ebs_storage_settings { + default_ebs_volume_size_in_gb = 10 + maximum_ebs_volume_size_in_gb = %[3]q + } + } + } + + retention_policy { + home_efs_file_system = "Delete" + } +} +`, rName, defaultUserSettingsMaxEbsVolumeSize, defaultSpaceSettingsMaxEbsVolumeSize)) +} + +func testAccDomainConfig_spaceSettingsCustomPOSIXUserConfig(rName string, defaultUserSettingsGid string, defaultUserSettingsUid string, defaultSpaceSettingsGid string, defaultSpaceSettingsUid string) string { + return acctest.ConfigCompose(testAccDomainConfig_base(rName), fmt.Sprintf(` +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 + custom_posix_user_config { + gid = %[2]q + uid = %[3]q + } + } + + default_space_settings { + execution_role = aws_iam_role.test.arn + custom_posix_user_config { + gid = %[4]q + uid = %[5]q + } + } + + retention_policy { + home_efs_file_system = "Delete" + } +} +`, rName, defaultUserSettingsGid, defaultUserSettingsUid, defaultSpaceSettingsGid, defaultSpaceSettingsUid)) +} + +func testAccDomainConfig_spaceSettingsCustomFileSystemConfigs(rName string, efsName string) string { + return acctest.ConfigCompose(testAccDomainConfig_base(rName), fmt.Sprintf(` +resource "aws_efs_file_system" "test" { + creation_token = %[2]q + tags = { + Name = %[2]q + } +} + +resource "aws_efs_mount_target" "test" { + file_system_id = aws_efs_file_system.test.id + subnet_id = aws_subnet.test[0].id +} + +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 + + custom_file_system_config { + efs_file_system_config { + file_system_id = aws_efs_mount_target.test.file_system_id + file_system_path = "/" + } + } + } + + default_space_settings { + execution_role = aws_iam_role.test.arn + + custom_file_system_config { + efs_file_system_config { + file_system_id = aws_efs_mount_target.test.file_system_id + file_system_path = "/" + } + } + } + + retention_policy { + home_efs_file_system = "Delete" + } +} +`, rName, efsName)) +} diff --git a/internal/service/sagemaker/sagemaker_test.go b/internal/service/sagemaker/sagemaker_test.go index 9550a5ccc6d..3b1666eab5b 100644 --- a/internal/service/sagemaker/sagemaker_test.go +++ b/internal/service/sagemaker/sagemaker_test.go @@ -70,10 +70,16 @@ func TestAccSageMaker_serial(t *testing.T) { "rStudioServerProAppSettings": testAccDomain_rStudioServerProAppSettings, "rStudioServerProDomainSettings": testAccDomain_rStudioServerProDomainSettings, "spaceSettingsKernelGatewayAppSettings": testAccDomain_spaceSettingsKernelGatewayAppSettings, + "spaceSettingsJupyterLabAppSettings": testAccDomain_spaceSettingsJupyterLabAppSettings, + "spaceSettingsSpaceStorageSettings": testAccDomain_spaceSettingsSpaceStorageSettings, + "spaceSettingsCustomPOSIXUserConfig": testAccDomain_spaceSettingsCustomPOSIXUserConfig, + "spaceSettingsCustomFileSystemConfigs": testAccDomain_spaceSettingsCustomFileSystemConfigs, "code": testAccDomain_jupyterServerAppSettings_code, "efs": testAccDomain_efs, "posix": testAccDomain_posix, "spaceStorageSettings": testAccDomain_spaceStorageSettings, + "studioWebPortalSettings_hiddenAppTypes": testAccDomain_studioWebPortalSettings_hiddenAppTypes, + "studioWebPortalSettings_hiddenMlTools": testAccDomain_studioWebPortalSettings_hiddenMlTools, }, "FlowDefinition": { acctest.CtBasic: testAccFlowDefinition_basic, diff --git a/website/docs/r/sagemaker_domain.html.markdown b/website/docs/r/sagemaker_domain.html.markdown index 2b94d3793a7..340ba04fb6b 100644 --- a/website/docs/r/sagemaker_domain.html.markdown +++ b/website/docs/r/sagemaker_domain.html.markdown @@ -112,6 +112,10 @@ The following arguments are optional: * `jupyter_server_app_settings` - (Optional) The Jupyter server's app settings. See [`jupyter_server_app_settings` Block](#jupyter_server_app_settings-block) below. * `kernel_gateway_app_settings` - (Optional) The kernel gateway app settings. See [`kernel_gateway_app_settings` Block](#kernel_gateway_app_settings-block) below. * `security_groups` - (Optional) The security groups for the Amazon Virtual Private Cloud that the space uses for communication. +* `jupyter_lab_app_settings` - (Optional) The settings for the JupyterLab application. See [`jupyter_lab_app_settings` Block](#jupyter_lab_app_settings-block) below. +* `space_storage_settings` - (Optional) The storage settings for a private space. See [`space_storage_settings` Block](#space_storage_settings-block) below. +* `custom_posix_user_config` - (Optional) Details about the POSIX identity that is used for file system operations. See [`custom_posix_user_config` Block](#custom_posix_user_config-block) below. +* `custom_file_system_config` - (Optional) The settings for assigning a custom file system to a user profile. Permitted users can access this file system in Amazon SageMaker Studio. See [`custom_file_system_config` Block](#custom_file_system_config-block) below. ### `default_user_settings` Block @@ -131,6 +135,7 @@ The following arguments are optional: * `space_storage_settings` - (Optional) The storage settings for a private space. See [`space_storage_settings` Block](#space_storage_settings-block) below. * `studio_web_portal` - (Optional) Whether the user can access Studio. If this value is set to `DISABLED`, the user cannot access Studio, even if that is the default experience for the domain. Valid values are `ENABLED` and `DISABLED`. * `tensor_board_app_settings` - (Optional) The TensorBoard app settings. See [`tensor_board_app_settings` Block](#tensor_board_app_settings-block) below. +* `studio_web_portal_settings` - (Optional) The Studio Web Portal settings. See [`studio_web_portal_settings` Block](#studio_web_portal_settings-block) below. #### `space_storage_settings` Block @@ -223,6 +228,11 @@ The following arguments are optional: * `lifecycle_config_arns` - (Optional) The Amazon Resource Name (ARN) of the Lifecycle Configurations. * `custom_image` - (Optional) A list of custom SageMaker images that are configured to run as a CodeEditor app. see [`custom_image` Block](#custom_image-block) below. +#### `studio_web_portal_settings` Block + +* `hidden_app_types` - (Optional) The Applications supported in Studio that are hidden from the Studio left navigation pane. +* `hidden_ml_tools` - (Optional) The machine learning tools that are hidden from the Studio left navigation pane. + ##### `code_repository` Block * `repository_url` - (Optional) The URL of the Git repository. From bd57cbbd51d0110079cf20b16793bea2e8462a01 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 9 Sep 2024 14:14:59 -0400 Subject: [PATCH 2/2] Tweak CHANGELOG entries. --- .changelog/38457.txt | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.changelog/38457.txt b/.changelog/38457.txt index e9ebf40162b..f8d7c4cfe13 100644 --- a/.changelog/38457.txt +++ b/.changelog/38457.txt @@ -1,7 +1,3 @@ ```release-note:enhancement -resource/aws_sagemaker_domain: Add `default_user_settings.studio_web_portal_settings` block -resource/aws_sagemaker_domain: Add `default_space_settings.jupyter_lab_app_settings` block -resource/aws_sagemaker_domain: Add `default_space_settings.space_storage_settings` block -resource/aws_sagemaker_domain: Add `default_space_settings.custom_posix_user_config` block -resource/aws_sagemaker_domain: Add `default_space_settings.custom_file_system_config` block +resource/aws_sagemaker_domain: Add `default_user_settings.studio_web_portal_settings`, `default_space_settings.jupyter_lab_app_settings`, `default_space_settings.space_storage_settings`, `default_space_settings.custom_posix_user_config`, and `default_space_settings.custom_file_system_config` configuration blocks ``` \ No newline at end of file