From d8040314ded734b4db3cf84ef4f957dc29f39dce Mon Sep 17 00:00:00 2001 From: GlennChia Date: Fri, 28 Jan 2022 17:43:13 +0800 Subject: [PATCH 01/20] feat(connect): add RoutingProfile schema --- internal/service/connect/routing_profile.go | 103 ++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 internal/service/connect/routing_profile.go diff --git a/internal/service/connect/routing_profile.go b/internal/service/connect/routing_profile.go new file mode 100644 index 00000000000..9a90583accd --- /dev/null +++ b/internal/service/connect/routing_profile.go @@ -0,0 +1,103 @@ +package connect + +import ( + "github.com/aws/aws-sdk-go/service/connect" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" +) + +func ResourceRoutingProfile() *schema.Resource { + return &schema.Resource{ + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, + Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "default_outbound_queue_id": { + Type: schema.TypeString, + Required: true, + }, + "description": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 250), + }, + "instance_id": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 100), + }, + "media_concurrencies": { + Type: schema.TypeSet, + MinItems: 1, + Required: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "channel": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(connect.Channel_Values(), false), // Valid values: VOICE | CHAT | TASK + }, + "concurrency": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IntBetween(1, 10), + }, + }, + }, + }, + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 127), + }, + "queue_configs": { + Type: schema.TypeSet, + Optional: true, + MinItems: 1, + MaxItems: 10, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "channel": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(connect.Channel_Values(), false), // Valid values: VOICE | CHAT | TASK + }, + "delay": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IntBetween(0, 9999), + }, + "priority": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IntBetween(1, 99), + }, + "queue_arn": { + Type: schema.TypeString, + Computed: true, + }, + "queue_id": { + Type: schema.TypeString, + Required: true, + }, + "queue_name": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "routing_profile_id": { + Type: schema.TypeString, + Computed: true, + }, + "tags": tftags.TagsSchema(), + "tags_all": tftags.TagsSchemaComputed(), + }, + } +} From fadc39cb1057473f2cca59f0415b6d7007628762 Mon Sep 17 00:00:00 2001 From: GlennChia Date: Fri, 28 Jan 2022 17:49:41 +0800 Subject: [PATCH 02/20] feat(connect): add RoutingProfile read --- internal/service/connect/enum.go | 3 + internal/service/connect/routing_profile.go | 142 ++++++++++++++++++++ 2 files changed, 145 insertions(+) diff --git a/internal/service/connect/enum.go b/internal/service/connect/enum.go index 6ae001e36da..33466de54a8 100644 --- a/internal/service/connect/enum.go +++ b/internal/service/connect/enum.go @@ -27,6 +27,9 @@ const ( // ListLambdaFunctionsMaxResults Valid Range: Minimum value of 1. Maximum value of 1000. // https://docs.aws.amazon.com/connect/latest/APIReference/API_ListQuickConnects.html ListQuickConnectsMaxResults = 60 + // ListRoutingProfileQueuesMaxResults Valid Range: Minimum value of 1. Maximum value of 100. + // https://docs.aws.amazon.com/connect/latest/APIReference/API_ListRoutingProfileQueues.html + ListRoutingProfileQueuesMaxResults = 60 ) func InstanceAttributeMapping() map[string]string { diff --git a/internal/service/connect/routing_profile.go b/internal/service/connect/routing_profile.go index 9a90583accd..b3fadf7f981 100644 --- a/internal/service/connect/routing_profile.go +++ b/internal/service/connect/routing_profile.go @@ -1,14 +1,24 @@ package connect import ( + "context" + "fmt" + "log" + "strings" + + "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/connect" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + "github.com/hashicorp/terraform-provider-aws/internal/conns" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" ) func ResourceRoutingProfile() *schema.Resource { return &schema.Resource{ + ReadContext: resourceRoutingProfileRead, Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, }, @@ -101,3 +111,135 @@ func ResourceRoutingProfile() *schema.Resource { }, } } + +func resourceRoutingProfileRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*conns.AWSClient).ConnectConn + defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig + ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig + + instanceID, routingProfileID, err := RoutingProfileParseID(d.Id()) + + if err != nil { + return diag.FromErr(err) + } + + resp, err := conn.DescribeRoutingProfileWithContext(ctx, &connect.DescribeRoutingProfileInput{ + InstanceId: aws.String(instanceID), + RoutingProfileId: aws.String(routingProfileID), + }) + + if !d.IsNewResource() && tfawserr.ErrMessageContains(err, connect.ErrCodeResourceNotFoundException, "") { + log.Printf("[WARN] Connect Routing Profile (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + + if err != nil { + return diag.FromErr(fmt.Errorf("error getting Connect Routing Profile (%s): %w", d.Id(), err)) + } + + if resp == nil || resp.RoutingProfile == nil { + return diag.FromErr(fmt.Errorf("error getting Connect Routing Profile (%s): empty response", d.Id())) + } + + routingProfile := resp.RoutingProfile + + if err := d.Set("media_concurrencies", flattenRoutingProfileMediaConcurrencies(routingProfile.MediaConcurrencies)); err != nil { + return diag.FromErr(err) + } + + d.Set("arn", routingProfile.RoutingProfileArn) + d.Set("default_outbound_queue_id", routingProfile.DefaultOutboundQueueId) + d.Set("description", routingProfile.Description) + d.Set("instance_id", instanceID) + d.Set("name", routingProfile.Name) + + d.Set("routing_profile_id", routingProfile.RoutingProfileId) + + // getting the routing profile queues uses a separate API: ListRoutingProfileQueues + queueConfigs, err := getConnectRoutingProfileQueueConfigs(ctx, conn, instanceID, routingProfileID) + + if err != nil { + return diag.FromErr(fmt.Errorf("error finding Connect Routing Profile Queue Configs Summary by Routing Profile ID (%s): %w", routingProfileID, err)) + } + + d.Set("queue_configs", queueConfigs) + + tags := KeyValueTags(routingProfile.Tags).IgnoreAWS().IgnoreConfig(ignoreTagsConfig) + + //lintignore:AWSR002 + if err := d.Set("tags", tags.RemoveDefaultConfig(defaultTagsConfig).Map()); err != nil { + return diag.FromErr(fmt.Errorf("error setting tags: %w", err)) + } + + if err := d.Set("tags_all", tags.Map()); err != nil { + return diag.FromErr(fmt.Errorf("error setting tags_all: %w", err)) + } + + return nil +} + +func flattenRoutingProfileMediaConcurrencies(mediaConcurrencies []*connect.MediaConcurrency) []interface{} { + mediaConcurrenciesList := []interface{}{} + + for _, mediaConcurrency := range mediaConcurrencies { + values := map[string]interface{}{ + "channel": aws.StringValue(mediaConcurrency.Channel), + "concurrency": aws.Int64Value(mediaConcurrency.Concurrency), + } + + mediaConcurrenciesList = append(mediaConcurrenciesList, values) + } + return mediaConcurrenciesList +} + +func getConnectRoutingProfileQueueConfigs(ctx context.Context, conn *connect.Connect, instanceID, routingProfileID string) ([]interface{}, error) { + queueConfigsList := []interface{}{} + + input := &connect.ListRoutingProfileQueuesInput{ + InstanceId: aws.String(instanceID), + MaxResults: aws.Int64(ListRoutingProfileQueuesMaxResults), + RoutingProfileId: aws.String(routingProfileID), + } + + err := conn.ListRoutingProfileQueuesPagesWithContext(ctx, input, func(page *connect.ListRoutingProfileQueuesOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, qc := range page.RoutingProfileQueueConfigSummaryList { + if qc == nil { + continue + } + + values := map[string]interface{}{ + "channel": aws.StringValue(qc.Channel), + "delay": aws.Int64Value(qc.Delay), + "priority": aws.Int64Value(qc.Priority), + "queue_arn": aws.StringValue(qc.QueueArn), + "queue_id": aws.StringValue(qc.QueueId), + "queue_name": aws.StringValue(qc.QueueName), + } + + queueConfigsList = append(queueConfigsList, values) + } + + return !lastPage + }) + + if err != nil { + return nil, err + } + + return queueConfigsList, nil +} + +func RoutingProfileParseID(id string) (string, string, error) { + parts := strings.SplitN(id, ":", 2) + + if len(parts) != 2 || parts[0] == "" || parts[1] == "" { + return "", "", fmt.Errorf("unexpected format of ID (%s), expected instanceID:routingProfileID", id) + } + + return parts[0], parts[1], nil +} From 14870509d634038bfa2495e1d905eb5420e0203a Mon Sep 17 00:00:00 2001 From: GlennChia Date: Fri, 28 Jan 2022 17:52:46 +0800 Subject: [PATCH 03/20] feat(connect): add RoutingProfile create --- internal/service/connect/routing_profile.go | 88 ++++++++++++++++++++- 1 file changed, 87 insertions(+), 1 deletion(-) diff --git a/internal/service/connect/routing_profile.go b/internal/service/connect/routing_profile.go index b3fadf7f981..60456b2922b 100644 --- a/internal/service/connect/routing_profile.go +++ b/internal/service/connect/routing_profile.go @@ -18,7 +18,8 @@ import ( func ResourceRoutingProfile() *schema.Resource { return &schema.Resource{ - ReadContext: resourceRoutingProfileRead, + CreateContext: resourceRoutingProfileCreate, + ReadContext: resourceRoutingProfileRead, Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, }, @@ -112,6 +113,46 @@ func ResourceRoutingProfile() *schema.Resource { } } +func resourceRoutingProfileCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*conns.AWSClient).ConnectConn + defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig + tags := defaultTagsConfig.MergeTags(tftags.New(d.Get("tags").(map[string]interface{}))) + + instanceID := d.Get("instance_id").(string) + name := d.Get("name").(string) + + input := &connect.CreateRoutingProfileInput{ + DefaultOutboundQueueId: aws.String(d.Get("default_outbound_queue_id").(string)), + Description: aws.String(d.Get("description").(string)), + InstanceId: aws.String(instanceID), + MediaConcurrencies: expandRoutingProfileMediaConcurrencies(d.Get("media_concurrencies").(*schema.Set).List()), + Name: aws.String(name), + } + + if v, ok := d.GetOk("queue_configs"); ok && v.(*schema.Set).Len() > 0 { + input.QueueConfigs = expandRoutingProfileQueueConfigs(v.(*schema.Set).List()) + } + + if len(tags) > 0 { + input.Tags = Tags(tags.IgnoreAWS()) + } + + log.Printf("[DEBUG] Creating Connect Routing Profile %s", input) + output, err := conn.CreateRoutingProfileWithContext(ctx, input) + + if err != nil { + return diag.FromErr(fmt.Errorf("error creating Connect Routing Profile (%s): %w", name, err)) + } + + if output == nil { + return diag.FromErr(fmt.Errorf("error creating Connect Routing Profile (%s): empty output", name)) + } + + d.SetId(fmt.Sprintf("%s:%s", instanceID, aws.StringValue(output.RoutingProfileId))) + + return resourceRoutingProfileRead(ctx, d, meta) +} + func resourceRoutingProfileRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { conn := meta.(*conns.AWSClient).ConnectConn defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig @@ -179,6 +220,25 @@ func resourceRoutingProfileRead(ctx context.Context, d *schema.ResourceData, met return nil } +func expandRoutingProfileMediaConcurrencies(mediaConcurrencies []interface{}) []*connect.MediaConcurrency { + if len(mediaConcurrencies) == 0 { + return nil + } + + mediaConcurrenciesExpanded := []*connect.MediaConcurrency{} + + for _, mediaConcurrency := range mediaConcurrencies { + data := mediaConcurrency.(map[string]interface{}) + mediaConcurrencyExpanded := &connect.MediaConcurrency{ + Channel: aws.String(data["channel"].(string)), + Concurrency: aws.Int64(int64(data["concurrency"].(int))), + } + mediaConcurrenciesExpanded = append(mediaConcurrenciesExpanded, mediaConcurrencyExpanded) + } + + return mediaConcurrenciesExpanded +} + func flattenRoutingProfileMediaConcurrencies(mediaConcurrencies []*connect.MediaConcurrency) []interface{} { mediaConcurrenciesList := []interface{}{} @@ -193,6 +253,32 @@ func flattenRoutingProfileMediaConcurrencies(mediaConcurrencies []*connect.Media return mediaConcurrenciesList } +func expandRoutingProfileQueueConfigs(queueConfigs []interface{}) []*connect.RoutingProfileQueueConfig { + if len(queueConfigs) == 0 { + return nil + } + + queueConfigsExpanded := []*connect.RoutingProfileQueueConfig{} + + for _, queueConfig := range queueConfigs { + data := queueConfig.(map[string]interface{}) + queueConfigExpanded := &connect.RoutingProfileQueueConfig{ + Delay: aws.Int64(int64(data["delay"].(int))), + Priority: aws.Int64(int64(data["priority"].(int))), + } + + qr := connect.RoutingProfileQueueReference{ + Channel: aws.String(data["channel"].(string)), + QueueId: aws.String(data["queue_id"].(string)), + } + queueConfigExpanded.QueueReference = &qr + + queueConfigsExpanded = append(queueConfigsExpanded, queueConfigExpanded) + } + + return queueConfigsExpanded +} + func getConnectRoutingProfileQueueConfigs(ctx context.Context, conn *connect.Connect, instanceID, routingProfileID string) ([]interface{}, error) { queueConfigsList := []interface{}{} From 69877fbc24423d59db2ad2d7cf13a2805cca6bec Mon Sep 17 00:00:00 2001 From: GlennChia Date: Fri, 28 Jan 2022 17:53:04 +0800 Subject: [PATCH 04/20] feat(connect): add RoutingProfile update --- internal/service/connect/routing_profile.go | 88 +++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/internal/service/connect/routing_profile.go b/internal/service/connect/routing_profile.go index 60456b2922b..98a95fbe460 100644 --- a/internal/service/connect/routing_profile.go +++ b/internal/service/connect/routing_profile.go @@ -20,6 +20,7 @@ func ResourceRoutingProfile() *schema.Resource { return &schema.Resource{ CreateContext: resourceRoutingProfileCreate, ReadContext: resourceRoutingProfileRead, + UpdateContext: resourceRoutingProfileUpdate, Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, }, @@ -220,6 +221,93 @@ func resourceRoutingProfileRead(ctx context.Context, d *schema.ResourceData, met return nil } +func resourceRoutingProfileUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*conns.AWSClient).ConnectConn + + instanceID, routingProfileID, err := RoutingProfileParseID(d.Id()) + + if err != nil { + return diag.FromErr(err) + } + + // RoutingProfile has 4 update APIs + // UpdateRoutingProfileConcurrency: Updates the channels that agents can handle in the Contact Control Panel (CCP) for a routing profile. + // UpdateRoutingProfileDefaultOutboundQueue: Updates the default outbound queue of a routing profile. + // UpdateRoutingProfileName: Updates the name and description of a routing profile. + // UpdateRoutingProfileQueues: Updates the properties associated with a set of queues for a routing profile. + + // updates to concurrency + inputConcurrency := &connect.UpdateRoutingProfileConcurrencyInput{ + InstanceId: aws.String(instanceID), + RoutingProfileId: aws.String(routingProfileID), + } + + if d.HasChange("media_concurrencies") { + mediaConcurrencies := expandRoutingProfileMediaConcurrencies(d.Get("media_concurrencies").(*schema.Set).List()) + inputConcurrency.MediaConcurrencies = mediaConcurrencies + _, err = conn.UpdateRoutingProfileConcurrencyWithContext(ctx, inputConcurrency) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error updating RoutingProfile Media Concurrency (%s): %w", d.Id(), err)) + } + } + + // updates to default outbound queue id + inputDefaultOutboundQueue := &connect.UpdateRoutingProfileDefaultOutboundQueueInput{ + InstanceId: aws.String(instanceID), + RoutingProfileId: aws.String(routingProfileID), + } + + if d.HasChange("default_outbound_queue_id") { + inputDefaultOutboundQueue.DefaultOutboundQueueId = aws.String(d.Get("default_outbound_queue_id").(string)) + _, err = conn.UpdateRoutingProfileDefaultOutboundQueueWithContext(ctx, inputDefaultOutboundQueue) + + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error updating RoutingProfile Default Outbound Queue ID (%s): %w", d.Id(), err)) + } + } + + // updates to name and/or description + inputNameDesc := &connect.UpdateRoutingProfileNameInput{ + InstanceId: aws.String(instanceID), + RoutingProfileId: aws.String(routingProfileID), + } + + if d.HasChanges("name", "description") { + inputNameDesc.Name = aws.String(d.Get("name").(string)) + inputNameDesc.Description = aws.String(d.Get("description").(string)) + _, err = conn.UpdateRoutingProfileNameWithContext(ctx, inputNameDesc) + + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error updating RoutingProfile Name (%s): %w", d.Id(), err)) + } + } + + // updates to queue configs + inputQueueConfig := &connect.UpdateRoutingProfileQueuesInput{ + InstanceId: aws.String(instanceID), + RoutingProfileId: aws.String(routingProfileID), + } + + if d.HasChange("queue_configs") { + queueConfigs := expandRoutingProfileQueueConfigs(d.Get("queue_configs").(*schema.Set).List()) + inputQueueConfig.QueueConfigs = queueConfigs + _, err = conn.UpdateRoutingProfileQueuesWithContext(ctx, inputQueueConfig) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error updating RoutingProfile Queue Configs (%s): %w", d.Id(), err)) + } + } + + // updates to tags + if d.HasChange("tags_all") { + o, n := d.GetChange("tags_all") + if err := UpdateTags(conn, d.Id(), o, n); err != nil { + return diag.FromErr(fmt.Errorf("error updating tags: %w", err)) + } + } + + return resourceRoutingProfileRead(ctx, d, meta) +} + func expandRoutingProfileMediaConcurrencies(mediaConcurrencies []interface{}) []*connect.MediaConcurrency { if len(mediaConcurrencies) == 0 { return nil From 3d646801b0598740f4fbbd04090d3851468cbf70 Mon Sep 17 00:00:00 2001 From: GlennChia Date: Fri, 28 Jan 2022 17:54:05 +0800 Subject: [PATCH 05/20] feat(connect): NoopContext RoutingProfile delete --- internal/service/connect/routing_profile.go | 24 +++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/internal/service/connect/routing_profile.go b/internal/service/connect/routing_profile.go index 98a95fbe460..7d886f48e19 100644 --- a/internal/service/connect/routing_profile.go +++ b/internal/service/connect/routing_profile.go @@ -21,6 +21,9 @@ func ResourceRoutingProfile() *schema.Resource { CreateContext: resourceRoutingProfileCreate, ReadContext: resourceRoutingProfileRead, UpdateContext: resourceRoutingProfileUpdate, + // Routing profiles do not support deletion today. NoOp the Delete method. + // Users can rename their routing profiles manually if they want. + DeleteContext: schema.NoopContext, Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, }, @@ -308,6 +311,27 @@ func resourceRoutingProfileUpdate(ctx context.Context, d *schema.ResourceData, m return resourceRoutingProfileRead(ctx, d, meta) } +// func resourceRoutingProfileDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { +// conn := meta.(*conns.AWSClient).ConnectConn + +// instanceID, routingProfileID, err := RoutingProfileParseID(d.Id()) + +// if err != nil { +// return diag.FromErr(err) +// } + +// _, err = conn.DeleteRoutingProfileWithContext(ctx, &connect.DeleteRoutingProfileInput{ +// InstanceId: aws.String(instanceID), +// RoutingProfileId: aws.String(routingProfileID), +// }) + +// if err != nil { +// return diag.FromErr(fmt.Errorf("error deleting RoutingProfile (%s): %w", d.Id(), err)) +// } + +// return nil +// } + func expandRoutingProfileMediaConcurrencies(mediaConcurrencies []interface{}) []*connect.MediaConcurrency { if len(mediaConcurrencies) == 0 { return nil From c1daa2117454fcfd523f541facca43802ca6aef7 Mon Sep 17 00:00:00 2001 From: GlennChia Date: Fri, 28 Jan 2022 17:56:32 +0800 Subject: [PATCH 06/20] feat(connect): add aws_connect_routing_profile --- internal/provider/provider.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 841ea0e913a..f6773081e1d 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -1004,6 +1004,7 @@ func Provider() *schema.Provider { "aws_connect_queue": connect.ResourceQueue(), "aws_connect_quick_connect": connect.ResourceQuickConnect(), "aws_connect_security_profile": connect.ResourceSecurityProfile(), + "aws_connect_routing_profile": connect.ResourceRoutingProfile(), "aws_cur_report_definition": cur.ResourceReportDefinition(), From ae19edc215340dcda1eae9fa3f9fd6ff8be4e95f Mon Sep 17 00:00:00 2001 From: GlennChia Date: Fri, 28 Jan 2022 18:19:02 +0800 Subject: [PATCH 07/20] test(connect): check RoutingProfile exists --- .../service/connect/routing_profile_test.go | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 internal/service/connect/routing_profile_test.go diff --git a/internal/service/connect/routing_profile_test.go b/internal/service/connect/routing_profile_test.go new file mode 100644 index 00000000000..eea5bc6de05 --- /dev/null +++ b/internal/service/connect/routing_profile_test.go @@ -0,0 +1,47 @@ +package connect_test + +import ( + "fmt" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/connect" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + tfconnect "github.com/hashicorp/terraform-provider-aws/internal/service/connect" +) + +func testAccCheckRoutingProfileExists(resourceName string, function *connect.DescribeRoutingProfileOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("Connect Routing Profile not found: %s", resourceName) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("Connect Routing Profile ID not set") + } + instanceID, routingProfileID, err := tfconnect.RoutingProfileParseID(rs.Primary.ID) + + if err != nil { + return err + } + + conn := acctest.Provider.Meta().(*conns.AWSClient).ConnectConn + + params := &connect.DescribeRoutingProfileInput{ + InstanceId: aws.String(instanceID), + RoutingProfileId: aws.String(routingProfileID), + } + + getFunction, err := conn.DescribeRoutingProfile(params) + if err != nil { + return err + } + + *function = *getFunction + + return nil + } +} From c076ff3d424b53f73ba1866bd5d4924b17643c91 Mon Sep 17 00:00:00 2001 From: GlennChia Date: Fri, 28 Jan 2022 18:19:42 +0800 Subject: [PATCH 08/20] test(connect): check RoutingProfile destroy --- .../service/connect/routing_profile_test.go | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/internal/service/connect/routing_profile_test.go b/internal/service/connect/routing_profile_test.go index eea5bc6de05..0095b711d9f 100644 --- a/internal/service/connect/routing_profile_test.go +++ b/internal/service/connect/routing_profile_test.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/connect" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" @@ -45,3 +46,34 @@ func testAccCheckRoutingProfileExists(resourceName string, function *connect.Des return nil } } + +func testAccCheckRoutingProfileDestroy(s *terraform.State) error { + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_connect_routing_profile" { + continue + } + + conn := acctest.Provider.Meta().(*conns.AWSClient).ConnectConn + + instanceID, routingProfileID, err := tfconnect.RoutingProfileParseID(rs.Primary.ID) + + if err != nil { + return err + } + + params := &connect.DescribeRoutingProfileInput{ + InstanceId: aws.String(instanceID), + RoutingProfileId: aws.String(routingProfileID), + } + + _, experr := conn.DescribeRoutingProfile(params) + // Verify the error is what we want + if experr != nil { + if awsErr, ok := experr.(awserr.Error); ok && awsErr.Code() == "ResourceNotFoundException" { + continue + } + return experr + } + } + return nil +} From 95db493ee5c933bc5f12211650a4b0ae78744252 Mon Sep 17 00:00:00 2001 From: GlennChia Date: Fri, 28 Jan 2022 18:27:17 +0800 Subject: [PATCH 09/20] test(connect): RoutingProfile basic, update desc --- .../service/connect/routing_profile_test.go | 117 ++++++++++++++++++ 1 file changed, 117 insertions(+) diff --git a/internal/service/connect/routing_profile_test.go b/internal/service/connect/routing_profile_test.go index 0095b711d9f..d0cc1cfcdf9 100644 --- a/internal/service/connect/routing_profile_test.go +++ b/internal/service/connect/routing_profile_test.go @@ -2,10 +2,12 @@ package connect_test import ( "fmt" + "testing" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/connect" + sdkacctest "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/hashicorp/terraform-provider-aws/internal/acctest" @@ -13,6 +15,76 @@ import ( tfconnect "github.com/hashicorp/terraform-provider-aws/internal/service/connect" ) +// Serialized acceptance tests due to Connect account limits (max 2 parallel tests) +func TestAccConnectRoutingProfile_serial(t *testing.T) { + testCases := map[string]func(t *testing.T){ + "basic": testAccRoutingProfile_basic, + } + + for name, tc := range testCases { + tc := tc + t.Run(name, func(t *testing.T) { + tc(t) + }) + } +} + +func testAccRoutingProfile_basic(t *testing.T) { + var v connect.DescribeRoutingProfileOutput + rName := sdkacctest.RandomWithPrefix("resource-test-terraform") + rName2 := sdkacctest.RandomWithPrefix("resource-test-terraform") + rName3 := sdkacctest.RandomWithPrefix("resource-test-terraform") + resourceName := "aws_connect_routing_profile.test" + originalDescription := "Created" + updatedDescription := "Updated" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, connect.EndpointsID), + Providers: acctest.Providers, + CheckDestroy: testAccCheckRoutingProfileDestroy, + Steps: []resource.TestStep{ + { + Config: testAccRoutingProfileBasicConfig(rName, rName2, rName3, originalDescription), + Check: resource.ComposeTestCheckFunc( + testAccCheckRoutingProfileExists(resourceName, &v), + resource.TestCheckResourceAttrSet(resourceName, "arn"), + resource.TestCheckResourceAttrPair(resourceName, "default_outbound_queue_id", "aws_connect_queue.default_outbound_queue", "queue_id"), + resource.TestCheckResourceAttr(resourceName, "description", originalDescription), + resource.TestCheckResourceAttrPair(resourceName, "instance_id", "aws_connect_instance.test", "id"), + resource.TestCheckResourceAttr(resourceName, "media_concurrencies.#", "1"), + resource.TestCheckResourceAttr(resourceName, "media_concurrencies.0.channel", connect.ChannelVoice), + resource.TestCheckResourceAttr(resourceName, "media_concurrencies.0.concurrency", "1"), + resource.TestCheckResourceAttr(resourceName, "name", rName3), + resource.TestCheckResourceAttrSet(resourceName, "routing_profile_id"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccRoutingProfileBasicConfig(rName, rName2, rName3, updatedDescription), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckRoutingProfileExists(resourceName, &v), + resource.TestCheckResourceAttrSet(resourceName, "arn"), + resource.TestCheckResourceAttrPair(resourceName, "default_outbound_queue_id", "aws_connect_queue.default_outbound_queue", "queue_id"), + resource.TestCheckResourceAttr(resourceName, "description", updatedDescription), + resource.TestCheckResourceAttrPair(resourceName, "instance_id", "aws_connect_instance.test", "id"), + resource.TestCheckResourceAttr(resourceName, "media_concurrencies.#", "1"), + resource.TestCheckResourceAttr(resourceName, "media_concurrencies.0.channel", connect.ChannelVoice), + resource.TestCheckResourceAttr(resourceName, "media_concurrencies.0.concurrency", "1"), + resource.TestCheckResourceAttr(resourceName, "name", rName3), + resource.TestCheckResourceAttrSet(resourceName, "routing_profile_id"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + ), + }, + }, + }) +} + func testAccCheckRoutingProfileExists(resourceName string, function *connect.DescribeRoutingProfileOutput) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[resourceName] @@ -77,3 +149,48 @@ func testAccCheckRoutingProfileDestroy(s *terraform.State) error { } return nil } + +func testAccRoutingProfileBaseConfig(rName, rName2 string) string { + return fmt.Sprintf(` +resource "aws_connect_instance" "test" { + identity_management_type = "CONNECT_MANAGED" + inbound_calls_enabled = true + instance_alias = %[1]q + outbound_calls_enabled = true +} + +data "aws_connect_hours_of_operation" "test" { + instance_id = aws_connect_instance.test.id + name = "Basic Hours" +} + +resource "aws_connect_queue" "default_outbound_queue" { + instance_id = aws_connect_instance.test.id + name = %[2]q + description = "Default Outbound Queue for Routing Profiles" + hours_of_operation_id = data.aws_connect_hours_of_operation.test.hours_of_operation_id +} +`, rName, rName2) +} + +func testAccRoutingProfileBasicConfig(rName, rName2, rName3, label string) string { + return acctest.ConfigCompose( + testAccRoutingProfileBaseConfig(rName, rName2), + fmt.Sprintf(` +resource "aws_connect_routing_profile" "test" { + instance_id = aws_connect_instance.test.id + name = %[1]q + default_outbound_queue_id = aws_connect_queue.default_outbound_queue.queue_id + description = %[2]q + + media_concurrencies { + channel = "VOICE" + concurrency = 1 + } + + tags = { + "Name" = "Test Routing Profile", + } +} +`, rName3, label)) +} From a46b62983247ce02c505c4f5179541edeffd9e58 Mon Sep 17 00:00:00 2001 From: GlennChia Date: Fri, 28 Jan 2022 18:32:44 +0800 Subject: [PATCH 10/20] test(connect): RoutingProfile skip disappears --- .../service/connect/routing_profile_test.go | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/internal/service/connect/routing_profile_test.go b/internal/service/connect/routing_profile_test.go index d0cc1cfcdf9..b2af76fc556 100644 --- a/internal/service/connect/routing_profile_test.go +++ b/internal/service/connect/routing_profile_test.go @@ -18,7 +18,8 @@ import ( // Serialized acceptance tests due to Connect account limits (max 2 parallel tests) func TestAccConnectRoutingProfile_serial(t *testing.T) { testCases := map[string]func(t *testing.T){ - "basic": testAccRoutingProfile_basic, + "basic": testAccRoutingProfile_basic, + "disappears": testAccRoutingProfile_disappears, } for name, tc := range testCases { @@ -85,6 +86,32 @@ func testAccRoutingProfile_basic(t *testing.T) { }) } +func testAccRoutingProfile_disappears(t *testing.T) { + t.Skip("Routing Profiles do not support deletion today") + var v connect.DescribeRoutingProfileOutput + rName := sdkacctest.RandomWithPrefix("resource-test-terraform") + rName2 := sdkacctest.RandomWithPrefix("resource-test-terraform") + rName3 := sdkacctest.RandomWithPrefix("resource-test-terraform") + resourceName := "aws_connect_routing_profile.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, connect.EndpointsID), + Providers: acctest.Providers, + CheckDestroy: testAccCheckRoutingProfileDestroy, + Steps: []resource.TestStep{ + { + Config: testAccRoutingProfileBasicConfig(rName, rName2, rName3, "Disappear"), + Check: resource.ComposeTestCheckFunc( + testAccCheckRoutingProfileExists(resourceName, &v), + acctest.CheckResourceDisappears(acctest.Provider, tfconnect.ResourceRoutingProfile(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + func testAccCheckRoutingProfileExists(resourceName string, function *connect.DescribeRoutingProfileOutput) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[resourceName] From 1b1db52a50e8439b5bd2a86170db0e7ce46da84f Mon Sep 17 00:00:00 2001 From: GlennChia Date: Fri, 28 Jan 2022 18:33:25 +0800 Subject: [PATCH 11/20] test(connect): RoutingProfile update concurrency --- .../service/connect/routing_profile_test.go | 85 ++++++++++++++++++- 1 file changed, 83 insertions(+), 2 deletions(-) diff --git a/internal/service/connect/routing_profile_test.go b/internal/service/connect/routing_profile_test.go index b2af76fc556..1598178d888 100644 --- a/internal/service/connect/routing_profile_test.go +++ b/internal/service/connect/routing_profile_test.go @@ -18,8 +18,9 @@ import ( // Serialized acceptance tests due to Connect account limits (max 2 parallel tests) func TestAccConnectRoutingProfile_serial(t *testing.T) { testCases := map[string]func(t *testing.T){ - "basic": testAccRoutingProfile_basic, - "disappears": testAccRoutingProfile_disappears, + "basic": testAccRoutingProfile_basic, + "disappears": testAccRoutingProfile_disappears, + "update_concurrency": testAccRoutingProfile_updateConcurrency, } for name, tc := range testCases { @@ -112,6 +113,59 @@ func testAccRoutingProfile_disappears(t *testing.T) { }) } +func testAccRoutingProfile_updateConcurrency(t *testing.T) { + var v connect.DescribeRoutingProfileOutput + rName := sdkacctest.RandomWithPrefix("resource-test-terraform") + rName2 := sdkacctest.RandomWithPrefix("resource-test-terraform") + rName3 := sdkacctest.RandomWithPrefix("resource-test-terraform") + resourceName := "aws_connect_routing_profile.test" + description := "testMediaConcurrencies" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, connect.EndpointsID), + Providers: acctest.Providers, + CheckDestroy: testAccCheckRoutingProfileDestroy, + Steps: []resource.TestStep{ + { + Config: testAccRoutingProfileBasicConfig(rName, rName2, rName3, description), + Check: resource.ComposeTestCheckFunc( + testAccCheckRoutingProfileExists(resourceName, &v), + resource.TestCheckResourceAttrSet(resourceName, "arn"), + resource.TestCheckResourceAttrPair(resourceName, "default_outbound_queue_id", "aws_connect_queue.default_outbound_queue", "queue_id"), + resource.TestCheckResourceAttr(resourceName, "description", description), + resource.TestCheckResourceAttrPair(resourceName, "instance_id", "aws_connect_instance.test", "id"), + resource.TestCheckResourceAttr(resourceName, "media_concurrencies.#", "1"), + resource.TestCheckResourceAttr(resourceName, "media_concurrencies.0.channel", connect.ChannelVoice), + resource.TestCheckResourceAttr(resourceName, "media_concurrencies.0.concurrency", "1"), + resource.TestCheckResourceAttr(resourceName, "name", rName3), + resource.TestCheckResourceAttrSet(resourceName, "routing_profile_id"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccRoutingProfileMediaConcurrenciesConfig(rName, rName2, rName3, description), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckRoutingProfileExists(resourceName, &v), + resource.TestCheckResourceAttrSet(resourceName, "arn"), + resource.TestCheckResourceAttrPair(resourceName, "default_outbound_queue_id", "aws_connect_queue.default_outbound_queue", "queue_id"), + resource.TestCheckResourceAttr(resourceName, "description", description), + resource.TestCheckResourceAttrPair(resourceName, "instance_id", "aws_connect_instance.test", "id"), + resource.TestCheckResourceAttr(resourceName, "media_concurrencies.#", "2"), + resource.TestCheckResourceAttr(resourceName, "name", rName3), + resource.TestCheckResourceAttrSet(resourceName, "routing_profile_id"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + ), + }, + }, + }) +} + func testAccCheckRoutingProfileExists(resourceName string, function *connect.DescribeRoutingProfileOutput) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[resourceName] @@ -221,3 +275,30 @@ resource "aws_connect_routing_profile" "test" { } `, rName3, label)) } + +func testAccRoutingProfileMediaConcurrenciesConfig(rName, rName2, rName3, label string) string { + return acctest.ConfigCompose( + testAccRoutingProfileBaseConfig(rName, rName2), + fmt.Sprintf(` +resource "aws_connect_routing_profile" "test" { + instance_id = aws_connect_instance.test.id + name = %[1]q + default_outbound_queue_id = aws_connect_queue.default_outbound_queue.queue_id + description = %[2]q + + media_concurrencies { + channel = "VOICE" + concurrency = 1 + } + + media_concurrencies { + channel = "CHAT" + concurrency = 2 + } + + tags = { + "Name" = "Test Routing Profile", + } +} +`, rName3, label)) +} From 967151f57d15241bc3f40cce2ba7b41b1c07eb7c Mon Sep 17 00:00:00 2001 From: GlennChia Date: Fri, 28 Jan 2022 18:34:11 +0800 Subject: [PATCH 12/20] test(connect): RoutingProfile update outboundQueue --- .../service/connect/routing_profile_test.go | 95 ++++++++++++++++++- 1 file changed, 92 insertions(+), 3 deletions(-) diff --git a/internal/service/connect/routing_profile_test.go b/internal/service/connect/routing_profile_test.go index 1598178d888..d5bc72cda38 100644 --- a/internal/service/connect/routing_profile_test.go +++ b/internal/service/connect/routing_profile_test.go @@ -18,9 +18,10 @@ import ( // Serialized acceptance tests due to Connect account limits (max 2 parallel tests) func TestAccConnectRoutingProfile_serial(t *testing.T) { testCases := map[string]func(t *testing.T){ - "basic": testAccRoutingProfile_basic, - "disappears": testAccRoutingProfile_disappears, - "update_concurrency": testAccRoutingProfile_updateConcurrency, + "basic": testAccRoutingProfile_basic, + "disappears": testAccRoutingProfile_disappears, + "update_concurrency": testAccRoutingProfile_updateConcurrency, + "update_default_outbound_queue": testAccRoutingProfile_updateDefaultOutboundQueue, } for name, tc := range testCases { @@ -166,6 +167,61 @@ func testAccRoutingProfile_updateConcurrency(t *testing.T) { }) } +func testAccRoutingProfile_updateDefaultOutboundQueue(t *testing.T) { + var v connect.DescribeRoutingProfileOutput + rName := sdkacctest.RandomWithPrefix("resource-test-terraform") + rName2 := sdkacctest.RandomWithPrefix("resource-test-terraform") + rName3 := sdkacctest.RandomWithPrefix("resource-test-terraform") + rName4 := sdkacctest.RandomWithPrefix("resource-test-terraform") + resourceName := "aws_connect_routing_profile.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, connect.EndpointsID), + Providers: acctest.Providers, + CheckDestroy: testAccCheckRoutingProfileDestroy, + Steps: []resource.TestStep{ + { + Config: testAccRoutingProfileDefaultOutboundQueueConfig(rName, rName2, rName3, rName4, "first"), + Check: resource.ComposeTestCheckFunc( + testAccCheckRoutingProfileExists(resourceName, &v), + resource.TestCheckResourceAttrSet(resourceName, "arn"), + resource.TestCheckResourceAttrPair(resourceName, "default_outbound_queue_id", "aws_connect_queue.default_outbound_queue", "queue_id"), + resource.TestCheckResourceAttrSet(resourceName, "description"), + resource.TestCheckResourceAttrPair(resourceName, "instance_id", "aws_connect_instance.test", "id"), + resource.TestCheckResourceAttr(resourceName, "media_concurrencies.#", "1"), + resource.TestCheckResourceAttr(resourceName, "media_concurrencies.0.channel", connect.ChannelVoice), + resource.TestCheckResourceAttr(resourceName, "media_concurrencies.0.concurrency", "1"), + resource.TestCheckResourceAttr(resourceName, "name", rName3), + resource.TestCheckResourceAttrSet(resourceName, "routing_profile_id"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccRoutingProfileDefaultOutboundQueueConfig(rName, rName2, rName3, rName4, "second"), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckRoutingProfileExists(resourceName, &v), + resource.TestCheckResourceAttrSet(resourceName, "arn"), + resource.TestCheckResourceAttrPair(resourceName, "default_outbound_queue_id", "aws_connect_queue.default_outbound_queue_update", "queue_id"), + resource.TestCheckResourceAttrSet(resourceName, "description"), + resource.TestCheckResourceAttrPair(resourceName, "instance_id", "aws_connect_instance.test", "id"), + resource.TestCheckResourceAttr(resourceName, "media_concurrencies.#", "1"), + resource.TestCheckResourceAttr(resourceName, "media_concurrencies.0.channel", connect.ChannelVoice), + resource.TestCheckResourceAttr(resourceName, "media_concurrencies.0.concurrency", "1"), + resource.TestCheckResourceAttr(resourceName, "name", rName3), + resource.TestCheckResourceAttrSet(resourceName, "routing_profile_id"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + ), + }, + }, + }) +} + func testAccCheckRoutingProfileExists(resourceName string, function *connect.DescribeRoutingProfileOutput) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[resourceName] @@ -302,3 +358,36 @@ resource "aws_connect_routing_profile" "test" { } `, rName3, label)) } + +func testAccRoutingProfileDefaultOutboundQueueConfig(rName, rName2, rName3, rName4, selectDefaultOutboundQueue string) string { + return acctest.ConfigCompose( + testAccRoutingProfileBaseConfig(rName, rName2), + fmt.Sprintf(` +locals { + select_default_outbound_queue_id = %[3]q +} + +resource "aws_connect_queue" "default_outbound_queue_update" { + instance_id = aws_connect_instance.test.id + name = %[2]q + description = "Default Outbound Queue for Routing Profiles" + hours_of_operation_id = data.aws_connect_hours_of_operation.test.hours_of_operation_id +} + +resource "aws_connect_routing_profile" "test" { + instance_id = aws_connect_instance.test.id + name = %[1]q + default_outbound_queue_id = local.select_default_outbound_queue_id == "first" ? aws_connect_queue.default_outbound_queue.queue_id : aws_connect_queue.default_outbound_queue_update.queue_id + description = "Test updating the default outbound queue id" + + media_concurrencies { + channel = "VOICE" + concurrency = 1 + } + + tags = { + "Name" = "Test Routing Profile", + } +} +`, rName3, rName4, selectDefaultOutboundQueue)) +} From 7f91283fa17a44c516e37d21a7930cda87646fa2 Mon Sep 17 00:00:00 2001 From: GlennChia Date: Fri, 28 Jan 2022 18:35:11 +0800 Subject: [PATCH 13/20] test(connect): RoutingProfile update queue configs --- .../service/connect/routing_profile_test.go | 128 ++++++++++++++++++ 1 file changed, 128 insertions(+) diff --git a/internal/service/connect/routing_profile_test.go b/internal/service/connect/routing_profile_test.go index d5bc72cda38..ed89a53b13d 100644 --- a/internal/service/connect/routing_profile_test.go +++ b/internal/service/connect/routing_profile_test.go @@ -22,6 +22,7 @@ func TestAccConnectRoutingProfile_serial(t *testing.T) { "disappears": testAccRoutingProfile_disappears, "update_concurrency": testAccRoutingProfile_updateConcurrency, "update_default_outbound_queue": testAccRoutingProfile_updateDefaultOutboundQueue, + "update_queues": testAccRoutingProfile_updateQueues, } for name, tc := range testCases { @@ -222,6 +223,75 @@ func testAccRoutingProfile_updateDefaultOutboundQueue(t *testing.T) { }) } +func testAccRoutingProfile_updateQueues(t *testing.T) { + var v connect.DescribeRoutingProfileOutput + rName := sdkacctest.RandomWithPrefix("resource-test-terraform") + rName2 := sdkacctest.RandomWithPrefix("resource-test-terraform") + rName3 := sdkacctest.RandomWithPrefix("resource-test-terraform") + resourceName := "aws_connect_routing_profile.test" + description := "testQueueConfigs" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, connect.EndpointsID), + Providers: acctest.Providers, + CheckDestroy: testAccCheckRoutingProfileDestroy, + Steps: []resource.TestStep{ + { + Config: testAccRoutingProfileQueueConfig1(rName, rName2, rName3, description), + Check: resource.ComposeTestCheckFunc( + testAccCheckRoutingProfileExists(resourceName, &v), + resource.TestCheckResourceAttrSet(resourceName, "arn"), + resource.TestCheckResourceAttrPair(resourceName, "default_outbound_queue_id", "aws_connect_queue.default_outbound_queue", "queue_id"), + resource.TestCheckResourceAttr(resourceName, "description", description), + resource.TestCheckResourceAttrPair(resourceName, "instance_id", "aws_connect_instance.test", "id"), + resource.TestCheckResourceAttr(resourceName, "media_concurrencies.#", "1"), + resource.TestCheckResourceAttr(resourceName, "media_concurrencies.0.channel", connect.ChannelVoice), + resource.TestCheckResourceAttr(resourceName, "media_concurrencies.0.concurrency", "1"), + resource.TestCheckResourceAttr(resourceName, "name", rName3), + resource.TestCheckResourceAttr(resourceName, "queue_configs.#", "1"), + resource.TestCheckResourceAttr(resourceName, "queue_configs.0.channel", connect.ChannelVoice), + resource.TestCheckResourceAttr(resourceName, "queue_configs.0.delay", "2"), + resource.TestCheckResourceAttr(resourceName, "queue_configs.0.priority", "1"), + resource.TestCheckResourceAttrPair(resourceName, "queue_configs.0.queue_arn", "aws_connect_queue.default_outbound_queue", "arn"), + resource.TestCheckResourceAttrPair(resourceName, "queue_configs.0.queue_id", "aws_connect_queue.default_outbound_queue", "queue_id"), + resource.TestCheckResourceAttrPair(resourceName, "queue_configs.0.queue_name", "aws_connect_queue.default_outbound_queue", "name"), + resource.TestCheckResourceAttrSet(resourceName, "routing_profile_id"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccRoutingProfileQueueConfig2(rName, rName2, rName3, description), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckRoutingProfileExists(resourceName, &v), + resource.TestCheckResourceAttrSet(resourceName, "arn"), + resource.TestCheckResourceAttrPair(resourceName, "default_outbound_queue_id", "aws_connect_queue.default_outbound_queue", "queue_id"), + resource.TestCheckResourceAttr(resourceName, "description", description), + resource.TestCheckResourceAttrPair(resourceName, "instance_id", "aws_connect_instance.test", "id"), + resource.TestCheckResourceAttr(resourceName, "media_concurrencies.#", "1"), + resource.TestCheckResourceAttr(resourceName, "media_concurrencies.0.channel", connect.ChannelVoice), + resource.TestCheckResourceAttr(resourceName, "media_concurrencies.0.concurrency", "1"), + resource.TestCheckResourceAttr(resourceName, "name", rName3), + resource.TestCheckResourceAttr(resourceName, "queue_configs.#", "1"), + resource.TestCheckResourceAttr(resourceName, "queue_configs.0.channel", connect.ChannelVoice), + resource.TestCheckResourceAttr(resourceName, "queue_configs.0.delay", "1"), + resource.TestCheckResourceAttr(resourceName, "queue_configs.0.priority", "2"), + resource.TestCheckResourceAttrPair(resourceName, "queue_configs.0.queue_arn", "aws_connect_queue.default_outbound_queue", "arn"), + resource.TestCheckResourceAttrPair(resourceName, "queue_configs.0.queue_id", "aws_connect_queue.default_outbound_queue", "queue_id"), + resource.TestCheckResourceAttrPair(resourceName, "queue_configs.0.queue_name", "aws_connect_queue.default_outbound_queue", "name"), + resource.TestCheckResourceAttrSet(resourceName, "routing_profile_id"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + ), + }, + }, + }) +} + func testAccCheckRoutingProfileExists(resourceName string, function *connect.DescribeRoutingProfileOutput) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[resourceName] @@ -391,3 +461,61 @@ resource "aws_connect_routing_profile" "test" { } `, rName3, rName4, selectDefaultOutboundQueue)) } + +func testAccRoutingProfileQueueConfig1(rName, rName2, rName3, label string) string { + return acctest.ConfigCompose( + testAccRoutingProfileBaseConfig(rName, rName2), + fmt.Sprintf(` +resource "aws_connect_routing_profile" "test" { + instance_id = aws_connect_instance.test.id + name = %[1]q + default_outbound_queue_id = aws_connect_queue.default_outbound_queue.queue_id + description = %[2]q + + media_concurrencies { + channel = "VOICE" + concurrency = 1 + } + + queue_configs { + channel = "VOICE" + delay = 2 + priority = 1 + queue_id = aws_connect_queue.default_outbound_queue.queue_id + } + + tags = { + "Name" = "Test Routing Profile", + } +} +`, rName3, label)) +} + +func testAccRoutingProfileQueueConfig2(rName, rName2, rName3, label string) string { + return acctest.ConfigCompose( + testAccRoutingProfileBaseConfig(rName, rName2), + fmt.Sprintf(` +resource "aws_connect_routing_profile" "test" { + instance_id = aws_connect_instance.test.id + name = %[1]q + default_outbound_queue_id = aws_connect_queue.default_outbound_queue.queue_id + description = %[2]q + + media_concurrencies { + channel = "VOICE" + concurrency = 1 + } + + queue_configs { + channel = "VOICE" + delay = 1 + priority = 2 + queue_id = aws_connect_queue.default_outbound_queue.queue_id + } + + tags = { + "Name" = "Test Routing Profile", + } +} +`, rName3, label)) +} From c75a1906b95f1b4cdbd2fa1aa489001774574626 Mon Sep 17 00:00:00 2001 From: GlennChia Date: Fri, 28 Jan 2022 20:16:56 +0800 Subject: [PATCH 14/20] docs(connect): add aws_connect_routing_profile --- .../r/connect_routing_profile.html.markdown | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 website/docs/r/connect_routing_profile.html.markdown diff --git a/website/docs/r/connect_routing_profile.html.markdown b/website/docs/r/connect_routing_profile.html.markdown new file mode 100644 index 00000000000..dcbe0ecf7f4 --- /dev/null +++ b/website/docs/r/connect_routing_profile.html.markdown @@ -0,0 +1,87 @@ +--- +subcategory: "Connect" +layout: "aws" +page_title: "AWS: aws_connect_routing_profile" +description: |- + Provides details about a specific Amazon Connect Routing Profile. +--- + +# Resource: aws_connect_routing_profile + +Provides an Amazon Connect Routing Profile resource. For more information see +[Amazon Connect: Getting Started](https://docs.aws.amazon.com/connect/latest/adminguide/amazon-connect-get-started.html) + +## Example Usage + +```terraform +resource "aws_connect_routing_profile" "example" { + instance_id = "aaaaaaaa-bbbb-cccc-dddd-111111111111" + name = "example" + default_outbound_queue_id = "12345678-1234-1234-1234-123456789012" + description = "example description" + + media_concurrencies { + channel = "VOICE" + concurrency = 1 + } + + queue_configs { + channel = "VOICE" + delay = 2 + priority = 1 + queue_id = "12345678-1234-1234-1234-123456789012" + } + + tags = { + "Name" = "Example Routing Profile", + } +} +``` + +## Argument Reference + +The following arguments are supported: + +* `default_outbound_queue_id` - (Required) Specifies the default outbound queue for the Routing Profile. +* `description` - (Required) Specifies the description of the Routing Profile. +* `instance_id` - (Required) Specifies the identifier of the hosting Amazon Connect Instance. +* `media_concurrencies` - (Required) One or more `media_concurrencies` blocks that specify the channels that agents can handle in the Contact Control Panel (CCP) for this Routing Profile. The `media_concurrencies` block is documented below. +* `name` - (Required) Specifies the name of the Routing Profile. +* `queue_configs` - (Optional) One or more `queue_configs` blocks that specify the inbound queues associated with the routing profile. If no queue is added, the agent only can make outbound calls. The `queue_configs` block is documented below. +* `tags` - (Optional) Tags to apply to the Routing Profile. 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. + +A `media_concurrencies` block supports the following arguments: + +* `channel` - (Required) Specifies the channels that agents can handle in the Contact Control Panel (CCP). Valid values are `VOICE`, `CHAT`, `TASK`. +* `concurrency` - (Required) Specifies the number of contacts an agent can have on a channel simultaneously. Valid Range for `VOICE`: Minimum value of 1. Maximum value of 1. Valid Range for `CHAT`: Minimum value of 1. Maximum value of 10. Valid Range for `TASK`: Minimum value of 1. Maximum value of 10. + +A `queue_configs` block supports the following arguments: + +* `channel` - (Required) Specifies the channels agents can handle in the Contact Control Panel (CCP) for this routing profile. Valid values are `VOICE`, `CHAT`, `TASK`. +* `delay` - (Required) Specifies the delay, in seconds, that a contact should be in the queue before they are routed to an available agent +* `priority` - (Required) Specifies the order in which contacts are to be handled for the queue. +* `queue_id` - (Required) Specifies the identifier for the queue. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `arn` - The Amazon Resource Name (ARN) of the Routing Profile. +* `id` - The identifier of the hosting Amazon Connect Instance and identifier of the Routing Profile separated by a colon (`:`). +* `queue_configs` - In addition to the arguments used in the `queue_configs` argument block, there are additional attributes exported within the `queue_configs` block. These additional attributes are documented below. +* `routing_profile_id` - The identifier for the Routing Profile. +* `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). + +A `queue_configs` block supports the following attributes in addition to the arguments defined earlier: + +* `queue_arn` - Specifies the ARN for the queue. +* `queue_name` - Specifies the name for the queue. + +## Import + +Amazon Connect Routing Profiles can be imported using the `instance_id` and `routing_profile_id` separated by a colon (`:`), e.g., + +``` +$ terraform import aws_connect_routing_profile.example f1288a1f-6193-445a-b47e-af739b2:c1d4e5f6-1b3c-1b3c-1b3c-c1d4e5f6c1d4e5 +``` From 0793166cfc5cf2e0173529ad36c34b5f615af15f Mon Sep 17 00:00:00 2001 From: GlennChia Date: Fri, 28 Jan 2022 20:21:25 +0800 Subject: [PATCH 15/20] ci(connect): changelog for RoutingProfile --- .changelog/22813.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/22813.txt diff --git a/.changelog/22813.txt b/.changelog/22813.txt new file mode 100644 index 00000000000..6296c72c565 --- /dev/null +++ b/.changelog/22813.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_connect_routing_profile + ``` \ No newline at end of file From 80c10503d26e84e25db6f20274b0b79e1f1fbe75 Mon Sep 17 00:00:00 2001 From: GlennChia Date: Fri, 28 Jan 2022 21:21:54 +0800 Subject: [PATCH 16/20] feat(connect): RoutingProfile add, remove queues --- internal/service/connect/routing_profile.go | 89 +++++++++++++++++++-- 1 file changed, 83 insertions(+), 6 deletions(-) diff --git a/internal/service/connect/routing_profile.go b/internal/service/connect/routing_profile.go index 7d886f48e19..d79ae8d1ba5 100644 --- a/internal/service/connect/routing_profile.go +++ b/internal/service/connect/routing_profile.go @@ -107,6 +107,39 @@ func ResourceRoutingProfile() *schema.Resource { }, }, }, + // used to update the queue configs by first disassociating the existing set and re-associating them + "queue_configs_associated": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "channel": { + Type: schema.TypeString, + Computed: true, + }, + "delay": { + Type: schema.TypeInt, + Computed: true, + }, + "priority": { + Type: schema.TypeInt, + Computed: true, + }, + "queue_arn": { + Type: schema.TypeString, + Computed: true, + }, + "queue_id": { + Type: schema.TypeString, + Computed: true, + }, + "queue_name": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, "routing_profile_id": { Type: schema.TypeString, Computed: true, @@ -209,6 +242,7 @@ func resourceRoutingProfileRead(ctx context.Context, d *schema.ResourceData, met } d.Set("queue_configs", queueConfigs) + d.Set("queue_configs_associated", queueConfigs) tags := KeyValueTags(routingProfile.Tags).IgnoreAWS().IgnoreConfig(ignoreTagsConfig) @@ -286,17 +320,40 @@ func resourceRoutingProfileUpdate(ctx context.Context, d *schema.ResourceData, m } // updates to queue configs - inputQueueConfig := &connect.UpdateRoutingProfileQueuesInput{ + // There are 3 APIs for this + // AssociateRoutingProfileQueues - Associates a set of queues with a routing profile. + // DisassociateRoutingProfileQueues - Disassociates a set of queues from a routing profile. + // UpdateRoutingProfileQueues - Updates the properties associated with a set of queues for a routing profile. + // since the update only updates the existing queues that are associated, we will instead disassociate (if there are any queues) + // and then associate all the queues again to ensure new queues can be added and unused queues can be removed + inputQueueAssociate := &connect.AssociateRoutingProfileQueuesInput{ + InstanceId: aws.String(instanceID), + RoutingProfileId: aws.String(routingProfileID), + } + + inputQueueDisassociate := &connect.DisassociateRoutingProfileQueuesInput{ InstanceId: aws.String(instanceID), RoutingProfileId: aws.String(routingProfileID), } if d.HasChange("queue_configs") { - queueConfigs := expandRoutingProfileQueueConfigs(d.Get("queue_configs").(*schema.Set).List()) - inputQueueConfig.QueueConfigs = queueConfigs - _, err = conn.UpdateRoutingProfileQueuesWithContext(ctx, inputQueueConfig) - if err != nil { - return diag.FromErr(fmt.Errorf("[ERROR] Error updating RoutingProfile Queue Configs (%s): %w", d.Id(), err)) + // first disassociate all existing queues + currentAssociatedQueueReferences := expandRoutingProfileQueueReferences(d.Get("queue_configs_associated").(*schema.Set).List()) + if currentAssociatedQueueReferences != nil { + inputQueueDisassociate.QueueReferences = currentAssociatedQueueReferences + _, err = conn.DisassociateRoutingProfileQueuesWithContext(ctx, inputQueueDisassociate) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error updating RoutingProfile Queue Configs, specifically disassociating queues from routing profile (%s): %w", d.Id(), err)) + } + } + // re-associate the queues + updatedQueueConfigs := expandRoutingProfileQueueConfigs(d.Get("queue_configs").(*schema.Set).List()) + if updatedQueueConfigs != nil { + inputQueueAssociate.QueueConfigs = updatedQueueConfigs + _, err = conn.AssociateRoutingProfileQueuesWithContext(ctx, inputQueueAssociate) + if err != nil { + return diag.FromErr(fmt.Errorf("[ERROR] Error updating RoutingProfile Queue Configs, specifically associating queues to routing profile (%s): %w", d.Id(), err)) + } } } @@ -391,6 +448,26 @@ func expandRoutingProfileQueueConfigs(queueConfigs []interface{}) []*connect.Rou return queueConfigsExpanded } +func expandRoutingProfileQueueReferences(queueConfigs []interface{}) []*connect.RoutingProfileQueueReference { + if len(queueConfigs) == 0 { + return nil + } + + queueReferencesExpanded := []*connect.RoutingProfileQueueReference{} + + for _, queueConfig := range queueConfigs { + data := queueConfig.(map[string]interface{}) + queueReferenceExpanded := &connect.RoutingProfileQueueReference{ + Channel: aws.String(data["channel"].(string)), + QueueId: aws.String(data["queue_id"].(string)), + } + + queueReferencesExpanded = append(queueReferencesExpanded, queueReferenceExpanded) + } + + return queueReferencesExpanded +} + func getConnectRoutingProfileQueueConfigs(ctx context.Context, conn *connect.Connect, instanceID, routingProfileID string) ([]interface{}, error) { queueConfigsList := []interface{}{} From e45dd9d42167d5ce7d0607d250ec87abf760309b Mon Sep 17 00:00:00 2001 From: GlennChia Date: Fri, 28 Jan 2022 21:23:57 +0800 Subject: [PATCH 17/20] test(connect): RoutingProfile add, rm, upd queues --- .../service/connect/routing_profile_test.go | 80 +++++++++++++++++-- 1 file changed, 73 insertions(+), 7 deletions(-) diff --git a/internal/service/connect/routing_profile_test.go b/internal/service/connect/routing_profile_test.go index ed89a53b13d..eb9f7680fcf 100644 --- a/internal/service/connect/routing_profile_test.go +++ b/internal/service/connect/routing_profile_test.go @@ -228,6 +228,7 @@ func testAccRoutingProfile_updateQueues(t *testing.T) { rName := sdkacctest.RandomWithPrefix("resource-test-terraform") rName2 := sdkacctest.RandomWithPrefix("resource-test-terraform") rName3 := sdkacctest.RandomWithPrefix("resource-test-terraform") + rName4 := sdkacctest.RandomWithPrefix("resource-test-terraform") resourceName := "aws_connect_routing_profile.test" description := "testQueueConfigs" @@ -238,8 +239,32 @@ func testAccRoutingProfile_updateQueues(t *testing.T) { CheckDestroy: testAccCheckRoutingProfileDestroy, Steps: []resource.TestStep{ { - Config: testAccRoutingProfileQueueConfig1(rName, rName2, rName3, description), + // Routing profile without queue_configs + Config: testAccRoutingProfileBasicConfig(rName, rName2, rName3, description), Check: resource.ComposeTestCheckFunc( + testAccCheckRoutingProfileExists(resourceName, &v), + resource.TestCheckResourceAttrSet(resourceName, "arn"), + resource.TestCheckResourceAttrPair(resourceName, "default_outbound_queue_id", "aws_connect_queue.default_outbound_queue", "queue_id"), + resource.TestCheckResourceAttr(resourceName, "description", description), + resource.TestCheckResourceAttrPair(resourceName, "instance_id", "aws_connect_instance.test", "id"), + resource.TestCheckResourceAttr(resourceName, "media_concurrencies.#", "1"), + resource.TestCheckResourceAttr(resourceName, "media_concurrencies.0.channel", connect.ChannelVoice), + resource.TestCheckResourceAttr(resourceName, "media_concurrencies.0.concurrency", "1"), + resource.TestCheckResourceAttr(resourceName, "name", rName3), + resource.TestCheckResourceAttr(resourceName, "queue_configs.#", "0"), + resource.TestCheckResourceAttrSet(resourceName, "routing_profile_id"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + // Routing profile with one queue_configs + Config: testAccRoutingProfileQueueConfig1(rName, rName2, rName3, description), + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckRoutingProfileExists(resourceName, &v), resource.TestCheckResourceAttrSet(resourceName, "arn"), resource.TestCheckResourceAttrPair(resourceName, "default_outbound_queue_id", "aws_connect_queue.default_outbound_queue", "queue_id"), @@ -266,7 +291,34 @@ func testAccRoutingProfile_updateQueues(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccRoutingProfileQueueConfig2(rName, rName2, rName3, description), + // Routing profile with two queue_configs (one new config and one edited config) + Config: testAccRoutingProfileQueueConfig2(rName, rName2, rName3, rName4, description), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckRoutingProfileExists(resourceName, &v), + resource.TestCheckResourceAttrSet(resourceName, "arn"), + resource.TestCheckResourceAttrPair(resourceName, "default_outbound_queue_id", "aws_connect_queue.default_outbound_queue", "queue_id"), + resource.TestCheckResourceAttr(resourceName, "description", description), + resource.TestCheckResourceAttrPair(resourceName, "instance_id", "aws_connect_instance.test", "id"), + resource.TestCheckResourceAttr(resourceName, "media_concurrencies.#", "1"), + resource.TestCheckResourceAttr(resourceName, "media_concurrencies.0.channel", connect.ChannelVoice), + resource.TestCheckResourceAttr(resourceName, "media_concurrencies.0.concurrency", "1"), + resource.TestCheckResourceAttr(resourceName, "name", rName3), + resource.TestCheckResourceAttr(resourceName, "queue_configs.#", "2"), + // The delay attribute of both elements of the set are set to 1 + resource.TestCheckResourceAttr(resourceName, "queue_configs.0.delay", "1"), + resource.TestCheckResourceAttr(resourceName, "queue_configs.1.delay", "1"), + resource.TestCheckResourceAttrSet(resourceName, "routing_profile_id"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + // Routing profile with one queue_configs (remove the created queue config) + Config: testAccRoutingProfileQueueConfig1(rName, rName2, rName3, description), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckRoutingProfileExists(resourceName, &v), resource.TestCheckResourceAttrSet(resourceName, "arn"), @@ -279,8 +331,8 @@ func testAccRoutingProfile_updateQueues(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "name", rName3), resource.TestCheckResourceAttr(resourceName, "queue_configs.#", "1"), resource.TestCheckResourceAttr(resourceName, "queue_configs.0.channel", connect.ChannelVoice), - resource.TestCheckResourceAttr(resourceName, "queue_configs.0.delay", "1"), - resource.TestCheckResourceAttr(resourceName, "queue_configs.0.priority", "2"), + resource.TestCheckResourceAttr(resourceName, "queue_configs.0.delay", "2"), + resource.TestCheckResourceAttr(resourceName, "queue_configs.0.priority", "1"), resource.TestCheckResourceAttrPair(resourceName, "queue_configs.0.queue_arn", "aws_connect_queue.default_outbound_queue", "arn"), resource.TestCheckResourceAttrPair(resourceName, "queue_configs.0.queue_id", "aws_connect_queue.default_outbound_queue", "queue_id"), resource.TestCheckResourceAttrPair(resourceName, "queue_configs.0.queue_name", "aws_connect_queue.default_outbound_queue", "name"), @@ -491,15 +543,22 @@ resource "aws_connect_routing_profile" "test" { `, rName3, label)) } -func testAccRoutingProfileQueueConfig2(rName, rName2, rName3, label string) string { +func testAccRoutingProfileQueueConfig2(rName, rName2, rName3, rName4, label string) string { return acctest.ConfigCompose( testAccRoutingProfileBaseConfig(rName, rName2), fmt.Sprintf(` +resource "aws_connect_queue" "test" { + instance_id = aws_connect_instance.test.id + name = %[2]q + description = "Additonal queue to routing profile queue config" + hours_of_operation_id = data.aws_connect_hours_of_operation.test.hours_of_operation_id +} + resource "aws_connect_routing_profile" "test" { instance_id = aws_connect_instance.test.id name = %[1]q default_outbound_queue_id = aws_connect_queue.default_outbound_queue.queue_id - description = %[2]q + description = %[3]q media_concurrencies { channel = "VOICE" @@ -513,9 +572,16 @@ resource "aws_connect_routing_profile" "test" { queue_id = aws_connect_queue.default_outbound_queue.queue_id } + queue_configs { + channel = "CHAT" + delay = 1 + priority = 1 + queue_id = aws_connect_queue.test.queue_id + } + tags = { "Name" = "Test Routing Profile", } } -`, rName3, label)) +`, rName3, rName4, label)) } From 0027f1ca831d73aa8e6da0bc6827718577150cfd Mon Sep 17 00:00:00 2001 From: GlennChia Date: Fri, 28 Jan 2022 21:58:41 +0800 Subject: [PATCH 18/20] chore(connect): fix spelling mistake golangci-lint --- internal/service/connect/routing_profile_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/connect/routing_profile_test.go b/internal/service/connect/routing_profile_test.go index eb9f7680fcf..32af07a23b5 100644 --- a/internal/service/connect/routing_profile_test.go +++ b/internal/service/connect/routing_profile_test.go @@ -550,7 +550,7 @@ func testAccRoutingProfileQueueConfig2(rName, rName2, rName3, rName4, label stri resource "aws_connect_queue" "test" { instance_id = aws_connect_instance.test.id name = %[2]q - description = "Additonal queue to routing profile queue config" + description = "Additional queue to routing profile queue config" hours_of_operation_id = data.aws_connect_hours_of_operation.test.hours_of_operation_id } From e7039fdb132d186c42989643e9c742d09b7bd9ed Mon Sep 17 00:00:00 2001 From: GlennChia Date: Wed, 2 Feb 2022 17:39:58 +0800 Subject: [PATCH 19/20] fix(connect): lint errors, change tfawserr package --- internal/service/connect/routing_profile.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/connect/routing_profile.go b/internal/service/connect/routing_profile.go index d79ae8d1ba5..398355f034b 100644 --- a/internal/service/connect/routing_profile.go +++ b/internal/service/connect/routing_profile.go @@ -8,7 +8,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/connect" - "github.com/hashicorp/aws-sdk-go-base/tfawserr" + "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" From 658fe76822a3d2fcdbaf31c909a47903873ef25a Mon Sep 17 00:00:00 2001 From: GlennChia Date: Tue, 1 Mar 2022 00:57:18 +0800 Subject: [PATCH 20/20] fix(connect): semgrep ci errors --- internal/service/connect/routing_profile.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/connect/routing_profile.go b/internal/service/connect/routing_profile.go index 398355f034b..65368b28237 100644 --- a/internal/service/connect/routing_profile.go +++ b/internal/service/connect/routing_profile.go @@ -206,7 +206,7 @@ func resourceRoutingProfileRead(ctx context.Context, d *schema.ResourceData, met RoutingProfileId: aws.String(routingProfileID), }) - if !d.IsNewResource() && tfawserr.ErrMessageContains(err, connect.ErrCodeResourceNotFoundException, "") { + if !d.IsNewResource() && tfawserr.ErrCodeEquals(err, connect.ErrCodeResourceNotFoundException) { log.Printf("[WARN] Connect Routing Profile (%s) not found, removing from state", d.Id()) d.SetId("") return nil