Skip to content

Commit a6c5083

Browse files
authored
Merge pull request #24849 from GlennChia/f-aws_connect_vocabulary
r/aws_connect_vocabulary
2 parents bae3dc5 + 262c97a commit a6c5083

File tree

7 files changed

+659
-0
lines changed

7 files changed

+659
-0
lines changed

.changelog/24849.txt

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:new-resource
2+
aws_connect_vocabulary
3+
```

internal/provider/provider.go

+1
Original file line numberDiff line numberDiff line change
@@ -1195,6 +1195,7 @@ func Provider() *schema.Provider {
11951195
"aws_connect_user": connect.ResourceUser(),
11961196
"aws_connect_user_hierarchy_group": connect.ResourceUserHierarchyGroup(),
11971197
"aws_connect_user_hierarchy_structure": connect.ResourceUserHierarchyStructure(),
1198+
"aws_connect_vocabulary": connect.ResourceVocabulary(),
11981199

11991200
"aws_cur_report_definition": cur.ResourceReportDefinition(),
12001201

internal/service/connect/status.go

+21
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,24 @@ func statusInstance(ctx context.Context, conn *connect.Connect, instanceId strin
2828
return output, aws.StringValue(output.Instance.InstanceStatus), nil
2929
}
3030
}
31+
32+
func statusVocabulary(ctx context.Context, conn *connect.Connect, instanceId, vocabularyId string) resource.StateRefreshFunc {
33+
return func() (interface{}, string, error) {
34+
input := &connect.DescribeVocabularyInput{
35+
InstanceId: aws.String(instanceId),
36+
VocabularyId: aws.String(vocabularyId),
37+
}
38+
39+
output, err := conn.DescribeVocabularyWithContext(ctx, input)
40+
41+
if tfawserr.ErrCodeEquals(err, connect.ErrCodeResourceNotFoundException) {
42+
return output, connect.ErrCodeResourceNotFoundException, nil
43+
}
44+
45+
if err != nil {
46+
return nil, "", err
47+
}
48+
49+
return output, aws.StringValue(output.Vocabulary.State), nil
50+
}
51+
}
+240
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
package connect
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"log"
7+
"regexp"
8+
"strings"
9+
"time"
10+
11+
"github.com/aws/aws-sdk-go/aws"
12+
"github.com/aws/aws-sdk-go/service/connect"
13+
"github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr"
14+
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
15+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
16+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
17+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
18+
"github.com/hashicorp/terraform-provider-aws/internal/conns"
19+
tftags "github.com/hashicorp/terraform-provider-aws/internal/tags"
20+
"github.com/hashicorp/terraform-provider-aws/internal/verify"
21+
)
22+
23+
func ResourceVocabulary() *schema.Resource {
24+
return &schema.Resource{
25+
CreateContext: resourceVocabularyCreate,
26+
ReadContext: resourceVocabularyRead,
27+
UpdateContext: resourceVocabularyUpdate,
28+
DeleteContext: resourceVocabularyDelete,
29+
30+
Importer: &schema.ResourceImporter{
31+
StateContext: schema.ImportStatePassthroughContext,
32+
},
33+
34+
Timeouts: &schema.ResourceTimeout{
35+
Create: schema.DefaultTimeout(vocabularyCreatedTimeout),
36+
Delete: schema.DefaultTimeout(vocabularyDeletedTimeout),
37+
},
38+
39+
CustomizeDiff: verify.SetTagsDiff,
40+
41+
Schema: map[string]*schema.Schema{
42+
"arn": {
43+
Type: schema.TypeString,
44+
Computed: true,
45+
},
46+
"content": {
47+
Type: schema.TypeString,
48+
Required: true,
49+
ForceNew: true,
50+
ValidateFunc: validation.StringLenBetween(1, 60000),
51+
},
52+
"failure_reason": {
53+
Type: schema.TypeString,
54+
Computed: true,
55+
},
56+
"instance_id": {
57+
Type: schema.TypeString,
58+
Required: true,
59+
ForceNew: true,
60+
ValidateFunc: validation.StringLenBetween(1, 100),
61+
},
62+
"language_code": {
63+
Type: schema.TypeString,
64+
Required: true,
65+
ForceNew: true,
66+
ValidateFunc: validation.StringInSlice(connect.VocabularyLanguageCode_Values(), false),
67+
},
68+
"last_modified_time": {
69+
Type: schema.TypeString,
70+
Computed: true,
71+
},
72+
"name": {
73+
Type: schema.TypeString,
74+
Required: true,
75+
ForceNew: true,
76+
ValidateFunc: validation.All(
77+
validation.StringLenBetween(1, 140),
78+
validation.StringMatch(regexp.MustCompile(`^[0-9a-zA-Z._-]+`), "must contain only alphanumeric, period, underscore, and hyphen characters"),
79+
),
80+
},
81+
"state": {
82+
Type: schema.TypeString,
83+
Computed: true,
84+
},
85+
"tags": tftags.TagsSchema(),
86+
"tags_all": tftags.TagsSchemaComputed(),
87+
"vocabulary_id": {
88+
Type: schema.TypeString,
89+
Computed: true,
90+
},
91+
},
92+
}
93+
}
94+
95+
func resourceVocabularyCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
96+
conn := meta.(*conns.AWSClient).ConnectConn
97+
defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig
98+
tags := defaultTagsConfig.MergeTags(tftags.New(d.Get("tags").(map[string]interface{})))
99+
100+
instanceID := d.Get("instance_id").(string)
101+
vocabularyName := d.Get("name").(string)
102+
103+
input := &connect.CreateVocabularyInput{
104+
ClientToken: aws.String(resource.UniqueId()),
105+
InstanceId: aws.String(instanceID),
106+
Content: aws.String(d.Get("content").(string)),
107+
LanguageCode: aws.String(d.Get("language_code").(string)),
108+
VocabularyName: aws.String(vocabularyName),
109+
}
110+
111+
if len(tags) > 0 {
112+
input.Tags = Tags(tags.IgnoreAWS())
113+
}
114+
115+
log.Printf("[DEBUG] Creating Connect Vocabulary %s", input)
116+
output, err := conn.CreateVocabularyWithContext(ctx, input)
117+
118+
if err != nil {
119+
return diag.FromErr(fmt.Errorf("error creating Connect Vocabulary (%s): %w", vocabularyName, err))
120+
}
121+
122+
if output == nil {
123+
return diag.FromErr(fmt.Errorf("error creating Connect Vocabulary (%s): empty output", vocabularyName))
124+
}
125+
126+
vocabularyID := aws.StringValue(output.VocabularyId)
127+
128+
d.SetId(fmt.Sprintf("%s:%s", instanceID, vocabularyID))
129+
130+
// waiter since the status changes from CREATION_IN_PROGRESS to either ACTIVE or CREATION_FAILED
131+
if _, err := waitVocabularyCreated(ctx, conn, d.Timeout(schema.TimeoutCreate), instanceID, vocabularyID); err != nil {
132+
return diag.FromErr(fmt.Errorf("error waiting for Vocabulary (%s) creation: %w", d.Id(), err))
133+
}
134+
135+
return resourceVocabularyRead(ctx, d, meta)
136+
}
137+
138+
func resourceVocabularyRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
139+
conn := meta.(*conns.AWSClient).ConnectConn
140+
defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig
141+
ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig
142+
143+
instanceID, vocabularyID, err := VocabularyParseID(d.Id())
144+
145+
if err != nil {
146+
return diag.FromErr(err)
147+
}
148+
149+
resp, err := conn.DescribeVocabularyWithContext(ctx, &connect.DescribeVocabularyInput{
150+
InstanceId: aws.String(instanceID),
151+
VocabularyId: aws.String(vocabularyID),
152+
})
153+
154+
if !d.IsNewResource() && tfawserr.ErrCodeEquals(err, connect.ErrCodeResourceNotFoundException) {
155+
log.Printf("[WARN] Connect Vocabulary (%s) not found, removing from state", d.Id())
156+
d.SetId("")
157+
return nil
158+
}
159+
160+
if err != nil {
161+
return diag.FromErr(fmt.Errorf("error getting Connect Vocabulary (%s): %w", d.Id(), err))
162+
}
163+
164+
if resp == nil || resp.Vocabulary == nil {
165+
return diag.FromErr(fmt.Errorf("error getting Connect Vocabulary (%s): empty response", d.Id()))
166+
}
167+
168+
vocabulary := resp.Vocabulary
169+
170+
d.Set("arn", vocabulary.Arn)
171+
d.Set("content", vocabulary.Content)
172+
d.Set("failure_reason", vocabulary.FailureReason)
173+
d.Set("instance_id", instanceID)
174+
d.Set("language_code", vocabulary.LanguageCode)
175+
d.Set("last_modified_time", vocabulary.LastModifiedTime.Format(time.RFC3339))
176+
d.Set("name", vocabulary.Name)
177+
d.Set("state", vocabulary.State)
178+
d.Set("vocabulary_id", vocabulary.Id)
179+
180+
tags := KeyValueTags(vocabulary.Tags).IgnoreAWS().IgnoreConfig(ignoreTagsConfig)
181+
182+
//lintignore:AWSR002
183+
if err := d.Set("tags", tags.RemoveDefaultConfig(defaultTagsConfig).Map()); err != nil {
184+
return diag.FromErr(fmt.Errorf("error setting tags: %w", err))
185+
}
186+
187+
if err := d.Set("tags_all", tags.Map()); err != nil {
188+
return diag.FromErr(fmt.Errorf("error setting tags_all: %w", err))
189+
}
190+
191+
return nil
192+
}
193+
194+
func resourceVocabularyUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
195+
conn := meta.(*conns.AWSClient).ConnectConn
196+
197+
if d.HasChange("tags_all") {
198+
o, n := d.GetChange("tags_all")
199+
if err := UpdateTags(conn, d.Get("arn").(string), o, n); err != nil {
200+
return diag.FromErr(fmt.Errorf("error updating tags: %w", err))
201+
}
202+
}
203+
204+
return resourceVocabularyRead(ctx, d, meta)
205+
}
206+
207+
func resourceVocabularyDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
208+
conn := meta.(*conns.AWSClient).ConnectConn
209+
210+
instanceID, vocabularyID, err := VocabularyParseID(d.Id())
211+
212+
if err != nil {
213+
return diag.FromErr(err)
214+
}
215+
216+
_, err = conn.DeleteVocabularyWithContext(ctx, &connect.DeleteVocabularyInput{
217+
InstanceId: aws.String(instanceID),
218+
VocabularyId: aws.String(vocabularyID),
219+
})
220+
221+
if err != nil {
222+
return diag.FromErr(fmt.Errorf("error deleting Vocabulary (%s): %w", d.Id(), err))
223+
}
224+
225+
if _, err := waitVocabularyDeleted(ctx, conn, d.Timeout(schema.TimeoutDelete), instanceID, vocabularyID); err != nil {
226+
return diag.FromErr(fmt.Errorf("error waiting for Vocabulary (%s) deletion: %w", d.Id(), err))
227+
}
228+
229+
return nil
230+
}
231+
232+
func VocabularyParseID(id string) (string, string, error) {
233+
parts := strings.SplitN(id, ":", 2)
234+
235+
if len(parts) != 2 || parts[0] == "" || parts[1] == "" {
236+
return "", "", fmt.Errorf("unexpected format of ID (%s), expected instanceID:vocabularyID", id)
237+
}
238+
239+
return parts[0], parts[1], nil
240+
}

0 commit comments

Comments
 (0)