Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

r/aws_connect_instance - add new resource #16709

Merged
merged 22 commits into from
Sep 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
dbb01ed
Feature: AWSConnectInstance Resource
abebars Dec 16, 2020
6ef35c5
Code review
abebars Feb 28, 2021
bc1cd06
Code review
abebars Feb 28, 2021
1d8b346
Fix regex
abebars Feb 28, 2021
0b686fc
Add Error Check
abebars Apr 23, 2021
c5f5209
Format changes `make fmt`
AdamTylerLynch Jul 22, 2021
6e5c378
Refactoring Connect Instance
AdamTylerLynch Jul 31, 2021
313bd21
WIP - refactoring. Need to add Create/Delete wait checks and fix AccT…
AdamTylerLynch Jul 31, 2021
1254465
WIP refactored to match default API values, AccTest_Basic working.
AdamTylerLynch Aug 4, 2021
f2d1256
fix data source acc tests
drewmullen Aug 5, 2021
be0647a
acc test for all attrs
drewmullen Aug 5, 2021
1e93156
Removed use_custom_tts_voices_enabled as it's a pre-release feature a…
AdamTylerLynch Sep 1, 2021
5865150
Combining AccTests to save resources. Fixed Formatting.
AdamTylerLynch Sep 2, 2021
8e107c8
Removed us_voices and finshed stacking AccTests
AdamTylerLynch Sep 3, 2021
b011e48
fixed spacing for linting
AdamTylerLynch Sep 3, 2021
406c9e8
Updated documentation, exposed Timeouts.
AdamTylerLynch Sep 17, 2021
d4f3b00
Fixing linting issues in Connect docs.
AdamTylerLynch Sep 17, 2021
f71a97d
Fixed hcl -> terraform
AdamTylerLynch Sep 17, 2021
4400987
Added Amazon Connect Instance changelog
AdamTylerLynch Sep 20, 2021
c313e27
add plan-time requirement for exactly-on-of argument; use pagination …
anGie44 Sep 23, 2021
08b6773
CR updates; serialize tests since max of 2 can be run in parallel
anGie44 Sep 23, 2021
823d1a7
update data source test to compare attributes with respective resource
anGie44 Sep 23, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changelog/16709.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
```release-note:new-resource
aws_connect_instance
```

```release-note:new-data-source
aws_connect_instance
```

210 changes: 210 additions & 0 deletions aws/data_source_aws_connect_instance.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
package aws

import (
"context"
"fmt"
"log"
"strconv"
"time"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/connect"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
tfconnect "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/connect"
)

func dataSourceAwsConnectInstance() *schema.Resource {
return &schema.Resource{
ReadContext: dataSourceAwsConnectInstanceRead,
Schema: map[string]*schema.Schema{
"arn": {
Type: schema.TypeString,
Computed: true,
},
"auto_resolve_best_voices_enabled": {
Type: schema.TypeBool,
Computed: true,
},
"contact_flow_logs_enabled": {
Type: schema.TypeBool,
Computed: true,
},
"contact_lens_enabled": {
Type: schema.TypeBool,
Computed: true,
},
"created_time": {
Type: schema.TypeString,
Computed: true,
},
"early_media_enabled": {
Type: schema.TypeBool,
Computed: true,
},
"identity_management_type": {
Type: schema.TypeString,
Computed: true,
},
"inbound_calls_enabled": {
Type: schema.TypeBool,
Computed: true,
},
"instance_alias": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ExactlyOneOf: []string{"instance_alias", "instance_id"},
},
"instance_id": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ExactlyOneOf: []string{"instance_id", "instance_alias"},
},
"outbound_calls_enabled": {
Type: schema.TypeBool,
Computed: true,
},
"status": {
Type: schema.TypeString,
Computed: true,
},
"service_role": {
Type: schema.TypeString,
Computed: true,
},
// "use_custom_tts_voices_enabled": {
// Type: schema.TypeBool,
// Computed: true,
// },
},
}
}

func dataSourceAwsConnectInstanceRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
conn := meta.(*AWSClient).connectconn

var matchedInstance *connect.Instance

if v, ok := d.GetOk("instance_id"); ok {
instanceId := v.(string)

input := connect.DescribeInstanceInput{
InstanceId: aws.String(instanceId),
}

log.Printf("[DEBUG] Reading Connect Instance by instance_id: %s", input)

output, err := conn.DescribeInstance(&input)

if err != nil {
return diag.FromErr(fmt.Errorf("error getting Connect Instance by instance_id (%s): %w", instanceId, err))
}

if output == nil {
return diag.FromErr(fmt.Errorf("error getting Connect Instance by instance_id (%s): empty output", instanceId))
}

matchedInstance = output.Instance

} else if v, ok := d.GetOk("instance_alias"); ok {
instanceAlias := v.(string)

instanceSummary, err := dataSourceAwsConnectGetConnectInstanceSummaryByInstanceAlias(ctx, conn, instanceAlias)

if err != nil {
return diag.FromErr(fmt.Errorf("error finding Connect Instance Summary by instance_alias (%s): %w", instanceAlias, err))
}

if instanceSummary == nil {
return diag.FromErr(fmt.Errorf("error finding Connect Instance Summary by instance_alias (%s): not found", instanceAlias))
}

matchedInstance = &connect.Instance{
Arn: instanceSummary.Arn,
CreatedTime: instanceSummary.CreatedTime,
Id: instanceSummary.Id,
IdentityManagementType: instanceSummary.IdentityManagementType,
InboundCallsEnabled: instanceSummary.InboundCallsEnabled,
InstanceAlias: instanceSummary.InstanceAlias,
InstanceStatus: instanceSummary.InstanceStatus,
OutboundCallsEnabled: instanceSummary.OutboundCallsEnabled,
ServiceRole: instanceSummary.ServiceRole,
}
}

if matchedInstance == nil {
return diag.FromErr(fmt.Errorf("no Connect Instance found for query, try adjusting your search criteria"))
}

d.SetId(aws.StringValue(matchedInstance.Id))

d.Set("arn", matchedInstance.Arn)
d.Set("created_time", matchedInstance.CreatedTime.Format(time.RFC3339))
d.Set("identity_management_type", matchedInstance.IdentityManagementType)
d.Set("inbound_calls_enabled", matchedInstance.InboundCallsEnabled)
d.Set("instance_alias", matchedInstance.InstanceAlias)
d.Set("outbound_calls_enabled", matchedInstance.OutboundCallsEnabled)
d.Set("service_role", matchedInstance.ServiceRole)
d.Set("status", matchedInstance.InstanceStatus)

for att := range tfconnect.InstanceAttributeMapping() {
value, err := dataResourceAwsConnectInstanceReadAttribute(ctx, conn, d.Id(), att)
if err != nil {
return diag.FromErr(fmt.Errorf("error reading Connect Instance (%s) attribute (%s): %w", d.Id(), att, err))
}
d.Set(tfconnect.InstanceAttributeMapping()[att], value)
}

return nil
}

func dataSourceAwsConnectGetConnectInstanceSummaryByInstanceAlias(ctx context.Context, conn *connect.Connect, instanceAlias string) (*connect.InstanceSummary, error) {
var result *connect.InstanceSummary

input := &connect.ListInstancesInput{
MaxResults: aws.Int64(tfconnect.ListInstancesMaxResults),
}

err := conn.ListInstancesPagesWithContext(ctx, input, func(page *connect.ListInstancesOutput, lastPage bool) bool {
if page == nil {
return !lastPage
}

for _, is := range page.InstanceSummaryList {
if is == nil {
continue
}

if aws.StringValue(is.InstanceAlias) == instanceAlias {
result = is
return false
}
}

return !lastPage
})

if err != nil {
return nil, err
}

return result, nil
}

func dataResourceAwsConnectInstanceReadAttribute(ctx context.Context, conn *connect.Connect, instanceID string, attributeType string) (bool, error) {
input := &connect.DescribeInstanceAttributeInput{
InstanceId: aws.String(instanceID),
AttributeType: aws.String(attributeType),
}

out, err := conn.DescribeInstanceAttributeWithContext(ctx, input)

if err != nil {
return false, err
}

result, parseErr := strconv.ParseBool(*out.Attribute.Value)
return result, parseErr
}
108 changes: 108 additions & 0 deletions aws/data_source_aws_connect_instance_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package aws

import (
"fmt"
"regexp"
"testing"

"github.com/aws/aws-sdk-go/service/connect"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)

func TestAccAwsConnectInstanceDataSource_basic(t *testing.T) {
anGie44 marked this conversation as resolved.
Show resolved Hide resolved
rName := acctest.RandomWithPrefix("datasource-test-terraform")
dataSourceName := "data.aws_connect_instance.test"
resourceName := "aws_connect_instance.test"
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ErrorCheck: testAccErrorCheck(t, connect.EndpointsID),
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccAwsConnectInstanceDataSourceConfig_nonExistentId,
ExpectError: regexp.MustCompile(`error getting Connect Instance by instance_id`),
},
{
Config: testAccAwsConnectInstanceDataSourceConfig_nonExistentAlias,
ExpectError: regexp.MustCompile(`error finding Connect Instance Summary by instance_alias`),
},
{
Config: testAccAwsConnectInstanceDataSourceConfigBasic(rName),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttrPair(resourceName, "arn", dataSourceName, "arn"),
resource.TestCheckResourceAttrPair(resourceName, "created_time", dataSourceName, "created_time"),
resource.TestCheckResourceAttrPair(resourceName, "identity_management_type", dataSourceName, "identity_management_type"),
resource.TestCheckResourceAttrPair(resourceName, "instance_alias", dataSourceName, "instance_alias"),
resource.TestCheckResourceAttrPair(resourceName, "inbound_calls_enabled", dataSourceName, "inbound_calls_enabled"),
resource.TestCheckResourceAttrPair(resourceName, "outbound_calls_enabled", dataSourceName, "outbound_calls_enabled"),
resource.TestCheckResourceAttrPair(resourceName, "contact_flow_logs_enabled", dataSourceName, "contact_flow_logs_enabled"),
resource.TestCheckResourceAttrPair(resourceName, "contact_lens_enabled", dataSourceName, "contact_lens_enabled"),
resource.TestCheckResourceAttrPair(resourceName, "auto_resolve_best_voices_enabled", dataSourceName, "auto_resolve_best_voices_enabled"),
resource.TestCheckResourceAttrPair(resourceName, "early_media_enabled", dataSourceName, "early_media_enabled"),
resource.TestCheckResourceAttrPair(resourceName, "status", dataSourceName, "status"),
resource.TestCheckResourceAttrPair(resourceName, "service_role", dataSourceName, "service_role"),
),
},
{
Config: testAccAwsConnectInstanceDataSourceConfigAlias(rName),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttrPair(resourceName, "arn", dataSourceName, "arn"),
resource.TestCheckResourceAttrPair(resourceName, "created_time", dataSourceName, "created_time"),
resource.TestCheckResourceAttrPair(resourceName, "identity_management_type", dataSourceName, "identity_management_type"),
resource.TestCheckResourceAttrPair(resourceName, "instance_alias", dataSourceName, "instance_alias"),
resource.TestCheckResourceAttrPair(resourceName, "inbound_calls_enabled", dataSourceName, "inbound_calls_enabled"),
resource.TestCheckResourceAttrPair(resourceName, "outbound_calls_enabled", dataSourceName, "outbound_calls_enabled"),
resource.TestCheckResourceAttrPair(resourceName, "contact_flow_logs_enabled", dataSourceName, "contact_flow_logs_enabled"),
resource.TestCheckResourceAttrPair(resourceName, "contact_lens_enabled", dataSourceName, "contact_lens_enabled"),
resource.TestCheckResourceAttrPair(resourceName, "auto_resolve_best_voices_enabled", dataSourceName, "auto_resolve_best_voices_enabled"),
resource.TestCheckResourceAttrPair(resourceName, "early_media_enabled", dataSourceName, "early_media_enabled"),
resource.TestCheckResourceAttrPair(resourceName, "status", dataSourceName, "status"),
resource.TestCheckResourceAttrPair(resourceName, "service_role", dataSourceName, "service_role"),
),
},
},
})
}

const testAccAwsConnectInstanceDataSourceConfig_nonExistentId = `
data "aws_connect_instance" "test" {
instance_id = "97afc98d-101a-ba98-ab97-ae114fc115ec"
}
`

const testAccAwsConnectInstanceDataSourceConfig_nonExistentAlias = `
data "aws_connect_instance" "test" {
instance_alias = "tf-acc-test-does-not-exist"
}
`

func testAccAwsConnectInstanceDataSourceConfigBasic(rName string) string {
return fmt.Sprintf(`
resource "aws_connect_instance" "test" {
instance_alias = %[1]q
identity_management_type = "CONNECT_MANAGED"
inbound_calls_enabled = true
outbound_calls_enabled = true
}

data "aws_connect_instance" "test" {
instance_id = aws_connect_instance.test.id
}
`, rName)
}

func testAccAwsConnectInstanceDataSourceConfigAlias(rName string) string {
return fmt.Sprintf(`
resource "aws_connect_instance" "test" {
instance_alias = %[1]q
identity_management_type = "CONNECT_MANAGED"
inbound_calls_enabled = true
outbound_calls_enabled = true
}

data "aws_connect_instance" "test" {
instance_alias = aws_connect_instance.test.instance_alias
}
`, rName)
}
22 changes: 22 additions & 0 deletions aws/internal/service/connect/enum.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package connect

import "github.com/aws/aws-sdk-go/service/connect"

const InstanceStatusStatusNotFound = "ResourceNotFoundException"

const (
ListInstancesMaxResults = 10
)

func InstanceAttributeMapping() map[string]string {
return map[string]string{
connect.InstanceAttributeTypeAutoResolveBestVoices: "auto_resolve_best_voices_enabled",
connect.InstanceAttributeTypeContactflowLogs: "contact_flow_logs_enabled",
connect.InstanceAttributeTypeContactLens: "contact_lens_enabled",
connect.InstanceAttributeTypeEarlyMedia: "early_media_enabled",
connect.InstanceAttributeTypeInboundCalls: "inbound_calls_enabled",
connect.InstanceAttributeTypeOutboundCalls: "outbound_calls_enabled",
// Pre-release feature requiring allow-list from AWS. Removing all functionality until feature is GA
//connect.InstanceAttributeTypeUseCustomTtsVoices: "use_custom_tts_voices_enabled",
}
}
7 changes: 7 additions & 0 deletions aws/internal/service/connect/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package connect

// Error code constants missing from AWS Go SDK:
// https://docs.aws.amazon.com/sdk-for-go/api/service/connect/#pkg-constants
const (
ErrCodeAccessDeniedException = "AccessDeniedException"
)
31 changes: 31 additions & 0 deletions aws/internal/service/connect/waiter/status.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package waiter

import (
"context"

"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/helper/resource"
tfconnect "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/connect"
)

func InstanceStatus(ctx context.Context, conn *connect.Connect, instanceId string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
input := &connect.DescribeInstanceInput{
InstanceId: aws.String(instanceId),
}

output, err := conn.DescribeInstanceWithContext(ctx, input)

if tfawserr.ErrCodeEquals(err, tfconnect.InstanceStatusStatusNotFound) {
return output, tfconnect.InstanceStatusStatusNotFound, nil
}

if err != nil {
return nil, "", err
}

return output, aws.StringValue(output.Instance.InstanceStatus), nil
}
}
Loading