diff --git a/.changelog/20122.txt b/.changelog/20122.txt new file mode 100644 index 000000000000..f01f4efcce05 --- /dev/null +++ b/.changelog/20122.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_sagemaker_workteam +``` \ No newline at end of file diff --git a/aws/aws_sagemaker_test.go b/aws/aws_sagemaker_test.go new file mode 100644 index 000000000000..3a3301ff05c8 --- /dev/null +++ b/aws/aws_sagemaker_test.go @@ -0,0 +1,60 @@ +package aws + +import ( + "testing" +) + +// Tests are serialized as SagmMaker Domain resources are limited to 1 per account by default. +// SageMaker UserProfile and App depend on the Domain resources and as such are also part of the serialized test suite. +// Sagemaker Workteam tests must also be serialized +func TestAccAWSSagemaker_serial(t *testing.T) { + testCases := map[string]map[string]func(t *testing.T){ + "App": { + "basic": testAccAWSSagemakerApp_basic, + "disappears": testAccAWSSagemakerApp_tags, + "tags": testAccAWSSagemakerApp_disappears, + "resourceSpec": testAccAWSSagemakerApp_resourceSpec, + }, + "Domain": { + "basic": testAccAWSSagemakerDomain_basic, + "disappears": testAccAWSSagemakerDomain_tags, + "tags": testAccAWSSagemakerDomain_disappears, + "tensorboardAppSettings": testAccAWSSagemakerDomain_tensorboardAppSettings, + "tensorboardAppSettingsWithImage": testAccAWSSagemakerDomain_tensorboardAppSettingsWithImage, + "kernelGatewayAppSettings": testAccAWSSagemakerDomain_kernelGatewayAppSettings, + "kernelGatewayAppSettings_customImage": testAccAWSSagemakerDomain_kernelGatewayAppSettings_customImage, + "jupyterServerAppSettings": testAccAWSSagemakerDomain_jupyterServerAppSettings, + "kms": testAccAWSSagemakerDomain_kms, + "securityGroup": testAccAWSSagemakerDomain_securityGroup, + "sharingSettings": testAccAWSSagemakerDomain_sharingSettings, + }, + "UserProfile": { + "basic": testAccAWSSagemakerUserProfile_basic, + "disappears": testAccAWSSagemakerUserProfile_tags, + "tags": testAccAWSSagemakerUserProfile_disappears, + "tensorboardAppSettings": testAccAWSSagemakerUserProfile_tensorboardAppSettings, + "tensorboardAppSettingsWithImage": testAccAWSSagemakerUserProfile_tensorboardAppSettingsWithImage, + "kernelGatewayAppSettings": testAccAWSSagemakerUserProfile_kernelGatewayAppSettings, + "jupyterServerAppSettings": testAccAWSSagemakerUserProfile_jupyterServerAppSettings, + }, + "Workteam": { + "disappears": testAccAWSSagemakerWorkteam_disappears, + "CognitoConfig": testAccAWSSagemakerWorkteam_cognitoConfig, + "NotificationConfig": testAccAWSSagemakerWorkteam_notificationConfig, + "OidcConfig": testAccAWSSagemakerWorkteam_oidcConfig, + "Tags": testAccAWSSagemakerWorkteam_tags, + }, + } + + for group, m := range testCases { + m := m + t.Run(group, func(t *testing.T) { + for name, tc := range m { + tc := tc + t.Run(name, func(t *testing.T) { + tc(t) + }) + } + }) + } +} diff --git a/aws/internal/service/sagemaker/finder/finder.go b/aws/internal/service/sagemaker/finder/finder.go index 9b3badf6934b..0ea02c403e78 100644 --- a/aws/internal/service/sagemaker/finder/finder.go +++ b/aws/internal/service/sagemaker/finder/finder.go @@ -209,3 +209,31 @@ func WorkforceByName(conn *sagemaker.SageMaker, name string) (*sagemaker.Workfor return output.Workforce, nil } + +func WorkteamByName(conn *sagemaker.SageMaker, name string) (*sagemaker.Workteam, error) { + input := &sagemaker.DescribeWorkteamInput{ + WorkteamName: aws.String(name), + } + + output, err := conn.DescribeWorkteam(input) + + if tfawserr.ErrMessageContains(err, "ValidationException", "The work team") { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + if output == nil || output.Workteam == nil { + return nil, &resource.NotFoundError{ + Message: "Empty result", + LastRequest: input, + } + } + + return output.Workteam, nil +} diff --git a/aws/provider.go b/aws/provider.go index 6fdd030ea27b..3f9f86dacc41 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -1014,6 +1014,7 @@ func Provider() *schema.Provider { "aws_sagemaker_notebook_instance": resourceAwsSagemakerNotebookInstance(), "aws_sagemaker_user_profile": resourceAwsSagemakerUserProfile(), "aws_sagemaker_workforce": resourceAwsSagemakerWorkforce(), + "aws_sagemaker_workteam": resourceAwsSagemakerWorkteam(), "aws_schemas_discoverer": resourceAwsSchemasDiscoverer(), "aws_schemas_registry": resourceAwsSchemasRegistry(), "aws_schemas_schema": resourceAwsSchemasSchema(), diff --git a/aws/resource_aws_sagemaker_domain_test.go b/aws/resource_aws_sagemaker_domain_test.go index b11720bff587..7fce7fcbd142 100644 --- a/aws/resource_aws_sagemaker_domain_test.go +++ b/aws/resource_aws_sagemaker_domain_test.go @@ -17,53 +17,6 @@ import ( "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/sagemaker/finder" ) -// Tests are serialized as SagmMaker Domain resources are limited to 1 per account by default. -// SageMaker UserProfile and App depend on the Domain resources and as such are also part of the serialized test suite. -func TestAccAWSSagemakerDomain_serial(t *testing.T) { - testCases := map[string]map[string]func(t *testing.T){ - "Domain": { - "basic": testAccAWSSagemakerDomain_basic, - "disappears": testAccAWSSagemakerDomain_tags, - "tags": testAccAWSSagemakerDomain_disappears, - "tensorboardAppSettings": testAccAWSSagemakerDomain_tensorboardAppSettings, - "tensorboardAppSettingsWithImage": testAccAWSSagemakerDomain_tensorboardAppSettingsWithImage, - "kernelGatewayAppSettings": testAccAWSSagemakerDomain_kernelGatewayAppSettings, - "kernelGatewayAppSettings_customImage": testAccAWSSagemakerDomain_kernelGatewayAppSettings_customImage, - "jupyterServerAppSettings": testAccAWSSagemakerDomain_jupyterServerAppSettings, - "kms": testAccAWSSagemakerDomain_kms, - "securityGroup": testAccAWSSagemakerDomain_securityGroup, - "sharingSettings": testAccAWSSagemakerDomain_sharingSettings, - }, - "UserProfile": { - "basic": testAccAWSSagemakerUserProfile_basic, - "disappears": testAccAWSSagemakerUserProfile_tags, - "tags": testAccAWSSagemakerUserProfile_disappears, - "tensorboardAppSettings": testAccAWSSagemakerUserProfile_tensorboardAppSettings, - "tensorboardAppSettingsWithImage": testAccAWSSagemakerUserProfile_tensorboardAppSettingsWithImage, - "kernelGatewayAppSettings": testAccAWSSagemakerUserProfile_kernelGatewayAppSettings, - "jupyterServerAppSettings": testAccAWSSagemakerUserProfile_jupyterServerAppSettings, - }, - "App": { - "basic": testAccAWSSagemakerApp_basic, - "disappears": testAccAWSSagemakerApp_tags, - "tags": testAccAWSSagemakerApp_disappears, - "resourceSpec": testAccAWSSagemakerApp_resourceSpec, - }, - } - - for group, m := range testCases { - m := m - t.Run(group, func(t *testing.T) { - for name, tc := range m { - tc := tc - t.Run(name, func(t *testing.T) { - tc(t) - }) - } - }) - } -} - func init() { resource.AddTestSweepers("aws_sagemaker_domain", &resource.Sweeper{ Name: "aws_sagemaker_domain", diff --git a/aws/resource_aws_sagemaker_workforce.go b/aws/resource_aws_sagemaker_workforce.go index 44297042145f..bee2694141da 100644 --- a/aws/resource_aws_sagemaker_workforce.go +++ b/aws/resource_aws_sagemaker_workforce.go @@ -194,7 +194,6 @@ func resourceAwsSagemakerWorkforceRead(d *schema.ResourceData, meta interface{}) if err != nil { return fmt.Errorf("error reading SageMaker Workforce (%s): %w", d.Id(), err) - } d.Set("arn", workforce.WorkforceArn) diff --git a/aws/resource_aws_sagemaker_workforce_test.go b/aws/resource_aws_sagemaker_workforce_test.go index b280924f68c8..b76c10af7d90 100644 --- a/aws/resource_aws_sagemaker_workforce_test.go +++ b/aws/resource_aws_sagemaker_workforce_test.go @@ -20,6 +20,9 @@ func init() { resource.AddTestSweepers("aws_sagemaker_workforce", &resource.Sweeper{ Name: "aws_sagemaker_workforce", F: testSweepSagemakerWorkforces, + Dependencies: []string{ + "aws_sagemaker_workteam", + }, }) } diff --git a/aws/resource_aws_sagemaker_workteam.go b/aws/resource_aws_sagemaker_workteam.go new file mode 100644 index 000000000000..63d3931258ac --- /dev/null +++ b/aws/resource_aws_sagemaker_workteam.go @@ -0,0 +1,400 @@ +package aws + +import ( + "fmt" + "log" + "regexp" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/sagemaker" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/sagemaker/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" +) + +func resourceAwsSagemakerWorkteam() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsSagemakerWorkteamCreate, + Read: resourceAwsSagemakerWorkteamRead, + Update: resourceAwsSagemakerWorkteamUpdate, + Delete: resourceAwsSagemakerWorkteamDelete, + + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "description": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 200), + }, + "member_definition": { + Type: schema.TypeList, + Required: true, + MinItems: 1, + MaxItems: 10, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "cognito_member_definition": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "client_id": { + Type: schema.TypeString, + Required: true, + }, + "user_group": { + Type: schema.TypeString, + Required: true, + }, + "user_pool": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + "oidc_member_definition": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "groups": { + Type: schema.TypeSet, + MaxItems: 10, + Required: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringLenBetween(1, 63), + }, + }, + }, + }, + }, + }, + }, + }, + "notification_configuration": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "notification_topic_arn": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validateArn, + }, + }, + }, + DiffSuppressFunc: suppressMissingOptionalConfigurationBlock, + }, + "subdomain": { + Type: schema.TypeString, + Computed: true, + }, + "tags": tagsSchema(), + "tags_all": tagsSchemaComputed(), + "workforce_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "workteam_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)."), + ), + }, + }, + + CustomizeDiff: SetTagsDiff, + } +} + +func resourceAwsSagemakerWorkteamCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).sagemakerconn + defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig + tags := defaultTagsConfig.MergeTags(keyvaluetags.New(d.Get("tags").(map[string]interface{}))) + + name := d.Get("workteam_name").(string) + input := &sagemaker.CreateWorkteamInput{ + WorkteamName: aws.String(name), + WorkforceName: aws.String(d.Get("workforce_name").(string)), + Description: aws.String(d.Get("description").(string)), + MemberDefinitions: expandSagemakerWorkteamMemberDefinition(d.Get("member_definition").([]interface{})), + } + + if v, ok := d.GetOk("notification_configuration"); ok { + input.NotificationConfiguration = expandSagemakerWorkteamNotificationConfiguration(v.([]interface{})) + } + + if len(tags) > 0 { + input.Tags = tags.IgnoreAws().SagemakerTags() + } + + log.Printf("[DEBUG] Updating SageMaker Workteam: %s", input) + _, err := tfresource.RetryWhenAwsErrCodeEquals(2*time.Minute, func() (interface{}, error) { + return conn.CreateWorkteam(input) + }, "ValidationException") + + if err != nil { + return fmt.Errorf("error creating SageMaker Workteam (%s): %w", name, err) + } + + d.SetId(name) + + return resourceAwsSagemakerWorkteamRead(d, meta) +} + +func resourceAwsSagemakerWorkteamRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).sagemakerconn + defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig + ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig + + workteam, err := finder.WorkteamByName(conn, d.Id()) + + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] SageMaker Workteam (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + + if err != nil { + return fmt.Errorf("error reading SageMaker Workteam (%s): %w", d.Id(), err) + } + + arn := aws.StringValue(workteam.WorkteamArn) + d.Set("arn", arn) + d.Set("subdomain", workteam.SubDomain) + d.Set("description", workteam.Description) + d.Set("workteam_name", workteam.WorkteamName) + + if err := d.Set("member_definition", flattenSagemakerWorkteamMemberDefinition(workteam.MemberDefinitions)); err != nil { + return fmt.Errorf("error setting member_definition: %w", err) + } + + if err := d.Set("notification_configuration", flattenSagemakerWorkteamNotificationConfiguration(workteam.NotificationConfiguration)); err != nil { + return fmt.Errorf("error setting notification_configuration: %w", err) + } + + tags, err := keyvaluetags.SagemakerListTags(conn, arn) + + if err != nil { + return fmt.Errorf("error listing tags for SageMaker Workteam (%s): %w", d.Id(), err) + } + + tags = tags.IgnoreAws().IgnoreConfig(ignoreTagsConfig) + + //lintignore:AWSR002 + if err := d.Set("tags", tags.RemoveDefaultConfig(defaultTagsConfig).Map()); err != nil { + return fmt.Errorf("error setting tags: %w", err) + } + + if err := d.Set("tags_all", tags.Map()); err != nil { + return fmt.Errorf("error setting tags_all: %w", err) + } + + return nil +} + +func resourceAwsSagemakerWorkteamUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).sagemakerconn + + if d.HasChangeExcept("tags_all") { + input := &sagemaker.UpdateWorkteamInput{ + WorkteamName: aws.String(d.Id()), + MemberDefinitions: expandSagemakerWorkteamMemberDefinition(d.Get("member_definition").([]interface{})), + } + + if d.HasChange("description") { + input.Description = aws.String(d.Get("description").(string)) + } + + if d.HasChange("notification_configuration") { + input.NotificationConfiguration = expandSagemakerWorkteamNotificationConfiguration(d.Get("notification_configuration").([]interface{})) + } + + log.Printf("[DEBUG] Updating SageMaker Workteam: %s", input) + _, err := conn.UpdateWorkteam(input) + + if err != nil { + return fmt.Errorf("error updating SageMaker Workteam (%s): %w", d.Id(), err) + } + } + + if d.HasChange("tags_all") { + o, n := d.GetChange("tags_all") + + if err := keyvaluetags.SagemakerUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { + return fmt.Errorf("error updating SageMaker Workteam (%s) tags: %w", d.Id(), err) + } + } + + return resourceAwsSagemakerWorkteamRead(d, meta) +} + +func resourceAwsSagemakerWorkteamDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).sagemakerconn + + log.Printf("[DEBUG] Deleting SageMaker Workteam: %s", d.Id()) + _, err := conn.DeleteWorkteam(&sagemaker.DeleteWorkteamInput{ + WorkteamName: aws.String(d.Id()), + }) + + if tfawserr.ErrMessageContains(err, "ValidationException", "The work team") { + return nil + } + + if err != nil { + return fmt.Errorf("error deleting SageMaker Workteam (%s): %w", d.Id(), err) + } + + return nil +} + +func expandSagemakerWorkteamMemberDefinition(l []interface{}) []*sagemaker.MemberDefinition { + if len(l) == 0 || l[0] == nil { + return nil + } + + var members []*sagemaker.MemberDefinition + + for _, mem := range l { + memRaw := mem.(map[string]interface{}) + member := &sagemaker.MemberDefinition{} + + if v, ok := memRaw["cognito_member_definition"].([]interface{}); ok && len(v) > 0 { + member.CognitoMemberDefinition = expandSagemakerWorkteamCognitoMemberDefinition(v) + } + + if v, ok := memRaw["oidc_member_definition"].([]interface{}); ok && len(v) > 0 { + member.OidcMemberDefinition = expandSagemakerWorkteamOidcMemberDefinition(v) + } + + members = append(members, member) + } + + return members +} + +func flattenSagemakerWorkteamMemberDefinition(config []*sagemaker.MemberDefinition) []map[string]interface{} { + members := make([]map[string]interface{}, 0, len(config)) + + for _, raw := range config { + member := make(map[string]interface{}) + + if raw.CognitoMemberDefinition != nil { + member["cognito_member_definition"] = flattenSagemakerWorkteamCognitoMemberDefinition(raw.CognitoMemberDefinition) + } + + if raw.OidcMemberDefinition != nil { + member["oidc_member_definition"] = flattenSagemakerWorkteamOidcMemberDefinition(raw.OidcMemberDefinition) + } + + members = append(members, member) + } + + return members +} + +func expandSagemakerWorkteamCognitoMemberDefinition(l []interface{}) *sagemaker.CognitoMemberDefinition { + if len(l) == 0 || l[0] == nil { + return nil + } + + m := l[0].(map[string]interface{}) + + config := &sagemaker.CognitoMemberDefinition{ + ClientId: aws.String(m["client_id"].(string)), + UserPool: aws.String(m["user_pool"].(string)), + UserGroup: aws.String(m["user_group"].(string)), + } + + return config +} + +func flattenSagemakerWorkteamCognitoMemberDefinition(config *sagemaker.CognitoMemberDefinition) []map[string]interface{} { + if config == nil { + return []map[string]interface{}{} + } + + m := map[string]interface{}{ + "client_id": aws.StringValue(config.ClientId), + "user_pool": aws.StringValue(config.UserPool), + "user_group": aws.StringValue(config.UserGroup), + } + + return []map[string]interface{}{m} +} + +func expandSagemakerWorkteamOidcMemberDefinition(l []interface{}) *sagemaker.OidcMemberDefinition { + if len(l) == 0 || l[0] == nil { + return nil + } + + m := l[0].(map[string]interface{}) + + config := &sagemaker.OidcMemberDefinition{ + Groups: expandStringSet(m["groups"].(*schema.Set)), + } + + return config +} + +func flattenSagemakerWorkteamOidcMemberDefinition(config *sagemaker.OidcMemberDefinition) []map[string]interface{} { + if config == nil { + return []map[string]interface{}{} + } + + m := map[string]interface{}{ + "groups": flattenStringSet(config.Groups), + } + + return []map[string]interface{}{m} +} + +func expandSagemakerWorkteamNotificationConfiguration(l []interface{}) *sagemaker.NotificationConfiguration { + if len(l) == 0 || l[0] == nil { + return nil + } + + m := l[0].(map[string]interface{}) + + config := &sagemaker.NotificationConfiguration{} + + if v, ok := m["notification_topic_arn"].(string); ok && v != "" { + config.NotificationTopicArn = aws.String(v) + } else { + return nil + } + + return config +} + +func flattenSagemakerWorkteamNotificationConfiguration(config *sagemaker.NotificationConfiguration) []map[string]interface{} { + if config == nil { + return []map[string]interface{}{} + } + + m := map[string]interface{}{ + "notification_topic_arn": aws.StringValue(config.NotificationTopicArn), + } + + return []map[string]interface{}{m} +} diff --git a/aws/resource_aws_sagemaker_workteam_test.go b/aws/resource_aws_sagemaker_workteam_test.go new file mode 100644 index 000000000000..36b0b32f6f82 --- /dev/null +++ b/aws/resource_aws_sagemaker_workteam_test.go @@ -0,0 +1,580 @@ +package aws + +import ( + "fmt" + "log" + "regexp" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/sagemaker" + "github.com/hashicorp/go-multierror" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/sagemaker/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" +) + +func init() { + resource.AddTestSweepers("aws_sagemaker_workteam", &resource.Sweeper{ + Name: "aws_sagemaker_workteam", + F: testSweepSagemakerWorkteams, + }) +} + +func testSweepSagemakerWorkteams(region string) error { + client, err := sharedClientForRegion(region) + if err != nil { + return fmt.Errorf("error getting client: %w", err) + } + conn := client.(*AWSClient).sagemakerconn + var sweeperErrs *multierror.Error + + err = conn.ListWorkteamsPages(&sagemaker.ListWorkteamsInput{}, func(page *sagemaker.ListWorkteamsOutput, lastPage bool) bool { + for _, workteam := range page.Workteams { + + r := resourceAwsSagemakerWorkteam() + d := r.Data(nil) + d.SetId(aws.StringValue(workteam.WorkteamName)) + err := r.Delete(d, client) + if err != nil { + log.Printf("[ERROR] %s", err) + sweeperErrs = multierror.Append(sweeperErrs, err) + continue + } + } + + return !lastPage + }) + + if testSweepSkipSweepError(err) { + log.Printf("[WARN] Skipping SageMaker workteam sweep for %s: %s", region, err) + return sweeperErrs.ErrorOrNil() + } + + if err != nil { + sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error retrieving Sagemaker Workteams: %w", err)) + } + + return sweeperErrs.ErrorOrNil() +} + +func testAccAWSSagemakerWorkteam_cognitoConfig(t *testing.T) { + var workteam sagemaker.Workteam + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_sagemaker_workteam.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, sagemaker.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSSagemakerWorkteamDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSSagemakerWorkteamCognitoConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSSagemakerWorkteamExists(resourceName, &workteam), + resource.TestCheckResourceAttr(resourceName, "workteam_name", rName), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "sagemaker", regexp.MustCompile(`workteam/.+`)), + resource.TestCheckResourceAttr(resourceName, "description", rName), + resource.TestCheckResourceAttr(resourceName, "member_definition.#", "1"), + resource.TestCheckResourceAttr(resourceName, "member_definition.0.cognito_member_definition.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "member_definition.0.cognito_member_definition.0.client_id", "aws_cognito_user_pool_client.test", "id"), + resource.TestCheckResourceAttrPair(resourceName, "member_definition.0.cognito_member_definition.0.user_pool", "aws_cognito_user_pool.test", "id"), + resource.TestCheckResourceAttrPair(resourceName, "member_definition.0.cognito_member_definition.0.user_group", "aws_cognito_user_group.test", "id"), + resource.TestCheckResourceAttrSet(resourceName, "subdomain"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"workforce_name"}, + }, + { + Config: testAccAWSSagemakerWorkteamCognitoUpdatedConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSSagemakerWorkteamExists(resourceName, &workteam), + resource.TestCheckResourceAttr(resourceName, "workteam_name", rName), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "sagemaker", regexp.MustCompile(`workteam/.+`)), + resource.TestCheckResourceAttr(resourceName, "description", rName), + resource.TestCheckResourceAttr(resourceName, "member_definition.#", "2"), + resource.TestCheckResourceAttr(resourceName, "member_definition.0.cognito_member_definition.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "member_definition.0.cognito_member_definition.0.client_id", "aws_cognito_user_pool_client.test", "id"), + resource.TestCheckResourceAttrPair(resourceName, "member_definition.0.cognito_member_definition.0.user_pool", "aws_cognito_user_pool.test", "id"), + resource.TestCheckResourceAttrPair(resourceName, "member_definition.0.cognito_member_definition.0.user_group", "aws_cognito_user_group.test", "id"), + resource.TestCheckResourceAttr(resourceName, "member_definition.1.cognito_member_definition.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "member_definition.1.cognito_member_definition.0.client_id", "aws_cognito_user_pool_client.test", "id"), + resource.TestCheckResourceAttrPair(resourceName, "member_definition.1.cognito_member_definition.0.user_pool", "aws_cognito_user_pool.test", "id"), + resource.TestCheckResourceAttrPair(resourceName, "member_definition.1.cognito_member_definition.0.user_group", "aws_cognito_user_group.test2", "id"), + resource.TestCheckResourceAttrSet(resourceName, "subdomain"), + ), + }, + { + Config: testAccAWSSagemakerWorkteamCognitoConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSSagemakerWorkteamExists(resourceName, &workteam), + resource.TestCheckResourceAttr(resourceName, "workteam_name", rName), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "sagemaker", regexp.MustCompile(`workteam/.+`)), + resource.TestCheckResourceAttr(resourceName, "description", rName), + resource.TestCheckResourceAttr(resourceName, "member_definition.#", "1"), + resource.TestCheckResourceAttr(resourceName, "member_definition.0.cognito_member_definition.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "member_definition.0.cognito_member_definition.0.client_id", "aws_cognito_user_pool_client.test", "id"), + resource.TestCheckResourceAttrPair(resourceName, "member_definition.0.cognito_member_definition.0.user_pool", "aws_cognito_user_pool.test", "id"), + resource.TestCheckResourceAttrPair(resourceName, "member_definition.0.cognito_member_definition.0.user_group", "aws_cognito_user_group.test", "id"), + resource.TestCheckResourceAttrSet(resourceName, "subdomain"), + ), + }, + }, + }) +} + +func testAccAWSSagemakerWorkteam_oidcConfig(t *testing.T) { + var workteam sagemaker.Workteam + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_sagemaker_workteam.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, sagemaker.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSSagemakerWorkteamDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSSagemakerWorkteamOidcConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSSagemakerWorkteamExists(resourceName, &workteam), + resource.TestCheckResourceAttr(resourceName, "workteam_name", rName), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "sagemaker", regexp.MustCompile(`workteam/.+`)), + resource.TestCheckResourceAttr(resourceName, "member_definition.#", "1"), + resource.TestCheckResourceAttr(resourceName, "member_definition.0.oidc_member_definition.#", "1"), + resource.TestCheckResourceAttr(resourceName, "member_definition.0.oidc_member_definition.0.groups.#", "1"), + resource.TestCheckTypeSetElemAttr(resourceName, "member_definition.0.oidc_member_definition.0.groups.*", rName), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"workforce_name"}, + }, + { + Config: testAccAWSSagemakerWorkteamOidcConfig2(rName, "test"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSSagemakerWorkteamExists(resourceName, &workteam), + resource.TestCheckResourceAttr(resourceName, "workteam_name", rName), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "sagemaker", regexp.MustCompile(`workteam/.+`)), + resource.TestCheckResourceAttr(resourceName, "member_definition.#", "1"), + resource.TestCheckResourceAttr(resourceName, "member_definition.0.oidc_member_definition.#", "1"), + resource.TestCheckResourceAttr(resourceName, "member_definition.0.oidc_member_definition.0.groups.#", "2"), + resource.TestCheckTypeSetElemAttr(resourceName, "member_definition.0.oidc_member_definition.0.groups.*", rName), + resource.TestCheckTypeSetElemAttr(resourceName, "member_definition.0.oidc_member_definition.0.groups.*", "test"), + ), + }, + { + Config: testAccAWSSagemakerWorkteamOidcConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSSagemakerWorkteamExists(resourceName, &workteam), + resource.TestCheckResourceAttr(resourceName, "workteam_name", rName), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "sagemaker", regexp.MustCompile(`workteam/.+`)), + resource.TestCheckResourceAttr(resourceName, "member_definition.#", "1"), + resource.TestCheckResourceAttr(resourceName, "member_definition.0.oidc_member_definition.#", "1"), + resource.TestCheckResourceAttr(resourceName, "member_definition.0.oidc_member_definition.0.groups.#", "1"), + resource.TestCheckTypeSetElemAttr(resourceName, "member_definition.0.oidc_member_definition.0.groups.*", rName)), + }, + }, + }) +} + +func testAccAWSSagemakerWorkteam_tags(t *testing.T) { + var workteam sagemaker.Workteam + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_sagemaker_workteam.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, sagemaker.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSSagemakerWorkteamDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSSagemakerWorkteamTagsConfig1(rName, "key1", "value1"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSSagemakerWorkteamExists(resourceName, &workteam), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"workforce_name"}, + }, + { + Config: testAccAWSSagemakerWorkteamTagsConfig2(rName, "key1", "value1updated", "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSSagemakerWorkteamExists(resourceName, &workteam), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + { + Config: testAccAWSSagemakerWorkteamTagsConfig1(rName, "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSSagemakerWorkteamExists(resourceName, &workteam), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + }, + }) +} + +func testAccAWSSagemakerWorkteam_notificationConfig(t *testing.T) { + var workteam sagemaker.Workteam + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_sagemaker_workteam.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, sagemaker.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSSagemakerWorkteamDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSSagemakerWorkteamNotificationConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSSagemakerWorkteamExists(resourceName, &workteam), + resource.TestCheckResourceAttr(resourceName, "workteam_name", rName), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "sagemaker", regexp.MustCompile(`workteam/.+`)), + resource.TestCheckResourceAttr(resourceName, "description", rName), + resource.TestCheckResourceAttr(resourceName, "notification_configuration.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "notification_configuration.0.notification_topic_arn", "aws_sns_topic.test", "arn"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"workforce_name"}, + }, + { + Config: testAccAWSSagemakerWorkteamOidcConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSSagemakerWorkteamExists(resourceName, &workteam), + resource.TestCheckResourceAttr(resourceName, "workteam_name", rName), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "sagemaker", regexp.MustCompile(`workteam/.+`)), + resource.TestCheckResourceAttr(resourceName, "description", rName), + resource.TestCheckResourceAttr(resourceName, "notification_configuration.#", "1"), + ), + }, + { + Config: testAccAWSSagemakerWorkteamNotificationConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSSagemakerWorkteamExists(resourceName, &workteam), + resource.TestCheckResourceAttr(resourceName, "workteam_name", rName), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "sagemaker", regexp.MustCompile(`workteam/.+`)), + resource.TestCheckResourceAttr(resourceName, "description", rName), + resource.TestCheckResourceAttr(resourceName, "notification_configuration.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "notification_configuration.0.notification_topic_arn", "aws_sns_topic.test", "arn"), + ), + }, + }, + }) +} + +func testAccAWSSagemakerWorkteam_disappears(t *testing.T) { + var workteam sagemaker.Workteam + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_sagemaker_workteam.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, sagemaker.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSSagemakerWorkteamDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSSagemakerWorkteamOidcConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSSagemakerWorkteamExists(resourceName, &workteam), + testAccCheckResourceDisappears(testAccProvider, resourceAwsSagemakerWorkteam(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccCheckAWSSagemakerWorkteamDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).sagemakerconn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_sagemaker_workteam" { + continue + } + + _, err := finder.WorkteamByName(conn, rs.Primary.ID) + + if tfresource.NotFound(err) { + continue + } + + if err != nil { + return err + } + + return fmt.Errorf("SageMaker Workteam %s still exists", rs.Primary.ID) + } + + return nil +} + +func testAccCheckAWSSagemakerWorkteamExists(n string, workteam *sagemaker.Workteam) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No SageMaker Workteam ID is set") + } + + conn := testAccProvider.Meta().(*AWSClient).sagemakerconn + + output, err := finder.WorkteamByName(conn, rs.Primary.ID) + + if err != nil { + return err + } + + *workteam = *output + + return nil + } +} + +func testAccAWSSagemakerWorkteamCognitoBaseConfig(rName string) string { + return fmt.Sprintf(` +resource "aws_cognito_user_pool" "test" { + name = %[1]q +} + +resource "aws_cognito_user_pool_client" "test" { + name = %[1]q + generate_secret = true + user_pool_id = aws_cognito_user_pool.test.id +} + +resource "aws_cognito_user_pool_domain" "test" { + domain = %[1]q + user_pool_id = aws_cognito_user_pool.test.id +} + +resource "aws_cognito_user_group" "test" { + name = %[1]q + user_pool_id = aws_cognito_user_pool.test.id +} + +resource "aws_sagemaker_workforce" "test" { + workforce_name = %[1]q + + cognito_config { + client_id = aws_cognito_user_pool_client.test.id + user_pool = aws_cognito_user_pool_domain.test.user_pool_id + } +} +`, rName) +} + +func testAccAWSSagemakerWorkteamCognitoConfig(rName string) string { + return composeConfig(testAccAWSSagemakerWorkteamCognitoBaseConfig(rName), fmt.Sprintf(` +resource "aws_sagemaker_workteam" "test" { + workteam_name = %[1]q + workforce_name = aws_sagemaker_workforce.test.id + description = %[1]q + + member_definition { + cognito_member_definition { + client_id = aws_cognito_user_pool_client.test.id + user_pool = aws_cognito_user_pool_domain.test.user_pool_id + user_group = aws_cognito_user_group.test.id + } + } +} +`, rName)) +} + +func testAccAWSSagemakerWorkteamCognitoUpdatedConfig(rName string) string { + return composeConfig(testAccAWSSagemakerWorkteamCognitoBaseConfig(rName), fmt.Sprintf(` +resource "aws_cognito_user_group" "test2" { + name = "%[1]s-2" + user_pool_id = aws_cognito_user_pool.test.id +} + +resource "aws_sagemaker_workteam" "test" { + workteam_name = %[1]q + workforce_name = aws_sagemaker_workforce.test.id + description = %[1]q + + member_definition { + cognito_member_definition { + client_id = aws_cognito_user_pool_client.test.id + user_pool = aws_cognito_user_pool_domain.test.user_pool_id + user_group = aws_cognito_user_group.test.id + } + } + + member_definition { + cognito_member_definition { + client_id = aws_cognito_user_pool_client.test.id + user_pool = aws_cognito_user_pool_domain.test.user_pool_id + user_group = aws_cognito_user_group.test2.id + } + } +} +`, rName)) +} + +func testAccAWSSagemakerWorkteamOidcBaseConfig(rName string) string { + return fmt.Sprintf(` +resource "aws_sagemaker_workforce" "test" { + workforce_name = %[1]q + + oidc_config { + authorization_endpoint = "https://example.com" + client_id = %[1]q + client_secret = %[1]q + issuer = "https://example.com" + jwks_uri = "https://example.com" + logout_endpoint = "https://example.com" + token_endpoint = "https://example.com" + user_info_endpoint = "https://example.com" + } +} +`, rName) +} + +func testAccAWSSagemakerWorkteamOidcConfig(rName string) string { + return composeConfig(testAccAWSSagemakerWorkteamOidcBaseConfig(rName), fmt.Sprintf(` +resource "aws_sagemaker_workteam" "test" { + workteam_name = %[1]q + workforce_name = aws_sagemaker_workforce.test.id + description = %[1]q + + member_definition { + oidc_member_definition { + groups = [%[1]q] + } + } +} +`, rName)) +} + +func testAccAWSSagemakerWorkteamOidcConfig2(rName, group string) string { + return composeConfig(testAccAWSSagemakerWorkteamOidcBaseConfig(rName), fmt.Sprintf(` +resource "aws_sagemaker_workteam" "test" { + workteam_name = %[1]q + workforce_name = aws_sagemaker_workforce.test.id + description = %[1]q + + member_definition { + oidc_member_definition { + groups = [%[1]q, %[2]q] + } + } +} +`, rName, group)) +} + +func testAccAWSSagemakerWorkteamNotificationConfig(rName string) string { + return composeConfig(testAccAWSSagemakerWorkteamOidcBaseConfig(rName), fmt.Sprintf(` +resource "aws_sns_topic" "test" { + name = %[1]q +} + +resource "aws_sns_topic_policy" "test" { + arn = aws_sns_topic.test.arn + + policy = jsonencode({ + "Version" : "2012-10-17", + "Id" : "default", + "Statement" : [ + { + "Sid" : "%[1]s", + "Effect" : "Allow", + "Principal" : { + "AWS" : "*" + }, + "Action" : [ + "sns:publish" + ], + "Resource" : "${aws_sns_topic.test.arn}" + } + ] + }) +} + +resource "aws_sagemaker_workteam" "test" { + workteam_name = %[1]q + workforce_name = aws_sagemaker_workforce.test.id + description = %[1]q + + member_definition { + oidc_member_definition { + groups = [%[1]q] + } + } + + notification_configuration { + notification_topic_arn = aws_sns_topic.test.arn + } +} +`, rName)) +} + +func testAccAWSSagemakerWorkteamTagsConfig1(rName, tagKey1, tagValue1 string) string { + return composeConfig(testAccAWSSagemakerWorkteamOidcBaseConfig(rName), fmt.Sprintf(` +resource "aws_sagemaker_workteam" "test" { + workteam_name = %[1]q + workforce_name = aws_sagemaker_workforce.test.id + description = %[1]q + + member_definition { + oidc_member_definition { + groups = [%[1]q] + } + } + + tags = { + %[2]q = %[3]q + } +} +`, rName, tagKey1, tagValue1)) +} + +func testAccAWSSagemakerWorkteamTagsConfig2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { + return composeConfig(testAccAWSSagemakerWorkteamOidcBaseConfig(rName), fmt.Sprintf(` +resource "aws_sagemaker_workteam" "test" { + workteam_name = %[1]q + workforce_name = aws_sagemaker_workforce.test.id + description = %[1]q + + member_definition { + oidc_member_definition { + groups = [%[1]q] + } + } + + tags = { + %[2]q = %[3]q + %[4]q = %[5]q + } +} +`, rName, tagKey1, tagValue1, tagKey2, tagValue2)) +} diff --git a/website/docs/r/sagemaker_workteam.html.markdown b/website/docs/r/sagemaker_workteam.html.markdown new file mode 100644 index 000000000000..970b34965453 --- /dev/null +++ b/website/docs/r/sagemaker_workteam.html.markdown @@ -0,0 +1,95 @@ +--- +subcategory: "Sagemaker" +layout: "aws" +page_title: "AWS: aws_sagemaker_workteam" +description: |- + Provides a Sagemaker Workteam resource. +--- + +# Resource: aws_sagemaker_workteam + +Provides a Sagemaker Workteam resource. + +## Example Usage + +### Cognito Usage + +```terraform +resource "aws_sagemaker_workteam" "example" { + workteam_name = "example" + workforce_name = aws_sagemaker_workforce.example.id + description = "example" + + member_definition { + cognito_member_definition { + client_id = aws_cognito_user_pool_client.example.id + user_pool = aws_cognito_user_pool_domain.example.user_pool_id + user_group = aws_cognito_user_group.example.id + } + } +} +``` + +### Oidc Usage + +```terraform +resource "aws_sagemaker_workteam" "example" { + workteam_name = "example" + workforce_name = aws_sagemaker_workforce.example.id + description = "example" + + member_definition { + oidc_member_definition { + groups = ["example"] + } + } +} +``` + +## Argument Reference + +The following arguments are supported: + +* `description` - (Required) A description of the work team. +* `workforce_name` - (Required) The name of the Workteam (must be unique). +* `workteam_name` - (Required) The name of the workforce. +* `member_definition` - (Required) A list of Member Definitions that contains objects that identify the workers that make up the work team. Workforces can be created using Amazon Cognito or your own OIDC Identity Provider (IdP). For private workforces created using Amazon Cognito use `cognito_member_definition`. For workforces created using your own OIDC identity provider (IdP) use `oidc_member_definition`. Do not provide input for both of these parameters in a single request. see [Member Definition](#member-definition) details below. +* `notification_configuration` - (Optional) Configures notification of workers regarding available or expiring work items. see [Notification Configuration](#notification-configuration) details below. +* `tags` - (Optional) A map of tags to assign to the resource. If configured with a provider [`default_tags` configuration block](/docs/providers/aws/index.html#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. + +### Member Definition + +* `cognito_member_definition` - (Optional) The Amazon Cognito user group that is part of the work team. See [Cognito Member Definition](#cognito-member-definition) details below. +* `oidc_member_definition` - (Optional) A list user groups that exist in your OIDC Identity Provider (IdP). One to ten groups can be used to create a single private work team. See [Cognito Member Definition](#oidc-member-definition) details below. + +#### Cognito Member Definition + +* `client_id` - (Required) An identifier for an application client. You must create the app client ID using Amazon Cognito. +* `user_pool` - (Required) An identifier for a user pool. The user pool must be in the same region as the service that you are calling. +* `user_group` - (Required) An identifier for a user group. + +#### Oidc Member Definition + +* `groups` - (Required) A list of comma separated strings that identifies user groups in your OIDC IdP. Each user group is made up of a group of private workers. + +### Notification Configuration + +* `notification_topic_arn` - (Required) The ARN for the SNS topic to which notifications should be published. + + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `arn` - The Amazon Resource Name (ARN) assigned by AWS to this Workteam. +* `id` - The name of the Workteam. +* `subdomain` - The subdomain for your OIDC Identity Provider. +* `tags_all` - A map of tags assigned to the resource, including those inherited from the provider [`default_tags` configuration block](/docs/providers/aws/index.html#default_tags-configuration-block). + +## Import + +Sagemaker Workteams can be imported using the `workteam_name`, e.g. + +``` +$ terraform import aws_sagemaker_workteam.example example +```