Skip to content

Commit 84a4f15

Browse files
authored
Merge pull request #27718 from KevinEady/f-ivs-recording_configuration
new resource: aws_ivs_recording_configuration
2 parents 262ff3e + 4d2df66 commit 84a4f15

File tree

8 files changed

+859
-1
lines changed

8 files changed

+859
-1
lines changed

.changelog/27718.txt

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

internal/provider/provider.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -1652,7 +1652,8 @@ func New(_ context.Context) (*schema.Provider, error) {
16521652
"aws_iot_topic_rule": iot.ResourceTopicRule(),
16531653
"aws_iot_topic_rule_destination": iot.ResourceTopicRuleDestination(),
16541654

1655-
"aws_ivs_playback_key_pair": ivs.ResourcePlaybackKeyPair(),
1655+
"aws_ivs_playback_key_pair": ivs.ResourcePlaybackKeyPair(),
1656+
"aws_ivs_recording_configuration": ivs.ResourceRecordingConfiguration(),
16561657

16571658
"aws_msk_cluster": kafka.ResourceCluster(),
16581659
"aws_msk_configuration": kafka.ResourceConfiguration(),

internal/service/ivs/find.go

+23
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,26 @@ func FindPlaybackKeyPairByID(ctx context.Context, conn *ivs.IVS, id string) (*iv
3232

3333
return out.KeyPair, nil
3434
}
35+
36+
func FindRecordingConfigurationByID(ctx context.Context, conn *ivs.IVS, id string) (*ivs.RecordingConfiguration, error) {
37+
in := &ivs.GetRecordingConfigurationInput{
38+
Arn: aws.String(id),
39+
}
40+
out, err := conn.GetRecordingConfigurationWithContext(ctx, in)
41+
if tfawserr.ErrCodeEquals(err, ivs.ErrCodeResourceNotFoundException) {
42+
return nil, &resource.NotFoundError{
43+
LastError: err,
44+
LastRequest: in,
45+
}
46+
}
47+
48+
if err != nil {
49+
return nil, err
50+
}
51+
52+
if out == nil || out.RecordingConfiguration == nil {
53+
return nil, tfresource.NewEmptyResultError(in)
54+
}
55+
56+
return out.RecordingConfiguration, nil
57+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,334 @@
1+
package ivs
2+
3+
import (
4+
"context"
5+
"errors"
6+
"log"
7+
"regexp"
8+
"time"
9+
10+
"github.com/aws/aws-sdk-go/aws"
11+
"github.com/aws/aws-sdk-go/service/ivs"
12+
"github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr"
13+
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
14+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
15+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
16+
"github.com/hashicorp/terraform-provider-aws/internal/conns"
17+
"github.com/hashicorp/terraform-provider-aws/internal/create"
18+
tftags "github.com/hashicorp/terraform-provider-aws/internal/tags"
19+
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
20+
"github.com/hashicorp/terraform-provider-aws/internal/verify"
21+
"github.com/hashicorp/terraform-provider-aws/names"
22+
)
23+
24+
func ResourceRecordingConfiguration() *schema.Resource {
25+
return &schema.Resource{
26+
CreateWithoutTimeout: resourceRecordingConfigurationCreate,
27+
ReadWithoutTimeout: resourceRecordingConfigurationRead,
28+
DeleteWithoutTimeout: resourceRecordingConfigurationDelete,
29+
30+
Importer: &schema.ResourceImporter{
31+
StateContext: schema.ImportStatePassthroughContext,
32+
},
33+
34+
Timeouts: &schema.ResourceTimeout{
35+
Create: schema.DefaultTimeout(10 * time.Minute),
36+
Delete: schema.DefaultTimeout(10 * time.Minute),
37+
},
38+
39+
Schema: map[string]*schema.Schema{
40+
41+
"arn": {
42+
Type: schema.TypeString,
43+
Computed: true,
44+
},
45+
"destination_configuration": {
46+
Type: schema.TypeList,
47+
Required: true,
48+
ForceNew: true,
49+
MaxItems: 1,
50+
Elem: &schema.Resource{
51+
Schema: map[string]*schema.Schema{
52+
"s3": {
53+
Type: schema.TypeList,
54+
MaxItems: 1,
55+
Required: true,
56+
Elem: &schema.Resource{
57+
Schema: map[string]*schema.Schema{
58+
"bucket_name": {
59+
Type: schema.TypeString,
60+
Required: true,
61+
ValidateFunc: validation.StringMatch(regexp.MustCompile(`^[a-z0-9-.]{3,63}$`), "must contain only lowercase alphanumeric characters, hyphen, or dot, and between 3 and 63 characters"),
62+
},
63+
},
64+
},
65+
},
66+
},
67+
},
68+
},
69+
"name": {
70+
Type: schema.TypeString,
71+
Optional: true,
72+
Computed: true,
73+
ForceNew: true,
74+
ValidateFunc: validation.StringMatch(regexp.MustCompile(`^[a-zA-Z0-9-_]{0,128}$`), "must contain only alphanumeric characters, hyphen, or underscore, and at most 128 characters"),
75+
},
76+
"recording_reconnect_window_seconds": {
77+
Type: schema.TypeInt,
78+
Optional: true,
79+
Computed: true,
80+
ForceNew: true,
81+
ValidateFunc: validation.IntBetween(0, 300),
82+
},
83+
"state": {
84+
Type: schema.TypeString,
85+
Computed: true,
86+
},
87+
"tags": tftags.TagsSchemaForceNew(),
88+
"tags_all": tftags.TagsSchemaComputed(),
89+
"thumbnail_configuration": {
90+
Type: schema.TypeList,
91+
Optional: true,
92+
Computed: true,
93+
ForceNew: true,
94+
MaxItems: 1,
95+
Elem: &schema.Resource{
96+
Schema: map[string]*schema.Schema{
97+
"recording_mode": {
98+
Type: schema.TypeString,
99+
Optional: true,
100+
Computed: true,
101+
ValidateFunc: validation.StringInSlice(ivs.RecordingMode_Values(), false),
102+
},
103+
"target_interval_seconds": {
104+
Type: schema.TypeInt,
105+
Optional: true,
106+
Computed: true,
107+
ValidateFunc: validation.IntBetween(5, 60),
108+
},
109+
},
110+
},
111+
},
112+
},
113+
114+
CustomizeDiff: verify.SetTagsDiff,
115+
}
116+
}
117+
118+
const (
119+
ResNameRecordingConfiguration = "Recording Configuration"
120+
)
121+
122+
func resourceRecordingConfigurationCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
123+
conn := meta.(*conns.AWSClient).IVSConn
124+
125+
in := &ivs.CreateRecordingConfigurationInput{
126+
DestinationConfiguration: expandDestinationConfiguration(d.Get("destination_configuration").([]interface{})),
127+
}
128+
129+
if v, ok := d.GetOk("name"); ok {
130+
in.Name = aws.String(v.(string))
131+
}
132+
133+
if v, ok := d.GetOk("recording_reconnect_window_seconds"); ok {
134+
in.RecordingReconnectWindowSeconds = aws.Int64(int64(v.(int)))
135+
}
136+
137+
defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig
138+
tags := defaultTagsConfig.MergeTags(tftags.New(d.Get("tags").(map[string]interface{})))
139+
140+
if len(tags) > 0 {
141+
in.Tags = Tags(tags.IgnoreAWS())
142+
}
143+
144+
if v, ok := d.GetOk("thumbnail_configuration"); ok {
145+
in.ThumbnailConfiguration = expandThumbnailConfiguration(v.([]interface{}))
146+
147+
if aws.StringValue(in.ThumbnailConfiguration.RecordingMode) == ivs.RecordingModeDisabled && in.ThumbnailConfiguration.TargetIntervalSeconds != nil {
148+
return diag.Errorf("thumbnail configuration target interval cannot be set if recording_mode is \"DISABLED\"")
149+
}
150+
}
151+
152+
out, err := conn.CreateRecordingConfigurationWithContext(ctx, in)
153+
if err != nil {
154+
return create.DiagError(names.IVS, create.ErrActionCreating, ResNameRecordingConfiguration, d.Get("name").(string), err)
155+
}
156+
157+
if out == nil || out.RecordingConfiguration == nil {
158+
return create.DiagError(names.IVS, create.ErrActionCreating, ResNameRecordingConfiguration, d.Get("name").(string), errors.New("empty output"))
159+
}
160+
161+
d.SetId(aws.StringValue(out.RecordingConfiguration.Arn))
162+
163+
if _, err := waitRecordingConfigurationCreated(ctx, conn, d.Id(), d.Timeout(schema.TimeoutCreate)); err != nil {
164+
return create.DiagError(names.IVS, create.ErrActionWaitingForCreation, ResNameRecordingConfiguration, d.Id(), err)
165+
}
166+
167+
return resourceRecordingConfigurationRead(ctx, d, meta)
168+
}
169+
170+
func resourceRecordingConfigurationRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
171+
conn := meta.(*conns.AWSClient).IVSConn
172+
173+
out, err := FindRecordingConfigurationByID(ctx, conn, d.Id())
174+
175+
if !d.IsNewResource() && tfresource.NotFound(err) {
176+
log.Printf("[WARN] IVS RecordingConfiguration (%s) not found, removing from state", d.Id())
177+
d.SetId("")
178+
return nil
179+
}
180+
181+
if err != nil {
182+
return create.DiagError(names.IVS, create.ErrActionReading, ResNameRecordingConfiguration, d.Id(), err)
183+
}
184+
185+
d.Set("arn", out.Arn)
186+
187+
if err := d.Set("destination_configuration", flattenDestinationConfiguration(out.DestinationConfiguration)); err != nil {
188+
return create.DiagError(names.IVS, create.ErrActionSetting, ResNameRecordingConfiguration, d.Id(), err)
189+
}
190+
191+
d.Set("name", out.Name)
192+
d.Set("recording_reconnect_window_seconds", out.RecordingReconnectWindowSeconds)
193+
d.Set("state", out.State)
194+
195+
if err := d.Set("thumbnail_configuration", flattenThumbnailConfiguration(out.ThumbnailConfiguration)); err != nil {
196+
return create.DiagError(names.IVS, create.ErrActionSetting, ResNameRecordingConfiguration, d.Id(), err)
197+
}
198+
199+
tags, err := ListTagsWithContext(ctx, conn, d.Id())
200+
if err != nil {
201+
return create.DiagError(names.IVS, create.ErrActionReading, ResNameRecordingConfiguration, d.Id(), err)
202+
}
203+
204+
defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig
205+
ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig
206+
tags = tags.IgnoreAWS().IgnoreConfig(ignoreTagsConfig)
207+
208+
if err := d.Set("tags", tags.RemoveDefaultConfig(defaultTagsConfig).Map()); err != nil {
209+
return create.DiagError(names.IVS, create.ErrActionSetting, ResNameRecordingConfiguration, d.Id(), err)
210+
}
211+
212+
if err := d.Set("tags_all", tags.Map()); err != nil {
213+
return create.DiagError(names.IVS, create.ErrActionSetting, ResNameRecordingConfiguration, d.Id(), err)
214+
}
215+
216+
return nil
217+
}
218+
219+
func resourceRecordingConfigurationDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
220+
conn := meta.(*conns.AWSClient).IVSConn
221+
222+
log.Printf("[INFO] Deleting IVS RecordingConfiguration %s", d.Id())
223+
224+
_, err := conn.DeleteRecordingConfigurationWithContext(ctx, &ivs.DeleteRecordingConfigurationInput{
225+
Arn: aws.String(d.Id()),
226+
})
227+
228+
if tfawserr.ErrCodeEquals(err, ivs.ErrCodeResourceNotFoundException) {
229+
return nil
230+
}
231+
232+
if err != nil {
233+
return create.DiagError(names.IVS, create.ErrActionDeleting, ResNameRecordingConfiguration, d.Id(), err)
234+
}
235+
236+
if _, err := waitRecordingConfigurationDeleted(ctx, conn, d.Id(), d.Timeout(schema.TimeoutDelete)); err != nil {
237+
return create.DiagError(names.IVS, create.ErrActionWaitingForDeletion, ResNameRecordingConfiguration, d.Id(), err)
238+
}
239+
240+
return nil
241+
}
242+
243+
func flattenDestinationConfiguration(apiObject *ivs.DestinationConfiguration) []interface{} {
244+
if apiObject == nil {
245+
return []interface{}{}
246+
}
247+
248+
m := map[string]interface{}{}
249+
250+
if v := apiObject.S3; v != nil {
251+
m["s3"] = flattenS3DestinationConfiguration(v)
252+
}
253+
254+
return []interface{}{m}
255+
}
256+
257+
func flattenS3DestinationConfiguration(apiObject *ivs.S3DestinationConfiguration) []interface{} {
258+
if apiObject == nil {
259+
return []interface{}{}
260+
}
261+
262+
m := map[string]interface{}{}
263+
264+
if v := apiObject.BucketName; v != nil {
265+
m["bucket_name"] = aws.StringValue(v)
266+
}
267+
268+
return []interface{}{m}
269+
}
270+
271+
func flattenThumbnailConfiguration(apiObject *ivs.ThumbnailConfiguration) []interface{} {
272+
if apiObject == nil {
273+
return []interface{}{}
274+
}
275+
276+
m := map[string]interface{}{}
277+
278+
if v := apiObject.RecordingMode; v != nil {
279+
m["recording_mode"] = aws.StringValue(v)
280+
}
281+
282+
if v := apiObject.TargetIntervalSeconds; v != nil {
283+
m["target_interval_seconds"] = aws.Int64Value(v)
284+
}
285+
286+
return []interface{}{m}
287+
}
288+
289+
func expandDestinationConfiguration(vSettings []interface{}) *ivs.DestinationConfiguration {
290+
if len(vSettings) == 0 || vSettings[0] == nil {
291+
return nil
292+
}
293+
tfMap := vSettings[0].(map[string]interface{})
294+
a := &ivs.DestinationConfiguration{}
295+
296+
if v, ok := tfMap["s3"].([]interface{}); ok && len(v) > 0 {
297+
a.S3 = expandS3DestinationConfiguration(v)
298+
}
299+
300+
return a
301+
}
302+
303+
func expandS3DestinationConfiguration(vSettings []interface{}) *ivs.S3DestinationConfiguration {
304+
if len(vSettings) == 0 || vSettings[0] == nil {
305+
return nil
306+
}
307+
308+
tfMap := vSettings[0].(map[string]interface{})
309+
a := &ivs.S3DestinationConfiguration{}
310+
311+
if v, ok := tfMap["bucket_name"].(string); ok && v != "" {
312+
a.BucketName = aws.String(v)
313+
}
314+
315+
return a
316+
}
317+
318+
func expandThumbnailConfiguration(vSettings []interface{}) *ivs.ThumbnailConfiguration {
319+
if len(vSettings) == 0 || vSettings[0] == nil {
320+
return nil
321+
}
322+
a := &ivs.ThumbnailConfiguration{}
323+
tfMap := vSettings[0].(map[string]interface{})
324+
325+
if v, ok := tfMap["recording_mode"].(string); ok && v != "" {
326+
a.RecordingMode = aws.String(v)
327+
}
328+
329+
if v, ok := tfMap["target_interval_seconds"].(int); ok {
330+
a.TargetIntervalSeconds = aws.Int64(int64(v))
331+
}
332+
333+
return a
334+
}

0 commit comments

Comments
 (0)