@@ -6,21 +6,24 @@ package timestreaminfluxdb
6
6
import (
7
7
"context"
8
8
"errors"
9
+ "math"
9
10
"time"
10
11
11
12
"github.com/YakDriver/regexache"
12
13
"github.com/aws/aws-sdk-go-v2/aws"
13
14
"github.com/aws/aws-sdk-go-v2/service/timestreaminfluxdb"
14
15
awstypes "github.com/aws/aws-sdk-go-v2/service/timestreaminfluxdb/types"
15
16
"github.com/hashicorp/terraform-plugin-framework-timeouts/resource/timeouts"
17
+ "github.com/hashicorp/terraform-plugin-framework-validators/int32validator"
16
18
"github.com/hashicorp/terraform-plugin-framework-validators/int64validator"
17
19
"github.com/hashicorp/terraform-plugin-framework-validators/listvalidator"
18
20
"github.com/hashicorp/terraform-plugin-framework-validators/setvalidator"
19
21
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
22
+ "github.com/hashicorp/terraform-plugin-framework/path"
20
23
"github.com/hashicorp/terraform-plugin-framework/resource"
21
24
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
22
25
"github.com/hashicorp/terraform-plugin-framework/resource/schema/boolplanmodifier"
23
- "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier "
26
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/int32planmodifier "
24
27
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
25
28
"github.com/hashicorp/terraform-plugin-framework/resource/schema/setplanmodifier"
26
29
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
@@ -32,7 +35,7 @@ import (
32
35
"github.com/hashicorp/terraform-provider-aws/internal/errs"
33
36
"github.com/hashicorp/terraform-provider-aws/internal/errs/fwdiag"
34
37
"github.com/hashicorp/terraform-provider-aws/internal/framework"
35
- "github.com/hashicorp/terraform-provider-aws/internal/framework/flex"
38
+ fwflex "github.com/hashicorp/terraform-provider-aws/internal/framework/flex"
36
39
fwtypes "github.com/hashicorp/terraform-provider-aws/internal/framework/types"
37
40
tftags "github.com/hashicorp/terraform-provider-aws/internal/tags"
38
41
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
@@ -68,9 +71,6 @@ func (r *resourceDBInstance) Schema(ctx context.Context, req resource.SchemaRequ
68
71
Attributes : map [string ]schema.Attribute {
69
72
names .AttrAllocatedStorage : schema.Int64Attribute {
70
73
Required : true ,
71
- PlanModifiers : []planmodifier.Int64 {
72
- int64planmodifier .RequiresReplace (),
73
- },
74
74
Validators : []validator.Int64 {
75
75
int64validator .Between (20 , 16384 ),
76
76
},
@@ -101,11 +101,8 @@ func (r *resourceDBInstance) Schema(ctx context.Context, req resource.SchemaRequ
101
101
that each data point persists). A bucket belongs to an organization.` ,
102
102
},
103
103
"db_instance_type" : schema.StringAttribute {
104
- CustomType : fwtypes .StringEnumType [awstypes.DbInstanceType ](),
105
- Required : true ,
106
- PlanModifiers : []planmodifier.String {
107
- stringplanmodifier .RequiresReplace (),
108
- },
104
+ CustomType : fwtypes .StringEnumType [awstypes.DbInstanceType ](),
105
+ Required : true ,
109
106
Description : `The Timestream for InfluxDB DB instance type to run InfluxDB on.` ,
110
107
},
111
108
"db_parameter_group_identifier" : schema.StringAttribute {
@@ -129,7 +126,6 @@ func (r *resourceDBInstance) Schema(ctx context.Context, req resource.SchemaRequ
129
126
Optional : true ,
130
127
Computed : true ,
131
128
PlanModifiers : []planmodifier.String {
132
- stringplanmodifier .RequiresReplace (),
133
129
stringplanmodifier .UseStateForUnknown (),
134
130
},
135
131
Description : `The Timestream for InfluxDB DB storage type to read and write InfluxDB data.
@@ -142,7 +138,6 @@ func (r *resourceDBInstance) Schema(ctx context.Context, req resource.SchemaRequ
142
138
Optional : true ,
143
139
Computed : true ,
144
140
PlanModifiers : []planmodifier.String {
145
- stringplanmodifier .RequiresReplace (),
146
141
stringplanmodifier .UseStateForUnknown (),
147
142
},
148
143
Description : `Specifies whether the DB instance will be deployed as a standalone instance or
@@ -183,6 +178,18 @@ func (r *resourceDBInstance) Schema(ctx context.Context, req resource.SchemaRequ
183
178
prefix included in the endpoint. DB instance names must be unique per customer
184
179
and per region.` ,
185
180
},
181
+ "network_type" : schema.StringAttribute {
182
+ CustomType : fwtypes .StringEnumType [awstypes.NetworkType ](),
183
+ Optional : true ,
184
+ Computed : true ,
185
+ PlanModifiers : []planmodifier.String {
186
+ stringplanmodifier .RequiresReplace (),
187
+ stringplanmodifier .UseStateForUnknown (),
188
+ },
189
+ Description : `Specifies whether the networkType of the Timestream for InfluxDB instance is
190
+ IPV4, which can communicate over IPv4 protocol only, or DUAL, which can communicate
191
+ over both IPv4 and IPv6 protocols.` ,
192
+ },
186
193
names .AttrTags : tftags .TagsAttribute (),
187
194
names .AttrTagsAll : tftags .TagsAttributeComputedOnly (),
188
195
"organization" : schema.StringAttribute {
@@ -211,6 +218,18 @@ func (r *resourceDBInstance) Schema(ctx context.Context, req resource.SchemaRequ
211
218
also use the InfluxDB CLI to create an operator token. These attributes will be
212
219
stored in a Secret created in AWS SecretManager in your account.` ,
213
220
},
221
+ names .AttrPort : schema.Int32Attribute {
222
+ Optional : true ,
223
+ Computed : true ,
224
+ PlanModifiers : []planmodifier.Int32 {
225
+ int32planmodifier .UseStateForUnknown (),
226
+ },
227
+ Validators : []validator.Int32 {
228
+ int32validator .Between (1024 , 65535 ),
229
+ int32validator .NoneOf (2375 , 2376 , 7788 , 7789 , 7790 , 7791 , 7792 , 7793 , 7794 , 7795 , 7796 , 7797 , 7798 , 7799 , 8090 , 51678 , 51679 , 51680 ),
230
+ },
231
+ Description : `The port number on which InfluxDB accepts connections.` ,
232
+ },
214
233
names .AttrPubliclyAccessible : schema.BoolAttribute {
215
234
Optional : true ,
216
235
Computed : true ,
@@ -349,17 +368,15 @@ func (r *resourceDBInstance) Create(ctx context.Context, req resource.CreateRequ
349
368
return
350
369
}
351
370
352
- in := timestreaminfluxdb.CreateDbInstanceInput {}
353
-
354
- resp .Diagnostics .Append (flex .Expand (ctx , plan , & in )... )
355
-
371
+ input := timestreaminfluxdb.CreateDbInstanceInput {}
372
+ resp .Diagnostics .Append (fwflex .Expand (ctx , plan , & input )... )
356
373
if resp .Diagnostics .HasError () {
357
374
return
358
375
}
359
376
360
- in .Tags = getTagsIn (ctx )
377
+ input .Tags = getTagsIn (ctx )
361
378
362
- out , err := conn .CreateDbInstance (ctx , & in )
379
+ out , err := conn .CreateDbInstance (ctx , & input )
363
380
if err != nil {
364
381
resp .Diagnostics .AddError (
365
382
create .ProblemStandardMessage (names .TimestreamInfluxDB , create .ErrActionCreating , ResNameDBInstance , plan .Name .String (), err ),
@@ -377,27 +394,26 @@ func (r *resourceDBInstance) Create(ctx context.Context, req resource.CreateRequ
377
394
}
378
395
379
396
state := plan
380
- state .ID = flex .StringToFramework (ctx , out .Id )
397
+ state .ID = fwflex .StringToFramework (ctx , out .Id )
381
398
382
399
createTimeout := r .CreateTimeout (ctx , plan .Timeouts )
383
400
output , err := waitDBInstanceCreated (ctx , conn , state .ID .ValueString (), createTimeout )
384
-
385
401
if err != nil {
402
+ resp .Diagnostics .Append (resp .State .SetAttribute (ctx , path .Root (names .AttrID ), out .Id )... )
386
403
resp .Diagnostics .AddError (
387
404
create .ProblemStandardMessage (names .TimestreamInfluxDB , create .ErrActionWaitingForCreation , ResNameDBInstance , plan .Name .String (), err ),
388
405
err .Error (),
389
406
)
390
407
return
391
408
}
392
409
393
- resp .Diagnostics .Append (flex .Flatten (ctx , output , & state )... )
394
-
410
+ resp .Diagnostics .Append (fwflex .Flatten (ctx , output , & state )... )
395
411
if resp .Diagnostics .HasError () {
396
412
return
397
413
}
398
414
399
415
// flatten using legacy since this computed output may be null
400
- state .SecondaryAvailabilityZone = flex .StringToFrameworkLegacy (ctx , output .SecondaryAvailabilityZone )
416
+ state .SecondaryAvailabilityZone = fwflex .StringToFrameworkLegacy (ctx , output .SecondaryAvailabilityZone )
401
417
402
418
resp .Diagnostics .Append (resp .State .Set (ctx , & state )... )
403
419
}
@@ -412,7 +428,6 @@ func (r *resourceDBInstance) Read(ctx context.Context, req resource.ReadRequest,
412
428
}
413
429
414
430
output , err := findDBInstanceByID (ctx , conn , state .ID .ValueString ())
415
-
416
431
if tfresource .NotFound (err ) {
417
432
resp .Diagnostics .Append (fwdiag .NewResourceNotFoundWarningDiagnostic (err ))
418
433
resp .State .RemoveResource (ctx )
@@ -427,14 +442,13 @@ func (r *resourceDBInstance) Read(ctx context.Context, req resource.ReadRequest,
427
442
return
428
443
}
429
444
430
- resp .Diagnostics .Append (flex .Flatten (ctx , output , & state )... )
431
-
445
+ resp .Diagnostics .Append (fwflex .Flatten (ctx , output , & state )... )
432
446
if resp .Diagnostics .HasError () {
433
447
return
434
448
}
435
449
436
450
// flatten using legacy since this computed output may be null
437
- state .SecondaryAvailabilityZone = flex .StringToFrameworkLegacy (ctx , output .SecondaryAvailabilityZone )
451
+ state .SecondaryAvailabilityZone = fwflex .StringToFrameworkLegacy (ctx , output .SecondaryAvailabilityZone )
438
452
439
453
resp .Diagnostics .Append (resp .State .Set (ctx , & state )... )
440
454
}
@@ -449,19 +463,22 @@ func (r *resourceDBInstance) Update(ctx context.Context, req resource.UpdateRequ
449
463
return
450
464
}
451
465
452
- if ! plan .DBParameterGroupIdentifier .Equal (state .DBParameterGroupIdentifier ) ||
453
- ! plan .LogDeliveryConfiguration .Equal (state .LogDeliveryConfiguration ) {
454
- in := timestreaminfluxdb.UpdateDbInstanceInput {
466
+ diff , d := fwflex .Diff (ctx , plan , state )
467
+ resp .Diagnostics .Append (d ... )
468
+ if resp .Diagnostics .HasError () {
469
+ return
470
+ }
471
+
472
+ if diff .HasChanges () {
473
+ input := timestreaminfluxdb.UpdateDbInstanceInput {
455
474
Identifier : plan .ID .ValueStringPointer (),
456
475
}
457
-
458
- resp .Diagnostics .Append (flex .Expand (ctx , plan , & in )... )
459
-
476
+ resp .Diagnostics .Append (fwflex .Expand (ctx , plan , & input , diff .IgnoredFieldNamesOpts ()... )... )
460
477
if resp .Diagnostics .HasError () {
461
478
return
462
479
}
463
480
464
- _ , err := conn .UpdateDbInstance (ctx , & in )
481
+ _ , err := conn .UpdateDbInstance (ctx , & input )
465
482
if err != nil {
466
483
resp .Diagnostics .AddError (
467
484
create .ProblemStandardMessage (names .TimestreamInfluxDB , create .ErrActionUpdating , ResNameDBInstance , plan .ID .String (), err ),
@@ -480,14 +497,16 @@ func (r *resourceDBInstance) Update(ctx context.Context, req resource.UpdateRequ
480
497
return
481
498
}
482
499
483
- resp .Diagnostics .Append (flex .Flatten (ctx , output , & plan )... )
484
-
500
+ resp .Diagnostics .Append (fwflex .Flatten (ctx , output , & plan )... )
485
501
if resp .Diagnostics .HasError () {
486
502
return
487
503
}
488
504
489
- // flatten using legacy since this computed output may be null
490
- plan .SecondaryAvailabilityZone = flex .StringToFrameworkLegacy (ctx , output .SecondaryAvailabilityZone )
505
+ plan .SecondaryAvailabilityZone = fwflex .StringToFrameworkLegacy (ctx , output .SecondaryAvailabilityZone )
506
+ }
507
+
508
+ if plan .SecondaryAvailabilityZone .IsUnknown () {
509
+ plan .SecondaryAvailabilityZone = state .SecondaryAvailabilityZone
491
510
}
492
511
493
512
resp .Diagnostics .Append (resp .State .Set (ctx , & plan )... )
@@ -529,6 +548,34 @@ func (r *resourceDBInstance) Delete(ctx context.Context, req resource.DeleteRequ
529
548
}
530
549
}
531
550
551
+ func (r * resourceDBInstance ) ValidateConfig (ctx context.Context , req resource.ValidateConfigRequest , resp * resource.ValidateConfigResponse ) {
552
+ var allocatedStorage types.Int64
553
+ resp .Diagnostics .Append (req .Config .GetAttribute (ctx , path .Root (names .AttrAllocatedStorage ), & allocatedStorage )... )
554
+ if resp .Diagnostics .HasError () {
555
+ return
556
+ }
557
+
558
+ if allocatedStorage .IsNull () || allocatedStorage .IsUnknown () {
559
+ return
560
+ }
561
+
562
+ if allocatedStorage .ValueInt64 () > math .MaxInt32 {
563
+ resp .Diagnostics .AddError (
564
+ "Invalid value for allocated_storage" ,
565
+ "allocated_storage was greater than the maximum allowed value for int32" ,
566
+ )
567
+ return
568
+ }
569
+
570
+ if allocatedStorage .ValueInt64 () < math .MinInt32 {
571
+ resp .Diagnostics .AddError (
572
+ "Invalid value for allocated_storage" ,
573
+ "allocated_storage was less than the minimum allowed value for int32" ,
574
+ )
575
+ return
576
+ }
577
+ }
578
+
532
579
func waitDBInstanceCreated (ctx context.Context , conn * timestreaminfluxdb.Client , id string , timeout time.Duration ) (* timestreaminfluxdb.GetDbInstanceOutput , error ) {
533
580
stateConf := & retry.StateChangeConf {
534
581
Pending : enum .Slice (awstypes .StatusCreating ),
@@ -549,7 +596,7 @@ func waitDBInstanceCreated(ctx context.Context, conn *timestreaminfluxdb.Client,
549
596
550
597
func waitDBInstanceUpdated (ctx context.Context , conn * timestreaminfluxdb.Client , id string , timeout time.Duration ) (* timestreaminfluxdb.GetDbInstanceOutput , error ) {
551
598
stateConf := & retry.StateChangeConf {
552
- Pending : enum .Slice (awstypes .StatusModifying , awstypes .StatusUpdating ),
599
+ Pending : enum .Slice (awstypes .StatusModifying , awstypes .StatusUpdating , awstypes . StatusUpdatingInstanceType , awstypes . StatusUpdatingDeploymentType ),
553
600
Target : enum .Slice (awstypes .StatusAvailable ),
554
601
Refresh : statusDBInstance (ctx , conn , id ),
555
602
Timeout : timeout ,
@@ -567,7 +614,7 @@ func waitDBInstanceUpdated(ctx context.Context, conn *timestreaminfluxdb.Client,
567
614
568
615
func waitDBInstanceDeleted (ctx context.Context , conn * timestreaminfluxdb.Client , id string , timeout time.Duration ) (* timestreaminfluxdb.GetDbInstanceOutput , error ) {
569
616
stateConf := & retry.StateChangeConf {
570
- Pending : enum .Slice (awstypes .StatusDeleting ),
617
+ Pending : enum .Slice (awstypes .StatusDeleting , awstypes . StatusDeleted ),
571
618
Target : []string {},
572
619
Refresh : statusDBInstance (ctx , conn , id ),
573
620
Timeout : timeout ,
@@ -635,8 +682,10 @@ type resourceDBInstanceData struct {
635
682
InfluxAuthParametersSecretARN types.String `tfsdk:"influx_auth_parameters_secret_arn"`
636
683
LogDeliveryConfiguration fwtypes.ListNestedObjectValueOf [logDeliveryConfigurationData ] `tfsdk:"log_delivery_configuration"`
637
684
Name types.String `tfsdk:"name"`
685
+ NetworkType fwtypes.StringEnum [awstypes.NetworkType ] `tfsdk:"network_type"`
638
686
Organization types.String `tfsdk:"organization"`
639
687
Password types.String `tfsdk:"password"`
688
+ Port types.Int32 `tfsdk:"port"`
640
689
PubliclyAccessible types.Bool `tfsdk:"publicly_accessible"`
641
690
SecondaryAvailabilityZone types.String `tfsdk:"secondary_availability_zone"`
642
691
Tags tftags.Map `tfsdk:"tags"`
0 commit comments