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_hours_of_operation #21934

Merged
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
bd08cf3
feat(connect): add HoursOfOperation schema
GlennChia Nov 28, 2021
3e468db
feat(connect): add HoursOfOp expand, flatten conf
GlennChia Nov 28, 2021
f2f1f30
feat(connect): add HoursOfOperation ParseID func
GlennChia Nov 28, 2021
46f084c
feat(connect): add HoursOfOperation read
GlennChia Nov 28, 2021
bfa5c75
feat(connect): add HoursOfOperation create
GlennChia Nov 28, 2021
0abdf7d
feat(connect): add HoursOfOperation update
GlennChia Nov 28, 2021
0c7b72b
feat(connect): add HoursOfOperation delete
GlennChia Nov 28, 2021
22812eb
feat(connect): add aws_connect_hours_of_operation
GlennChia Nov 28, 2021
57b9aa3
test(connect): config for instance and hoursOfOp
GlennChia Nov 28, 2021
64def5e
test(connect): serialise tests
GlennChia Nov 28, 2021
9eaa6d0
test(connect): check HoursOfOperation exists
GlennChia Nov 28, 2021
eae5d4a
test(connect): check HoursOfOperation destroy
GlennChia Nov 28, 2021
b63d101
test(connect): HoursOfOperation create and update
GlennChia Nov 28, 2021
6398db7
test(connect): HoursOfOperation disappear
GlennChia Nov 28, 2021
acd187c
refactor(connect): use WithContext for delete api
GlennChia Nov 28, 2021
40360e2
test(connect): add config block for multiple days
GlennChia Nov 28, 2021
756e56a
docs(connect): add aws_connect_hours_of_operation
GlennChia Nov 28, 2021
f657cc7
chore(connect): add CHANGELOG entry
GlennChia Nov 28, 2021
34bad0b
style(connect): terraform fmt resources
GlennChia Nov 28, 2021
bdc7162
docs(connect): use terraform lang in code block
GlennChia Nov 28, 2021
5dad896
fix(connect): golangci-lint errors
GlennChia Nov 28, 2021
af1e815
feat(connect): add validation to attributes
GlennChia Nov 28, 2021
869e7d2
chore(connect): standardise int representation
GlennChia Dec 8, 2021
1d62b38
fix(connect): convert config list to set of maps
GlennChia Dec 8, 2021
a70f7e8
Merge branch 'main' into f-aws_connect_hours_of_operation
GlennChia Dec 10, 2021
39f0326
style(connect): make fmt
GlennChia Dec 10, 2021
38dc7d0
Merge branch 'main' into f-aws_connect_hours_of_operation
GlennChia Dec 10, 2021
46d3ab2
removed validation based on service quotas (adjustable).
AdamTylerLynch Dec 10, 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
3 changes: 3 additions & 0 deletions .changelog/21934.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:new-resource
aws_connect_hours_of_operation
```
7 changes: 4 additions & 3 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -955,9 +955,10 @@ func Provider() *schema.Provider {
"aws_config_organization_managed_rule": configservice.ResourceOrganizationManagedRule(),
"aws_config_remediation_configuration": configservice.ResourceRemediationConfiguration(),

"aws_connect_bot_association": connect.ResourceBotAssociation(),
"aws_connect_contact_flow": connect.ResourceContactFlow(),
"aws_connect_instance": connect.ResourceInstance(),
"aws_connect_bot_association": connect.ResourceBotAssociation(),
"aws_connect_contact_flow": connect.ResourceContactFlow(),
"aws_connect_hours_of_operation": connect.ResourceHoursOfOperation(),
"aws_connect_instance": connect.ResourceInstance(),

"aws_cur_report_definition": cur.ResourceReportDefinition(),

Expand Down
352 changes: 352 additions & 0 deletions internal/service/connect/hours_of_operation.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,352 @@
package connect

import (
"bytes"
"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"
"github.com/hashicorp/terraform-provider-aws/internal/create"
tftags "github.com/hashicorp/terraform-provider-aws/internal/tags"
)

func ResourceHoursOfOperation() *schema.Resource {
return &schema.Resource{
CreateContext: resourceHoursOfOperationCreate,
ReadContext: resourceHoursOfOperationRead,
UpdateContext: resourceHoursOfOperationUpdate,
DeleteContext: resourceHoursOfOperationDelete,
Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},
Timeouts: &schema.ResourceTimeout{
Create: schema.DefaultTimeout(connectHoursOfOperationCreatedTimeout),
Delete: schema.DefaultTimeout(connectHoursOfOperationDeletedTimeout),
},
Schema: map[string]*schema.Schema{
"config": {
GlennChia marked this conversation as resolved.
Show resolved Hide resolved
Type: schema.TypeSet,
Required: true,
MinItems: 0,
MaxItems: 100,
GlennChia marked this conversation as resolved.
Show resolved Hide resolved
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"day": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringInSlice(connect.HoursOfOperationDays_Values(), false),
},
"end_time": {
Type: schema.TypeList,
MaxItems: 1,
Required: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"hours": {
Type: schema.TypeInt,
Required: true,
},
"minutes": {
Type: schema.TypeInt,
Required: true,
},
},
},
},
"start_time": {
Type: schema.TypeList,
MaxItems: 1,
Required: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"hours": {
Type: schema.TypeInt,
Required: true,
},
"minutes": {
Type: schema.TypeInt,
Required: true,
},
},
},
},
},
},
Set: func(v interface{}) int {
var buf bytes.Buffer
m := v.(map[string]interface{})
buf.WriteString(m["day"].(string))
buf.WriteString(fmt.Sprintf("%+v", m["end_time"].([]interface{})))
buf.WriteString(fmt.Sprintf("%+v", m["start_time"].([]interface{})))
return create.StringHashcode(buf.String())
},
},
"description": {
GlennChia marked this conversation as resolved.
Show resolved Hide resolved
Type: schema.TypeString,
Optional: true,
ValidateFunc: validation.StringLenBetween(1, 250),
},
"hours_of_operation_arn": {
Type: schema.TypeString,
Computed: true,
},
"hours_of_operation_id": {
Type: schema.TypeString,
Computed: true,
},
"instance_id": {
Type: schema.TypeString,
Required: true,
},
"name": {
GlennChia marked this conversation as resolved.
Show resolved Hide resolved
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringLenBetween(1, 127),
},
"tags": tftags.TagsSchema(),
"tags_all": tftags.TagsSchemaComputed(),
"time_zone": {
Type: schema.TypeString,
Required: true,
},
},
}
}

func resourceHoursOfOperationCreate(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)

config := expandConfigs(d.Get("config").(*schema.Set).List())

input := &connect.CreateHoursOfOperationInput{
Config: config,
InstanceId: aws.String(instanceID),
Name: aws.String(name),
TimeZone: aws.String(d.Get("time_zone").(string)),
}

if v, ok := d.GetOk("description"); ok {
input.Description = aws.String(v.(string))
}

if len(tags) > 0 {
input.Tags = Tags(tags.IgnoreAWS())
}

log.Printf("[DEBUG] Creating Connect Hours of Operation %s", input)
output, err := conn.CreateHoursOfOperationWithContext(ctx, input)

if err != nil {
return diag.FromErr(fmt.Errorf("error creating Connect Hours of Operation (%s): %w", name, err))
}

if output == nil {
return diag.FromErr(fmt.Errorf("error creating Connect Hours of Operation (%s): empty output", name))
}

d.SetId(fmt.Sprintf("%s:%s", instanceID, aws.StringValue(output.HoursOfOperationId)))
GlennChia marked this conversation as resolved.
Show resolved Hide resolved

return resourceHoursOfOperationRead(ctx, d, meta)
}

func resourceHoursOfOperationRead(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, hoursOfOperationID, err := HoursOfOperationParseID(d.Id())

if err != nil {
return diag.FromErr(err)
}

resp, err := conn.DescribeHoursOfOperationWithContext(ctx, &connect.DescribeHoursOfOperationInput{
HoursOfOperationId: aws.String(hoursOfOperationID),
InstanceId: aws.String(instanceID),
})

if !d.IsNewResource() && tfawserr.ErrMessageContains(err, connect.ErrCodeResourceNotFoundException, "") {
log.Printf("[WARN] Connect Hours of Operation (%s) not found, removing from state", d.Id())
d.SetId("")
return nil
}

if err != nil {
return diag.FromErr(fmt.Errorf("error getting Connect Hours of Operation (%s): %w", d.Id(), err))
}

if resp == nil || resp.HoursOfOperation == nil {
return diag.FromErr(fmt.Errorf("error getting Connect Hours of Operation (%s): empty response", d.Id()))
}

if err := d.Set("config", flattenConfigs(resp.HoursOfOperation.Config)); err != nil {
return diag.FromErr(err)
}

d.Set("hours_of_operation_arn", resp.HoursOfOperation.HoursOfOperationArn)
d.Set("hours_of_operation_id", resp.HoursOfOperation.HoursOfOperationId)
d.Set("instance_id", instanceID)
d.Set("description", resp.HoursOfOperation.Description)
d.Set("name", resp.HoursOfOperation.Name)
d.Set("time_zone", resp.HoursOfOperation.TimeZone)

tags := KeyValueTags(resp.HoursOfOperation.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 resourceHoursOfOperationUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
conn := meta.(*conns.AWSClient).ConnectConn

instanceID, hoursOfOperationID, err := HoursOfOperationParseID(d.Id())

if err != nil {
return diag.FromErr(err)
}

input := &connect.UpdateHoursOfOperationInput{
HoursOfOperationId: aws.String(hoursOfOperationID),
InstanceId: aws.String(instanceID),
}

if d.HasChange("config") {
config := expandConfigs(d.Get("config").(*schema.Set).List())
input.Config = config
}

if d.HasChange("name") {
input.Name = aws.String(d.Get("name").(string))
}

if d.HasChange("description") {
input.Description = aws.String(d.Get("description").(string))
}

if d.HasChange("time_zone") {
input.TimeZone = aws.String(d.Get("time_zone").(string))
}

_, err = conn.UpdateHoursOfOperationWithContext(ctx, input)

if err != nil {
return diag.FromErr(fmt.Errorf("[ERROR] Error updating HoursOfOperation (%s): %w", d.Id(), err))
}

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 resourceHoursOfOperationRead(ctx, d, meta)
}

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

instanceID, hoursOfOperationID, err := HoursOfOperationParseID(d.Id())

if err != nil {
return diag.FromErr(err)
}

_, err = conn.DeleteHoursOfOperationWithContext(ctx, &connect.DeleteHoursOfOperationInput{
HoursOfOperationId: aws.String(hoursOfOperationID),
InstanceId: aws.String(instanceID),
})

if err != nil {
return diag.FromErr(fmt.Errorf("error deleting HoursOfOperation (%s): %w", d.Id(), err))
}

return nil
}

func expandConfigs(configs []interface{}) []*connect.HoursOfOperationConfig {
if len(configs) == 0 {
return nil
}

hoursOfOperationConfigs := []*connect.HoursOfOperationConfig{}
for _, config := range configs {
data := config.(map[string]interface{})
hoursOfOperationConfig := &connect.HoursOfOperationConfig{
Day: aws.String(data["day"].(string)),
}

tet := data["end_time"].([]interface{})
vet := tet[0].(map[string]interface{})
et := connect.HoursOfOperationTimeSlice{
Hours: aws.Int64(int64(vet["hours"].(int))),
Minutes: aws.Int64(int64(vet["minutes"].(int))),
}
hoursOfOperationConfig.EndTime = &et

tst := data["start_time"].([]interface{})
vst := tst[0].(map[string]interface{})
st := connect.HoursOfOperationTimeSlice{
Hours: aws.Int64(int64(vst["hours"].(int))),
Minutes: aws.Int64(int64(vst["minutes"].(int))),
}
hoursOfOperationConfig.StartTime = &st

hoursOfOperationConfigs = append(hoursOfOperationConfigs, hoursOfOperationConfig)
}

return hoursOfOperationConfigs
}

func flattenConfigs(configs []*connect.HoursOfOperationConfig) []interface{} {
configsList := []interface{}{}
for _, config := range configs {
values := map[string]interface{}{}
values["day"] = aws.StringValue(config.Day)

et := map[string]interface{}{
"hours": aws.Int64Value(config.EndTime.Hours),
"minutes": aws.Int64Value(config.EndTime.Minutes),
}
values["end_time"] = []interface{}{et}

st := map[string]interface{}{
"hours": aws.Int64Value(config.StartTime.Hours),
"minutes": aws.Int64Value(config.StartTime.Minutes),
}
values["start_time"] = []interface{}{st}
configsList = append(configsList, values)
}
return configsList
}

func HoursOfOperationParseID(id string) (string, string, error) {
GlennChia marked this conversation as resolved.
Show resolved Hide resolved
parts := strings.SplitN(id, ":", 2)

if len(parts) != 2 || parts[0] == "" || parts[1] == "" {
return "", "", fmt.Errorf("unexpected format of ID (%s), expected instanceID:hoursOfOperationID", id)
}

return parts[0], parts[1], nil
}
Loading