From 5ca3524f679ffe17fbafb1b7d12f0fbbde5e1497 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 28 Oct 2022 23:37:36 +0300 Subject: [PATCH 1/5] sagemaker domain add args --- internal/service/sagemaker/domain.go | 475 ++++++++++++++---- internal/service/sagemaker/domain_test.go | 173 +++++++ internal/service/sagemaker/sagemaker_test.go | 3 + internal/service/sagemaker/user_profile.go | 165 ++++-- website/docs/r/sagemaker_domain.html.markdown | 24 + 5 files changed, 713 insertions(+), 127 deletions(-) diff --git a/internal/service/sagemaker/domain.go b/internal/service/sagemaker/domain.go index 2bf6f4d731ef..fc834d8fcd56 100644 --- a/internal/service/sagemaker/domain.go +++ b/internal/service/sagemaker/domain.go @@ -29,49 +29,28 @@ func ResourceDomain() *schema.Resource { }, Schema: map[string]*schema.Schema{ - "arn": { - Type: schema.TypeString, - Computed: true, - }, - "domain_name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: validation.All( - validation.StringLenBetween(1, 63), - validation.StringMatch(regexp.MustCompile(`^[a-zA-Z0-9](-*[a-zA-Z0-9])*$`), "Valid characters are a-z, A-Z, 0-9, and - (hyphen)."), - ), - }, - "auth_mode": { + "app_network_access_type": { Type: schema.TypeString, ForceNew: true, - Required: true, - ValidateFunc: validation.StringInSlice(sagemaker.AuthMode_Values(), false), - }, - "vpc_id": { - Type: schema.TypeString, - ForceNew: true, - Required: true, - }, - "subnet_ids": { - Type: schema.TypeSet, - Required: true, - ForceNew: true, - MaxItems: 16, - Elem: &schema.Schema{Type: schema.TypeString}, + Optional: true, + Default: sagemaker.AppNetworkAccessTypePublicInternetOnly, + ValidateFunc: validation.StringInSlice(sagemaker.AppNetworkAccessType_Values(), false), }, - "kms_key_id": { + "app_security_group_management": { Type: schema.TypeString, ForceNew: true, Optional: true, - ValidateFunc: verify.ValidARN, + ValidateFunc: validation.StringInSlice(sagemaker.AppSecurityGroupManagement_Values(), false), }, - "app_network_access_type": { + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "auth_mode": { Type: schema.TypeString, ForceNew: true, - Optional: true, - Default: sagemaker.AppNetworkAccessTypePublicInternetOnly, - ValidateFunc: validation.StringInSlice(sagemaker.AppNetworkAccessType_Values(), false), + Required: true, + ValidateFunc: validation.StringInSlice(sagemaker.AuthMode_Values(), false), }, "default_user_settings": { Type: schema.TypeList, @@ -79,42 +58,40 @@ func ResourceDomain() *schema.Resource { MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "security_groups": { - Type: schema.TypeSet, - Optional: true, - MaxItems: 5, - Elem: &schema.Schema{Type: schema.TypeString}, - }, "execution_role": { Type: schema.TypeString, Required: true, ValidateFunc: verify.ValidARN, }, - "sharing_settings": { + "canvas_app_settings": { Type: schema.TypeList, Optional: true, MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "notebook_output_option": { - Type: schema.TypeString, - Optional: true, - Default: sagemaker.NotebookOutputOptionDisabled, - ValidateFunc: validation.StringInSlice(sagemaker.NotebookOutputOption_Values(), false), - }, - "s3_kms_key_id": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: verify.ValidARN, - }, - "s3_output_path": { - Type: schema.TypeString, + "time_series_forecasting_settings": { + Type: schema.TypeList, Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "amazon_forecast_role_arn": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: verify.ValidARN, + }, + "status": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice(sagemaker.FeatureStatus_Values(), false), + }, + }, + }, }, }, }, }, - "tensor_board_app_settings": { + "jupyter_server_app_settings": { Type: schema.TypeList, Optional: true, MaxItems: 1, @@ -149,10 +126,18 @@ func ResourceDomain() *schema.Resource { }, }, }, + "lifecycle_config_arns": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: verify.ValidARN, + }, + }, }, }, }, - "jupyter_server_app_settings": { + "kernel_gateway_app_settings": { Type: schema.TypeList, Optional: true, MaxItems: 1, @@ -195,10 +180,37 @@ func ResourceDomain() *schema.Resource { ValidateFunc: verify.ValidARN, }, }, + "custom_image": { + Type: schema.TypeList, + Optional: true, + MaxItems: 30, + 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, + }, + }, + }, + }, }, }, }, - "kernel_gateway_app_settings": { + "security_groups": { + Type: schema.TypeSet, + Optional: true, + MaxItems: 5, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "r_session_app_settings": { Type: schema.TypeList, Optional: true, MaxItems: 1, @@ -233,14 +245,6 @@ func ResourceDomain() *schema.Resource { }, }, }, - "lifecycle_config_arns": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Schema{ - Type: schema.TypeString, - ValidateFunc: verify.ValidARN, - }, - }, "custom_image": { Type: schema.TypeList, Optional: true, @@ -265,11 +269,111 @@ func ResourceDomain() *schema.Resource { }, }, }, + "sharing_settings": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "notebook_output_option": { + Type: schema.TypeString, + Optional: true, + Default: sagemaker.NotebookOutputOptionDisabled, + ValidateFunc: validation.StringInSlice(sagemaker.NotebookOutputOption_Values(), false), + }, + "s3_kms_key_id": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: verify.ValidARN, + }, + "s3_output_path": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "tensor_board_app_settings": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "default_resource_spec": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "instance_type": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice(sagemaker.AppInstanceType_Values(), false), + }, + "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_arn": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: verify.ValidARN, + }, + }, + }, + }, + }, + }, + }, }, }, }, - "tags": tftags.TagsSchema(), - "tags_all": tftags.TagsSchemaComputed(), + "domain_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 63), + validation.StringMatch(regexp.MustCompile(`^[a-zA-Z0-9](-*[a-zA-Z0-9])*$`), "Valid characters are a-z, A-Z, 0-9, and - (hyphen)."), + ), + }, + "domain_settings": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "execution_role_identity_config": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice(sagemaker.ExecutionRoleIdentityConfig_Values(), false), + }, + "security_group_ids": { + Type: schema.TypeSet, + Optional: true, + ForceNew: true, + MaxItems: 3, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + "home_efs_file_system_id": { + Type: schema.TypeString, + Computed: true, + }, + "kms_key_id": { + Type: schema.TypeString, + ForceNew: true, + Optional: true, + ValidateFunc: verify.ValidARN, + }, "retention_policy": { Type: schema.TypeList, Optional: true, @@ -286,7 +390,7 @@ func ResourceDomain() *schema.Resource { }, }, }, - "url": { + "security_group_id_for_domain_boundary": { Type: schema.TypeString, Computed: true, }, @@ -294,10 +398,24 @@ func ResourceDomain() *schema.Resource { Type: schema.TypeString, Computed: true, }, - "home_efs_file_system_id": { + "subnet_ids": { + Type: schema.TypeSet, + Required: true, + ForceNew: true, + MaxItems: 16, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "tags": tftags.TagsSchema(), + "tags_all": tftags.TagsSchemaComputed(), + "url": { Type: schema.TypeString, Computed: true, }, + "vpc_id": { + Type: schema.TypeString, + ForceNew: true, + Required: true, + }, }, CustomizeDiff: verify.SetTagsDiff, @@ -318,14 +436,22 @@ func resourceDomainCreate(d *schema.ResourceData, meta interface{}) error { DefaultUserSettings: expandDomainDefaultUserSettings(d.Get("default_user_settings").([]interface{})), } - if len(tags) > 0 { - input.Tags = Tags(tags.IgnoreAWS()) + if v, ok := d.GetOk("app_security_group_management"); ok { + input.AppSecurityGroupManagement = aws.String(v.(string)) + } + + if v, ok := d.GetOk("domain_settings"); ok && len(v.([]interface{})) > 0 { + input.DomainSettings = expandDomainSettings(v.([]interface{})) } if v, ok := d.GetOk("kms_key_id"); ok { input.KmsKeyId = aws.String(v.(string)) } + if len(tags) > 0 { + input.Tags = Tags(tags.IgnoreAWS()) + } + log.Printf("[DEBUG] sagemaker domain create config: %#v", *input) output, err := conn.CreateDomain(input) if err != nil { @@ -372,13 +498,19 @@ func resourceDomainRead(d *schema.ResourceData, meta interface{}) error { d.Set("url", domain.Url) d.Set("vpc_id", domain.VpcId) d.Set("kms_key_id", domain.KmsKeyId) + d.Set("app_security_group_management", domain.AppSecurityGroupManagement) + d.Set("security_group_id_for_domain_boundary", domain.SecurityGroupIdForDomainBoundary) if err := d.Set("subnet_ids", flex.FlattenStringSet(domain.SubnetIds)); err != nil { - return fmt.Errorf("setting subnet_ids for SageMaker domain (%s): %w", d.Id(), err) + return fmt.Errorf("setting subnet_ids for SageMaker Domain (%s): %w", d.Id(), err) } if err := d.Set("default_user_settings", flattenDomainDefaultUserSettings(domain.DefaultUserSettings)); err != nil { - return fmt.Errorf("setting default_user_settings for SageMaker domain (%s): %w", d.Id(), err) + return fmt.Errorf("setting default_user_settings for SageMaker Domain (%s): %w", d.Id(), err) + } + + if err := d.Set("domain_settings", flattenDomainSettings(domain.DomainSettings)); err != nil { + return fmt.Errorf("setting domain_settings for SageMaker Domain (%s): %w", d.Id(), err) } tags, err := ListTags(conn, arn) @@ -404,12 +536,16 @@ func resourceDomainRead(d *schema.ResourceData, meta interface{}) error { func resourceDomainUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*conns.AWSClient).SageMakerConn - if d.HasChange("default_user_settings") { + if d.HasChangesExcept("tags", "tags_all") { input := &sagemaker.UpdateDomainInput{ DomainId: aws.String(d.Id()), DefaultUserSettings: expandDomainDefaultUserSettings(d.Get("default_user_settings").([]interface{})), } + if v, ok := d.GetOk("domain_settings"); ok && len(v.([]interface{})) > 0 { + input.DomainSettingsForUpdate = expandDomainSettingsUpdate(v.([]interface{})) + } + log.Printf("[DEBUG] sagemaker domain update config: %#v", *input) _, err := conn.UpdateDomain(input) if err != nil { @@ -457,6 +593,43 @@ func resourceDomainDelete(d *schema.ResourceData, meta interface{}) error { return nil } + +func expandDomainSettings(l []interface{}) *sagemaker.DomainSettings { + if len(l) == 0 || l[0] == nil { + return nil + } + + m := l[0].(map[string]interface{}) + + config := &sagemaker.DomainSettings{} + + if v, ok := m["execution_role_identity_config"].(string); ok && v != "" { + config.ExecutionRoleIdentityConfig = aws.String(v) + } + + if v, ok := m["security_group_ids"].(*schema.Set); ok && v.Len() > 0 { + config.SecurityGroupIds = flex.ExpandStringSet(v) + } + + return config +} + +func expandDomainSettingsUpdate(l []interface{}) *sagemaker.DomainSettingsForUpdate { + if len(l) == 0 || l[0] == nil { + return nil + } + + m := l[0].(map[string]interface{}) + + config := &sagemaker.DomainSettingsForUpdate{} + + if v, ok := m["execution_role_identity_config"].(string); ok && v != "" { + config.ExecutionRoleIdentityConfig = aws.String(v) + } + + return config +} + func expandRetentionPolicy(l []interface{}) *sagemaker.RetentionPolicy { if len(l) == 0 || l[0] == nil { return nil @@ -482,30 +655,38 @@ func expandDomainDefaultUserSettings(l []interface{}) *sagemaker.UserSettings { config := &sagemaker.UserSettings{} - if v, ok := m["execution_role"].(string); ok && v != "" { - config.ExecutionRole = aws.String(v) + if v, ok := m["canvas_app_settings"].([]interface{}); ok && len(v) > 0 { + config.CanvasAppSettings = expandCanvasAppSettings(v) } - if v, ok := m["security_groups"].(*schema.Set); ok && v.Len() > 0 { - config.SecurityGroups = flex.ExpandStringSet(v) + if v, ok := m["execution_role"].(string); ok && v != "" { + config.ExecutionRole = aws.String(v) } - if v, ok := m["tensor_board_app_settings"].([]interface{}); ok && len(v) > 0 { - config.TensorBoardAppSettings = expandDomainTensorBoardAppSettings(v) + if v, ok := m["jupyter_server_app_settings"].([]interface{}); ok && len(v) > 0 { + config.JupyterServerAppSettings = expandDomainJupyterServerAppSettings(v) } if v, ok := m["kernel_gateway_app_settings"].([]interface{}); ok && len(v) > 0 { config.KernelGatewayAppSettings = expandDomainKernelGatewayAppSettings(v) } - if v, ok := m["jupyter_server_app_settings"].([]interface{}); ok && len(v) > 0 { - config.JupyterServerAppSettings = expandDomainJupyterServerAppSettings(v) + if v, ok := m["r_session_app_settings"].([]interface{}); ok && len(v) > 0 { + config.RSessionAppSettings = expandRSessionAppSettings(v) + } + + if v, ok := m["security_groups"].(*schema.Set); ok && v.Len() > 0 { + config.SecurityGroups = flex.ExpandStringSet(v) } if v, ok := m["sharing_settings"].([]interface{}); ok && len(v) > 0 { config.SharingSettings = expandDomainShareSettings(v) } + if v, ok := m["tensor_board_app_settings"].([]interface{}); ok && len(v) > 0 { + config.TensorBoardAppSettings = expandDomainTensorBoardAppSettings(v) + } + return config } @@ -553,6 +734,26 @@ func expandDomainKernelGatewayAppSettings(l []interface{}) *sagemaker.KernelGate return config } +func expandRSessionAppSettings(l []interface{}) *sagemaker.RSessionAppSettings { + if len(l) == 0 || l[0] == nil { + return nil + } + + m := l[0].(map[string]interface{}) + + config := &sagemaker.RSessionAppSettings{} + + if v, ok := m["default_resource_spec"].([]interface{}); ok && len(v) > 0 { + config.DefaultResourceSpec = expandDomainDefaultResourceSpec(v) + } + + if v, ok := m["custom_image"].([]interface{}); ok && len(v) > 0 { + config.CustomImages = expandDomainCustomImages(v) + } + + return config +} + func expandDomainTensorBoardAppSettings(l []interface{}) *sagemaker.TensorBoardAppSettings { if len(l) == 0 || l[0] == nil { return nil @@ -619,6 +820,40 @@ func expandDomainShareSettings(l []interface{}) *sagemaker.SharingSettings { return config } +func expandCanvasAppSettings(l []interface{}) *sagemaker.CanvasAppSettings { + if len(l) == 0 || l[0] == nil { + return nil + } + + m := l[0].(map[string]interface{}) + + config := &sagemaker.CanvasAppSettings{ + TimeSeriesForecastingSettings: expandTimeSeriesForecastingSettings(m["time_series_forecasting_settings"].([]interface{})), + } + + return config +} + +func expandTimeSeriesForecastingSettings(l []interface{}) *sagemaker.TimeSeriesForecastingSettings { + if len(l) == 0 || l[0] == nil { + return nil + } + + m := l[0].(map[string]interface{}) + + config := &sagemaker.TimeSeriesForecastingSettings{} + + if v, ok := m["amazon_forecast_role_arn"].(string); ok && v != "" { + config.AmazonForecastRoleArn = aws.String(v) + } + + if v, ok := m["status"].(string); ok && v != "" { + config.Status = aws.String(v) + } + + return config +} + func expandDomainCustomImages(l []interface{}) []*sagemaker.CustomImage { images := make([]*sagemaker.CustomImage, 0, len(l)) @@ -647,12 +882,12 @@ func flattenDomainDefaultUserSettings(config *sagemaker.UserSettings) []map[stri m := map[string]interface{}{} - if config.ExecutionRole != nil { - m["execution_role"] = aws.StringValue(config.ExecutionRole) + if config.CanvasAppSettings != nil { + m["canvas_app_settings"] = flattenCanvasAppSettings(config.CanvasAppSettings) } - if config.SecurityGroups != nil { - m["security_groups"] = flex.FlattenStringSet(config.SecurityGroups) + if config.ExecutionRole != nil { + m["execution_role"] = aws.StringValue(config.ExecutionRole) } if config.JupyterServerAppSettings != nil { @@ -663,14 +898,22 @@ func flattenDomainDefaultUserSettings(config *sagemaker.UserSettings) []map[stri m["kernel_gateway_app_settings"] = flattenDomainKernelGatewayAppSettings(config.KernelGatewayAppSettings) } - if config.TensorBoardAppSettings != nil { - m["tensor_board_app_settings"] = flattenDomainTensorBoardAppSettings(config.TensorBoardAppSettings) + if config.RSessionAppSettings != nil { + m["r_session_app_settings"] = flattenRSessionAppSettings(config.RSessionAppSettings) + } + + if config.SecurityGroups != nil { + m["security_groups"] = flex.FlattenStringSet(config.SecurityGroups) } if config.SharingSettings != nil { m["sharing_settings"] = flattenDomainShareSettings(config.SharingSettings) } + if config.TensorBoardAppSettings != nil { + m["tensor_board_app_settings"] = flattenDomainTensorBoardAppSettings(config.TensorBoardAppSettings) + } + return []map[string]interface{}{m} } @@ -754,6 +997,24 @@ func flattenDomainKernelGatewayAppSettings(config *sagemaker.KernelGatewayAppSet return []map[string]interface{}{m} } +func flattenRSessionAppSettings(config *sagemaker.RSessionAppSettings) []map[string]interface{} { + if config == nil { + return []map[string]interface{}{} + } + + m := map[string]interface{}{} + + if config.DefaultResourceSpec != nil { + m["default_resource_spec"] = flattenDomainDefaultResourceSpec(config.DefaultResourceSpec) + } + + if config.CustomImages != nil { + m["custom_image"] = flattenDomainCustomImages(config.CustomImages) + } + + return []map[string]interface{}{m} +} + func flattenDomainShareSettings(config *sagemaker.SharingSettings) []map[string]interface{} { if config == nil { return []map[string]interface{}{} @@ -774,6 +1035,44 @@ func flattenDomainShareSettings(config *sagemaker.SharingSettings) []map[string] return []map[string]interface{}{m} } +func flattenCanvasAppSettings(config *sagemaker.CanvasAppSettings) []map[string]interface{} { + if config == nil { + return []map[string]interface{}{} + } + + m := map[string]interface{}{ + "time_series_forecasting_settings": flattenTimeSeriesForecastingSettings(config.TimeSeriesForecastingSettings), + } + + return []map[string]interface{}{m} +} + +func flattenTimeSeriesForecastingSettings(config *sagemaker.TimeSeriesForecastingSettings) []map[string]interface{} { + if config == nil { + return []map[string]interface{}{} + } + + m := map[string]interface{}{ + "amazon_forecast_role_arn": aws.StringValue(config.AmazonForecastRoleArn), + "status": aws.StringValue(config.Status), + } + + return []map[string]interface{}{m} +} + +func flattenDomainSettings(config *sagemaker.DomainSettings) []map[string]interface{} { + if config == nil { + return []map[string]interface{}{} + } + + m := map[string]interface{}{ + "execution_role_identity_config": aws.StringValue(config.ExecutionRoleIdentityConfig), + "security_group_ids": flex.FlattenStringSet(config.SecurityGroupIds), + } + + return []map[string]interface{}{m} +} + func flattenDomainCustomImages(config []*sagemaker.CustomImage) []map[string]interface{} { images := make([]map[string]interface{}, 0, len(config)) diff --git a/internal/service/sagemaker/domain_test.go b/internal/service/sagemaker/domain_test.go index ce80efde12d5..4a9ef2dff2e8 100644 --- a/internal/service/sagemaker/domain_test.go +++ b/internal/service/sagemaker/domain_test.go @@ -43,6 +43,7 @@ func testAccDomain_basic(t *testing.T) { resource.TestCheckResourceAttrPair(resourceName, "vpc_id", "aws_vpc.test", "id"), resource.TestCheckResourceAttrSet(resourceName, "url"), resource.TestCheckResourceAttrSet(resourceName, "home_efs_file_system_id"), + resource.TestCheckResourceAttr(resourceName, "domain_settings.#", "0"), ), }, { @@ -55,6 +56,43 @@ func testAccDomain_basic(t *testing.T) { }) } +func testAccDomain_domainSettings(t *testing.T) { + var domain sagemaker.DescribeDomainOutput + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_sagemaker_domain.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, sagemaker.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckDomainDestroy, + Steps: []resource.TestStep{ + { + Config: testAccDomainConfig_domainSettings(rName, "DISABLED"), + Check: resource.ComposeTestCheckFunc( + testAccCheckDomainExists(resourceName, &domain), + resource.TestCheckResourceAttr(resourceName, "domain_settings.#", "1"), + resource.TestCheckResourceAttr(resourceName, "domain_settings.0.execution_role_identity_config", "DISABLED"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"retention_policy"}, + }, + { + Config: testAccDomainConfig_domainSettings(rName, "USER_PROFILE_NAME"), + Check: resource.ComposeTestCheckFunc( + testAccCheckDomainExists(resourceName, &domain), + resource.TestCheckResourceAttr(resourceName, "domain_settings.#", "1"), + resource.TestCheckResourceAttr(resourceName, "domain_settings.0.execution_role_identity_config", "USER_PROFILE_NAME"), + ), + }, + }, + }) +} + func testAccDomain_kms(t *testing.T) { var domain sagemaker.DescribeDomainOutput rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -198,6 +236,37 @@ func testAccDomain_sharingSettings(t *testing.T) { }) } +func testAccDomain_canvasAppSettings(t *testing.T) { + var domain sagemaker.DescribeDomainOutput + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_sagemaker_domain.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, sagemaker.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckDomainDestroy, + Steps: []resource.TestStep{ + { + Config: testAccDomainConfig_canvasAppSettings(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckDomainExists(resourceName, &domain), + resource.TestCheckResourceAttr(resourceName, "default_user_settings.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_user_settings.0.canvas_app_settings.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_user_settings.0.canvas_app_settings.0.time_series_forecasting_settings.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_user_settings.0.canvas_app_settings.0.time_series_forecasting_settings.0.status", "DISABLED"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"retention_policy"}, + }, + }, + }) +} + func testAccDomain_tensorboardAppSettings(t *testing.T) { var domain sagemaker.DescribeDomainOutput rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -261,6 +330,37 @@ func testAccDomain_tensorboardAppSettingsWithImage(t *testing.T) { }) } +func testAccDomain_rSessionAppSettings(t *testing.T) { + var domain sagemaker.DescribeDomainOutput + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_sagemaker_domain.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, sagemaker.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckDomainDestroy, + Steps: []resource.TestStep{ + { + Config: testAccDomainConfig_rSessionAppSettings(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckDomainExists(resourceName, &domain), + resource.TestCheckResourceAttr(resourceName, "default_user_settings.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_user_settings.0.r_session_app_settings.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_user_settings.0.r_session_app_settings.0.default_resource_spec.#", "1"), + resource.TestCheckResourceAttr(resourceName, "default_user_settings.0.r_session_app_settings.0.default_resource_spec.0.instance_type", "ml.t3.micro"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"retention_policy"}, + }, + }, + }) +} + func testAccDomain_kernelGatewayAppSettings(t *testing.T) { var domain sagemaker.DescribeDomainOutput rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -630,6 +730,29 @@ resource "aws_sagemaker_domain" "test" { `, rName) } +func testAccDomainConfig_domainSettings(rName, config string) string { + return testAccDomainBaseConfig(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 + } + + domain_settings { + execution_role_identity_config = %[2]q + } + + retention_policy { + home_efs_file_system = "Delete" + } +} +`, rName, config) +} + func testAccDomainConfig_kms(rName string) string { return testAccDomainBaseConfig(rName) + fmt.Sprintf(` resource "aws_kms_key" "test" { @@ -790,6 +913,31 @@ resource "aws_sagemaker_domain" "test" { `, rName) } +func testAccDomainConfig_canvasAppSettings(rName string) string { + return testAccDomainBaseConfig(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 + + canvas_app_settings { + time_series_forecasting_settings { + status = "DISABLED" + } + } + } + + retention_policy { + home_efs_file_system = "Delete" + } +} +`, rName) +} + func testAccDomainConfig_tensorBoardAppSettings(rName string) string { return testAccDomainBaseConfig(rName) + fmt.Sprintf(` resource "aws_sagemaker_domain" "test" { @@ -871,6 +1019,31 @@ resource "aws_sagemaker_domain" "test" { `, rName) } +func testAccDomainConfig_rSessionAppSettings(rName string) string { + return testAccDomainBaseConfig(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 + + r_session_app_settings { + default_resource_spec { + instance_type = "ml.t3.micro" + } + } + } + + retention_policy { + home_efs_file_system = "Delete" + } +} +`, rName) +} + func testAccDomainConfig_kernelGatewayAppSettings(rName string) string { return testAccDomainBaseConfig(rName) + fmt.Sprintf(` resource "aws_sagemaker_domain" "test" { diff --git a/internal/service/sagemaker/sagemaker_test.go b/internal/service/sagemaker/sagemaker_test.go index 442aab59f3d2..22e3ad660c30 100644 --- a/internal/service/sagemaker/sagemaker_test.go +++ b/internal/service/sagemaker/sagemaker_test.go @@ -46,6 +46,9 @@ func TestAccSageMaker_serial(t *testing.T) { "securityGroup": testAccDomain_securityGroup, "sharingSettings": testAccDomain_sharingSettings, "defaultUserSettingsUpdated": testAccDomain_defaultUserSettingsUpdated, + "canvas": testAccDomain_canvasAppSettings, + "domainSettings": testAccDomain_domainSettings, + "rSessionAppSettings": testAccDomain_rSessionAppSettings, }, "FlowDefinition": { "basic": testAccFlowDefinition_basic, diff --git a/internal/service/sagemaker/user_profile.go b/internal/service/sagemaker/user_profile.go index 5c0f184b40bd..b1c6072591fe 100644 --- a/internal/service/sagemaker/user_profile.go +++ b/internal/service/sagemaker/user_profile.go @@ -62,43 +62,40 @@ func ResourceUserProfile() *schema.Resource { MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "security_groups": { - Type: schema.TypeSet, - Optional: true, - MaxItems: 5, - Elem: &schema.Schema{Type: schema.TypeString}, - }, - "execution_role": { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, - }, - "sharing_settings": { + "canvas_app_settings": { Type: schema.TypeList, Optional: true, - ForceNew: true, MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "notebook_output_option": { - Type: schema.TypeString, - Optional: true, - Default: sagemaker.NotebookOutputOptionDisabled, - ValidateFunc: validation.StringInSlice(sagemaker.NotebookOutputOption_Values(), false), - }, - "s3_kms_key_id": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: verify.ValidARN, - }, - "s3_output_path": { - Type: schema.TypeString, + "time_series_forecasting_settings": { + Type: schema.TypeList, Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "amazon_forecast_role_arn": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: verify.ValidARN, + }, + "status": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice(sagemaker.FeatureStatus_Values(), false), + }, + }, + }, }, }, }, }, - "tensor_board_app_settings": { + "execution_role": { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, + "jupyter_server_app_settings": { Type: schema.TypeList, Optional: true, ForceNew: true, @@ -134,10 +131,18 @@ func ResourceUserProfile() *schema.Resource { }, }, }, + "lifecycle_config_arns": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: verify.ValidARN, + }, + }, }, }, }, - "jupyter_server_app_settings": { + "kernel_gateway_app_settings": { Type: schema.TypeList, Optional: true, ForceNew: true, @@ -181,19 +186,39 @@ func ResourceUserProfile() *schema.Resource { ValidateFunc: verify.ValidARN, }, }, + "custom_image": { + Type: schema.TypeList, + Optional: true, + MaxItems: 30, + 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, + }, + }, + }, + }, }, }, }, - "kernel_gateway_app_settings": { + "r_session_app_settings": { Type: schema.TypeList, Optional: true, - ForceNew: true, MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "default_resource_spec": { Type: schema.TypeList, - Required: true, + Optional: true, MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ @@ -220,14 +245,6 @@ func ResourceUserProfile() *schema.Resource { }, }, }, - "lifecycle_config_arns": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Schema{ - Type: schema.TypeString, - ValidateFunc: verify.ValidARN, - }, - }, "custom_image": { Type: schema.TypeList, Optional: true, @@ -252,6 +269,76 @@ func ResourceUserProfile() *schema.Resource { }, }, }, + "security_groups": { + Type: schema.TypeSet, + Optional: true, + MaxItems: 5, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "sharing_settings": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "notebook_output_option": { + Type: schema.TypeString, + Optional: true, + Default: sagemaker.NotebookOutputOptionDisabled, + ValidateFunc: validation.StringInSlice(sagemaker.NotebookOutputOption_Values(), false), + }, + "s3_kms_key_id": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: verify.ValidARN, + }, + "s3_output_path": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "tensor_board_app_settings": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "default_resource_spec": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "instance_type": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice(sagemaker.AppInstanceType_Values(), false), + }, + "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_arn": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: verify.ValidARN, + }, + }, + }, + }, + }, + }, + }, }, }, }, diff --git a/website/docs/r/sagemaker_domain.html.markdown b/website/docs/r/sagemaker_domain.html.markdown index c788b8fc1551..bbcbb9058246 100644 --- a/website/docs/r/sagemaker_domain.html.markdown +++ b/website/docs/r/sagemaker_domain.html.markdown @@ -95,9 +95,11 @@ The following arguments are supported: * `vpc_id` - (Required) The ID of the Amazon Virtual Private Cloud (VPC) that Studio uses for communication. * `subnet_ids` - (Required) The VPC subnets that Studio uses for communication. * `default_user_settings` - (Required) The default user settings. See [Default User Settings](#default-user-settings) below. +* `domain_settings` - (Optional) The domain settings. See [Domain Settings](#domain-settings) below. * `retention_policy` - (Optional) The retention policy for this domain, which specifies whether resources will be retained after the Domain is deleted. By default, all resources are retained. See [Retention Policy](#retention-policy) below. * `kms_key_id` - (Optional) The AWS KMS customer managed CMK used to encrypt the EFS volume attached to the domain. * `app_network_access_type` - (Optional) Specifies the VPC used for non-EFS traffic. The default value is `PublicInternetOnly`. Valid values are `PublicInternetOnly` and `VpcOnly`. +* `app_security_group_management` - (Optional) The entity that creates and manages the required security groups for inter-app communication in `VPCOnly` mode. Valid values are `Service` and `Customer`. * `tags` - (Optional) A map of tags to assign to the resource. If configured with a provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. ### Default User Settings @@ -105,9 +107,16 @@ The following arguments are supported: * `execution_role` - (Required) The execution role ARN for the user. * `security_groups` - (Optional) A list of security group IDs that will be attached to the user. * `sharing_settings` - (Optional) The sharing settings. See [Sharing Settings](#sharing-settings) below. +* `canvas_app_settings` - (Optional) The Canvas app settings. See [Canvas App Settings](#canvas-app-settings) below. * `tensor_board_app_settings` - (Optional) The TensorBoard app settings. See [TensorBoard App Settings](#tensorboard-app-settings) below. * `jupyter_server_app_settings` - (Optional) The Jupyter server's app settings. See [Jupyter Server App Settings](#jupyter-server-app-settings) below. * `kernel_gateway_app_settings` - (Optional) The kernel gateway app settings. See [Kernel Gateway App Settings](#kernel-gateway-app-settings) below. +* `r_session_app_settings` - (Optional) The RSession app settings. See [RSession App Settings](#rsession-app-settings) below. + +### Domain Settings + +* `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`. +* `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. #### Sharing Settings @@ -115,6 +124,10 @@ The following arguments are supported: * `s3_kms_key_id` - (Optional) When `notebook_output_option` is Allowed, the AWS Key Management Service (KMS) encryption key ID used to encrypt the notebook cell output in the Amazon S3 bucket. * `s3_output_path` - (Optional) When `notebook_output_option` is Allowed, the Amazon S3 bucket used to save the notebook cell output. +#### Canvas App Settings + +* `time_series_forecasting_settings` - (Optional) Time series forecast settings for the Canvas app. see [Time Series Forecasting Settings](#time-series-forecasting-settings) below. + #### TensorBoard App Settings * `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](#default-resource-spec) below. @@ -130,6 +143,11 @@ The following arguments are supported: * `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](#default-resource-spec) below. * `lifecycle_config_arns` - (Optional) The Amazon Resource Name (ARN) of the Lifecycle Configurations. +#### RSession App Settings + +* `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](#default-resource-spec) below. +* `custom_image` - (Optional) A list of custom SageMaker images that are configured to run as a KernelGateway app. see [Custom Image](#custom-image) below. + ##### Default Resource Spec * `instance_type` - (Optional) The instance type that the image version runs on.. For valid values see [SageMaker Instance Types](https://docs.aws.amazon.com/sagemaker/latest/dg/notebooks-available-instance-types.html). @@ -137,6 +155,11 @@ The following arguments are supported: * `sagemaker_image_arn` - (Optional) The ARN of the SageMaker image that the image version belongs to. * `sagemaker_image_version_arn` - (Optional) The ARN of the image version created on the instance. +##### Time Series Forecasting Settings + +* `amazon_forecast_role_arn` - (Optional) The IAM role that Canvas passes to Amazon Forecast for time series forecasting. By default, Canvas uses the execution role specified in the UserProfile that launches the Canvas app. If an execution role is not specified in the UserProfile, Canvas uses the execution role specified in the Domain that owns the UserProfile. To allow time series forecasting, this IAM role should have the [AmazonSageMakerCanvasForecastAccess](https://docs.aws.amazon.com/sagemaker/latest/dg/security-iam-awsmanpol-canvas.html#security-iam-awsmanpol-AmazonSageMakerCanvasForecastAccess) policy attached and forecast.amazonaws.com added in the trust relationship as a service principal. +* `status` - (Optional) Describes whether time series forecasting is enabled or disabled in the Canvas app. Valid values are `ENABLED` and `DISABLED`. + ##### Custom Image * `app_image_config_name` - (Required) The name of the App Image Config. @@ -155,6 +178,7 @@ In addition to all arguments above, the following attributes are exported: * `arn` - The Amazon Resource Name (ARN) assigned by AWS to this Domain. * `url` - The domain's URL. * `single_sign_on_managed_application_instance_id` - The SSO managed application instance ID. +* `security_group_id_for_domain_boundary` - The ID of the security group that authorizes traffic between the RSessionGateway apps and the RStudioServerPro app. * `home_efs_file_system_id` - The ID of the Amazon Elastic File System (EFS) managed by this Domain. * `tags_all` - A map of tags assigned to the resource, including those inherited from the provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block). From a55327ba0259a3618e01ef8ac57baa13ce010a8c Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 28 Oct 2022 23:40:10 +0300 Subject: [PATCH 2/5] changelog --- .changelog/27542.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/27542.txt diff --git a/.changelog/27542.txt b/.changelog/27542.txt new file mode 100644 index 000000000000..7b6836f1e0b6 --- /dev/null +++ b/.changelog/27542.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_sagemaker_domain: Add `domain_settings`, `app_security_group_management`, `default_user_settings.r_session_app_settings`, and `default_user_settings.canvas_app_settings` arguments. +``` \ No newline at end of file From e7247da0ef5f9b4d3d760b4da1b1284972851210 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Fri, 28 Oct 2022 23:42:27 +0300 Subject: [PATCH 3/5] user profile --- .changelog/27542.txt | 4 ++++ .../docs/r/sagemaker_user_profile.html.markdown | 17 +++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/.changelog/27542.txt b/.changelog/27542.txt index 7b6836f1e0b6..ce7e25874a7c 100644 --- a/.changelog/27542.txt +++ b/.changelog/27542.txt @@ -1,3 +1,7 @@ ```release-note:enhancement resource/aws_sagemaker_domain: Add `domain_settings`, `app_security_group_management`, `default_user_settings.r_session_app_settings`, and `default_user_settings.canvas_app_settings` arguments. +``` + +```release-note:enhancement +resource/aws_sagemaker_user_profile: Add `user_settings.r_session_app_settings` and `user_settings.canvas_app_settings` arguments. ``` \ No newline at end of file diff --git a/website/docs/r/sagemaker_user_profile.html.markdown b/website/docs/r/sagemaker_user_profile.html.markdown index 9e45f5432775..4fa1ed17406b 100644 --- a/website/docs/r/sagemaker_user_profile.html.markdown +++ b/website/docs/r/sagemaker_user_profile.html.markdown @@ -40,6 +40,13 @@ The following arguments are supported: * `tensor_board_app_settings` - (Optional) The TensorBoard app settings. See [TensorBoard App Settings](#tensorboard-app-settings) below. * `jupyter_server_app_settings` - (Optional) The Jupyter server's app settings. See [Jupyter Server App Settings](#jupyter-server-app-settings) below. * `kernel_gateway_app_settings` - (Optional) The kernel gateway app settings. See [Kernel Gateway App Settings](#kernel-gateway-app-settings) below. +* `kernel_gateway_app_settings` - (Optional) The kernel gateway app settings. See [Kernel Gateway App Settings](#kernel-gateway-app-settings) below. +* `r_session_app_settings` - (Optional) The RSession app settings. See [RSession App Settings](#rsession-app-settings) below. +* `canvas_app_settings` - (Optional) The Canvas app settings. See [Canvas App Settings](#canvas-app-settings) below. + +#### Canvas App Settings + +* `time_series_forecasting_settings` - (Optional) Time series forecast settings for the Canvas app. see [Time Series Forecasting Settings](#time-series-forecasting-settings) below. #### Sharing Settings @@ -62,6 +69,11 @@ The following arguments are supported: * `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](#default-resource-spec) below. * `lifecycle_config_arns` - (Optional) The Amazon Resource Name (ARN) of the Lifecycle Configurations. +#### RSession App Settings + +* `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](#default-resource-spec) below. +* `custom_image` - (Optional) A list of custom SageMaker images that are configured to run as a KernelGateway app. see [Custom Image](#custom-image) below. + ##### Default Resource Spec * `instance_type` - (Optional) The instance type. @@ -75,6 +87,11 @@ The following arguments are supported: * `image_name` - (Required) The name of the Custom Image. * `image_version_number` - (Optional) The version number of the Custom Image. +##### Time Series Forecasting Settings + +* `amazon_forecast_role_arn` - (Optional) The IAM role that Canvas passes to Amazon Forecast for time series forecasting. By default, Canvas uses the execution role specified in the UserProfile that launches the Canvas app. If an execution role is not specified in the UserProfile, Canvas uses the execution role specified in the Domain that owns the UserProfile. To allow time series forecasting, this IAM role should have the [AmazonSageMakerCanvasForecastAccess](https://docs.aws.amazon.com/sagemaker/latest/dg/security-iam-awsmanpol-canvas.html#security-iam-awsmanpol-AmazonSageMakerCanvasForecastAccess) policy attached and forecast.amazonaws.com added in the trust relationship as a service principal. +* `status` - (Optional) Describes whether time series forecasting is enabled or disabled in the Canvas app. Valid values are `ENABLED` and `DISABLED`. + ## Attributes Reference In addition to all arguments above, the following attributes are exported: From 3d37e57e6b71415c4456ea2084317ca02bb6cc9c Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 31 Oct 2022 11:58:53 -0400 Subject: [PATCH 4/5] r/aws_sagemaker_domain: Simplify acceptance test configurations. --- internal/service/sagemaker/domain_test.go | 149 ++++++++++------------ 1 file changed, 70 insertions(+), 79 deletions(-) diff --git a/internal/service/sagemaker/domain_test.go b/internal/service/sagemaker/domain_test.go index 4a9ef2dff2e8..60c06615336c 100644 --- a/internal/service/sagemaker/domain_test.go +++ b/internal/service/sagemaker/domain_test.go @@ -666,27 +666,10 @@ func testAccCheckDomainExists(n string, codeRepo *sagemaker.DescribeDomainOutput } } -func testAccDomainBaseConfig(rName string) string { - return fmt.Sprintf(` +func testAccDomainConfig_base(rName string) string { + return acctest.ConfigCompose(acctest.ConfigVPCWithSubnets(rName, 1), fmt.Sprintf(` data "aws_partition" "current" {} -resource "aws_vpc" "test" { - cidr_block = "10.0.0.0/16" - - tags = { - Name = %[1]q - } -} - -resource "aws_subnet" "test" { - vpc_id = aws_vpc.test.id - cidr_block = "10.0.1.0/24" - - tags = { - Name = %[1]q - } -} - resource "aws_iam_role" "test" { name = %[1]q path = "/" @@ -708,16 +691,16 @@ resource "aws_iam_role_policy_attachment" "test" { role = aws_iam_role.test.name policy_arn = "arn:${data.aws_partition.current.partition}:iam::aws:policy/AmazonSageMakerFullAccess" } -`, rName) +`, rName)) } func testAccDomainConfig_basic(rName string) string { - return testAccDomainBaseConfig(rName) + fmt.Sprintf(` + 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] + subnet_ids = aws_subnet.test[*].id default_user_settings { execution_role = aws_iam_role.test.arn @@ -727,16 +710,16 @@ resource "aws_sagemaker_domain" "test" { home_efs_file_system = "Delete" } } -`, rName) +`, rName)) } func testAccDomainConfig_domainSettings(rName, config string) string { - return testAccDomainBaseConfig(rName) + fmt.Sprintf(` + 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] + subnet_ids = aws_subnet.test[*].id default_user_settings { execution_role = aws_iam_role.test.arn @@ -750,13 +733,13 @@ resource "aws_sagemaker_domain" "test" { home_efs_file_system = "Delete" } } -`, rName, config) +`, rName, config)) } func testAccDomainConfig_kms(rName string) string { - return testAccDomainBaseConfig(rName) + fmt.Sprintf(` + return acctest.ConfigCompose(testAccDomainConfig_base(rName), fmt.Sprintf(` resource "aws_kms_key" "test" { - description = "Terraform acc test" + description = %[1]q deletion_window_in_days = 7 } @@ -764,7 +747,7 @@ resource "aws_sagemaker_domain" "test" { domain_name = %[1]q auth_mode = "IAM" vpc_id = aws_vpc.test.id - subnet_ids = [aws_subnet.test.id] + subnet_ids = aws_subnet.test[*].id kms_key_id = aws_kms_key.test.arn default_user_settings { @@ -775,68 +758,76 @@ resource "aws_sagemaker_domain" "test" { home_efs_file_system = "Delete" } } -`, rName) +`, rName)) } func testAccDomainConfig_securityGroup1(rName string) string { - return testAccDomainBaseConfig(rName) + fmt.Sprintf(` + return acctest.ConfigCompose(testAccDomainConfig_base(rName), fmt.Sprintf(` resource "aws_security_group" "test" { - name = "%[1]s" + count = 1 + + name = "%[1]s-${count.index}" + + tags = { + Name = %[1]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] + subnet_ids = aws_subnet.test[*].id default_user_settings { execution_role = aws_iam_role.test.arn - security_groups = [aws_security_group.test.id] + security_groups = aws_security_group.test[*].id } retention_policy { home_efs_file_system = "Delete" } } -`, rName) +`, rName)) } func testAccDomainConfig_securityGroup2(rName string) string { - return testAccDomainBaseConfig(rName) + fmt.Sprintf(` + return acctest.ConfigCompose(testAccDomainConfig_base(rName), fmt.Sprintf(` resource "aws_security_group" "test" { - name = %[1]q -} + count = 2 + + name = "%[1]s-${count.index}" -resource "aws_security_group" "test2" { - name = "%[1]s-2" + tags = { + Name = %[1]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] + subnet_ids = aws_subnet.test[*].id default_user_settings { execution_role = aws_iam_role.test.arn - security_groups = [aws_security_group.test.id, aws_security_group.test2.id] + security_groups = aws_security_group.test[*].id } retention_policy { home_efs_file_system = "Delete" } } -`, rName) +`, rName)) } func testAccDomainConfig_tags1(rName, tagKey1, tagValue1 string) string { - return testAccDomainBaseConfig(rName) + fmt.Sprintf(` + 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] + subnet_ids = aws_subnet.test[*].id default_user_settings { execution_role = aws_iam_role.test.arn @@ -850,16 +841,16 @@ resource "aws_sagemaker_domain" "test" { %[2]q = %[3]q } } -`, rName, tagKey1, tagValue1) +`, rName, tagKey1, tagValue1)) } func testAccDomainConfig_tags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { - return testAccDomainBaseConfig(rName) + fmt.Sprintf(` + 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] + subnet_ids = aws_subnet.test[*].id default_user_settings { execution_role = aws_iam_role.test.arn @@ -874,11 +865,11 @@ resource "aws_sagemaker_domain" "test" { %[4]q = %[5]q } } -`, rName, tagKey1, tagValue1, tagKey2, tagValue2) +`, rName, tagKey1, tagValue1, tagKey2, tagValue2)) } func testAccDomainConfig_sharingSettings(rName string) string { - return testAccDomainBaseConfig(rName) + fmt.Sprintf(` + return acctest.ConfigCompose(testAccDomainConfig_base(rName), fmt.Sprintf(` resource "aws_kms_key" "test" { description = %[1]q deletion_window_in_days = 7 @@ -894,7 +885,7 @@ resource "aws_sagemaker_domain" "test" { domain_name = %[1]q auth_mode = "IAM" vpc_id = aws_vpc.test.id - subnet_ids = [aws_subnet.test.id] + subnet_ids = aws_subnet.test[*].id default_user_settings { execution_role = aws_iam_role.test.arn @@ -910,16 +901,16 @@ resource "aws_sagemaker_domain" "test" { home_efs_file_system = "Delete" } } -`, rName) +`, rName)) } func testAccDomainConfig_canvasAppSettings(rName string) string { - return testAccDomainBaseConfig(rName) + fmt.Sprintf(` + 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] + subnet_ids = aws_subnet.test[*].id default_user_settings { execution_role = aws_iam_role.test.arn @@ -935,16 +926,16 @@ resource "aws_sagemaker_domain" "test" { home_efs_file_system = "Delete" } } -`, rName) +`, rName)) } func testAccDomainConfig_tensorBoardAppSettings(rName string) string { - return testAccDomainBaseConfig(rName) + fmt.Sprintf(` + 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] + subnet_ids = aws_subnet.test[*].id default_user_settings { execution_role = aws_iam_role.test.arn @@ -960,11 +951,11 @@ resource "aws_sagemaker_domain" "test" { home_efs_file_system = "Delete" } } -`, rName) +`, rName)) } func testAccDomainConfig_tensorBoardAppSettingsImage(rName string) string { - return testAccDomainBaseConfig(rName) + fmt.Sprintf(` + return acctest.ConfigCompose(testAccDomainConfig_base(rName), fmt.Sprintf(` resource "aws_sagemaker_image" "test" { image_name = %[1]q role_arn = aws_iam_role.test.arn @@ -974,7 +965,7 @@ resource "aws_sagemaker_domain" "test" { domain_name = %[1]q auth_mode = "IAM" vpc_id = aws_vpc.test.id - subnet_ids = [aws_subnet.test.id] + subnet_ids = aws_subnet.test[*].id default_user_settings { execution_role = aws_iam_role.test.arn @@ -991,16 +982,16 @@ resource "aws_sagemaker_domain" "test" { home_efs_file_system = "Delete" } } -`, rName) +`, rName)) } func testAccDomainConfig_jupyterServerAppSettings(rName string) string { - return testAccDomainBaseConfig(rName) + fmt.Sprintf(` + 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] + subnet_ids = aws_subnet.test[*].id default_user_settings { execution_role = aws_iam_role.test.arn @@ -1016,16 +1007,16 @@ resource "aws_sagemaker_domain" "test" { home_efs_file_system = "Delete" } } -`, rName) +`, rName)) } func testAccDomainConfig_rSessionAppSettings(rName string) string { - return testAccDomainBaseConfig(rName) + fmt.Sprintf(` + 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] + subnet_ids = aws_subnet.test[*].id default_user_settings { execution_role = aws_iam_role.test.arn @@ -1041,16 +1032,16 @@ resource "aws_sagemaker_domain" "test" { home_efs_file_system = "Delete" } } -`, rName) +`, rName)) } func testAccDomainConfig_kernelGatewayAppSettings(rName string) string { - return testAccDomainBaseConfig(rName) + fmt.Sprintf(` + 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] + subnet_ids = aws_subnet.test[*].id default_user_settings { execution_role = aws_iam_role.test.arn @@ -1066,11 +1057,11 @@ resource "aws_sagemaker_domain" "test" { home_efs_file_system = "Delete" } } -`, rName) +`, rName)) } func testAccDomainConfig_kernelGatewayAppSettingsLifecycle(rName string) string { - return testAccDomainBaseConfig(rName) + fmt.Sprintf(` + return acctest.ConfigCompose(testAccDomainConfig_base(rName), fmt.Sprintf(` resource "aws_sagemaker_studio_lifecycle_config" "test" { studio_lifecycle_config_name = %[1]q studio_lifecycle_config_app_type = "JupyterServer" @@ -1081,7 +1072,7 @@ resource "aws_sagemaker_domain" "test" { domain_name = %[1]q auth_mode = "IAM" vpc_id = aws_vpc.test.id - subnet_ids = [aws_subnet.test.id] + subnet_ids = aws_subnet.test[*].id default_user_settings { execution_role = aws_iam_role.test.arn @@ -1100,11 +1091,11 @@ resource "aws_sagemaker_domain" "test" { home_efs_file_system = "Delete" } } -`, rName) +`, rName)) } func testAccDomainConfig_kernelGatewayAppSettingsCustomImage(rName, baseImage string) string { - return testAccDomainBaseConfig(rName) + fmt.Sprintf(` + return acctest.ConfigCompose(testAccDomainConfig_base(rName), fmt.Sprintf(` resource "aws_sagemaker_image" "test" { image_name = %[1]q role_arn = aws_iam_role.test.arn @@ -1131,7 +1122,7 @@ resource "aws_sagemaker_domain" "test" { domain_name = %[1]q auth_mode = "IAM" vpc_id = aws_vpc.test.id - subnet_ids = [aws_subnet.test.id] + subnet_ids = aws_subnet.test[*].id default_user_settings { execution_role = aws_iam_role.test.arn @@ -1148,11 +1139,11 @@ resource "aws_sagemaker_domain" "test" { home_efs_file_system = "Delete" } } -`, rName, baseImage) +`, rName, baseImage)) } func testAccDomainConfig_kernelGatewayAppSettingsDefaultResourceSpecAndCustomImage(rName, baseImage string) string { - return testAccDomainBaseConfig(rName) + fmt.Sprintf(` + return acctest.ConfigCompose(testAccDomainConfig_base(rName), fmt.Sprintf(` resource "aws_sagemaker_image" "test" { image_name = %[1]q role_arn = aws_iam_role.test.arn @@ -1179,7 +1170,7 @@ resource "aws_sagemaker_domain" "test" { domain_name = %[1]q auth_mode = "IAM" vpc_id = aws_vpc.test.id - subnet_ids = [aws_subnet.test.id] + subnet_ids = aws_subnet.test[*].id default_user_settings { execution_role = aws_iam_role.test.arn @@ -1201,5 +1192,5 @@ resource "aws_sagemaker_domain" "test" { home_efs_file_system = "Delete" } } -`, rName, baseImage) +`, rName, baseImage)) } From fee9ec4c4ef81925cb7a6cf24f5d1401dfbcb90c Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 31 Oct 2022 13:50:45 -0400 Subject: [PATCH 5/5] r/aws_sagemaker_user_profile: Simplify acceptance test configurations. --- .../service/sagemaker/user_profile_test.go | 61 +++++++------------ 1 file changed, 22 insertions(+), 39 deletions(-) diff --git a/internal/service/sagemaker/user_profile_test.go b/internal/service/sagemaker/user_profile_test.go index 225b6d31dc3a..3d8e51a3f45a 100644 --- a/internal/service/sagemaker/user_profile_test.go +++ b/internal/service/sagemaker/user_profile_test.go @@ -364,25 +364,8 @@ func testAccCheckUserProfileExists(n string, userProfile *sagemaker.DescribeUser } } -func testAccUserProfileBaseConfig(rName string) string { - return fmt.Sprintf(` -resource "aws_vpc" "test" { - cidr_block = "10.0.0.0/16" - - tags = { - Name = %[1]q - } -} - -resource "aws_subnet" "test" { - vpc_id = aws_vpc.test.id - cidr_block = "10.0.1.0/24" - - tags = { - Name = %[1]q - } -} - +func testAccUserProfileConfig_base(rName string) string { + return acctest.ConfigCompose(acctest.ConfigVPCWithSubnets(rName, 1), fmt.Sprintf(` resource "aws_iam_role" "test" { name = %[1]q path = "/" @@ -404,7 +387,7 @@ resource "aws_sagemaker_domain" "test" { domain_name = %[1]q auth_mode = "IAM" vpc_id = aws_vpc.test.id - subnet_ids = [aws_subnet.test.id] + subnet_ids = aws_subnet.test[*].id default_user_settings { execution_role = aws_iam_role.test.arn @@ -414,20 +397,20 @@ resource "aws_sagemaker_domain" "test" { home_efs_file_system = "Delete" } } -`, rName) +`, rName)) } func testAccUserProfileConfig_basic(rName string) string { - return testAccUserProfileBaseConfig(rName) + fmt.Sprintf(` + return acctest.ConfigCompose(testAccUserProfileConfig_base(rName), fmt.Sprintf(` resource "aws_sagemaker_user_profile" "test" { domain_id = aws_sagemaker_domain.test.id user_profile_name = %[1]q } -`, rName) +`, rName)) } func testAccUserProfileConfig_tags1(rName, tagKey1, tagValue1 string) string { - return testAccUserProfileBaseConfig(rName) + fmt.Sprintf(` + return acctest.ConfigCompose(testAccUserProfileConfig_base(rName), fmt.Sprintf(` resource "aws_sagemaker_user_profile" "test" { domain_id = aws_sagemaker_domain.test.id user_profile_name = %[1]q @@ -436,11 +419,11 @@ resource "aws_sagemaker_user_profile" "test" { %[2]q = %[3]q } } -`, rName, tagKey1, tagValue1) +`, rName, tagKey1, tagValue1)) } func testAccUserProfileConfig_tags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { - return testAccUserProfileBaseConfig(rName) + fmt.Sprintf(` + return acctest.ConfigCompose(testAccUserProfileConfig_base(rName), fmt.Sprintf(` resource "aws_sagemaker_user_profile" "test" { domain_id = aws_sagemaker_domain.test.id user_profile_name = %[1]q @@ -450,11 +433,11 @@ resource "aws_sagemaker_user_profile" "test" { %[4]q = %[5]q } } -`, rName, tagKey1, tagValue1, tagKey2, tagValue2) +`, rName, tagKey1, tagValue1, tagKey2, tagValue2)) } func testAccUserProfileConfig_tensorBoardAppSettings(rName string) string { - return testAccUserProfileBaseConfig(rName) + fmt.Sprintf(` + return acctest.ConfigCompose(testAccUserProfileConfig_base(rName), fmt.Sprintf(` resource "aws_sagemaker_user_profile" "test" { domain_id = aws_sagemaker_domain.test.id user_profile_name = %[1]q @@ -469,11 +452,11 @@ resource "aws_sagemaker_user_profile" "test" { } } } -`, rName) +`, rName)) } func testAccUserProfileConfig_tensorBoardAppSettingsImage(rName string) string { - return testAccUserProfileBaseConfig(rName) + fmt.Sprintf(` + return acctest.ConfigCompose(testAccUserProfileConfig_base(rName), fmt.Sprintf(` resource "aws_sagemaker_image" "test" { image_name = %[1]q role_arn = aws_iam_role.test.arn @@ -494,11 +477,11 @@ resource "aws_sagemaker_user_profile" "test" { } } } -`, rName) +`, rName)) } func testAccUserProfileConfig_jupyterServerAppSettings(rName string) string { - return testAccUserProfileBaseConfig(rName) + fmt.Sprintf(` + return acctest.ConfigCompose(testAccUserProfileConfig_base(rName), fmt.Sprintf(` resource "aws_sagemaker_user_profile" "test" { domain_id = aws_sagemaker_domain.test.id user_profile_name = %[1]q @@ -513,11 +496,11 @@ resource "aws_sagemaker_user_profile" "test" { } } } -`, rName) +`, rName)) } func testAccUserProfileConfig_kernelGatewayAppSettings(rName string) string { - return testAccUserProfileBaseConfig(rName) + fmt.Sprintf(` + return acctest.ConfigCompose(testAccUserProfileConfig_base(rName), fmt.Sprintf(` resource "aws_sagemaker_user_profile" "test" { domain_id = aws_sagemaker_domain.test.id user_profile_name = %[1]q @@ -532,11 +515,11 @@ resource "aws_sagemaker_user_profile" "test" { } } } -`, rName) +`, rName)) } func testAccUserProfileConfig_kernelGatewayAppSettingsLifecycle(rName string) string { - return testAccUserProfileBaseConfig(rName) + fmt.Sprintf(` + return acctest.ConfigCompose(testAccUserProfileConfig_base(rName), fmt.Sprintf(` resource "aws_sagemaker_studio_lifecycle_config" "test" { studio_lifecycle_config_name = %[1]q studio_lifecycle_config_app_type = "JupyterServer" @@ -560,11 +543,11 @@ resource "aws_sagemaker_user_profile" "test" { } } } -`, rName) +`, rName)) } func testAccUserProfileConfig_kernelGatewayAppSettingsImage(rName, baseImage string) string { - return testAccUserProfileBaseConfig(rName) + fmt.Sprintf(` + return acctest.ConfigCompose(testAccUserProfileConfig_base(rName), fmt.Sprintf(` data "aws_partition" "current" {} resource "aws_iam_role_policy_attachment" "test" { @@ -603,5 +586,5 @@ resource "aws_sagemaker_user_profile" "test" { depends_on = [aws_iam_role_policy_attachment.test] } -`, rName, baseImage) +`, rName, baseImage)) }