Skip to content

Commit e4e65a8

Browse files
author
Nikolaos Fideropoulos
committed
initial set of changes
1 parent bc9cfd5 commit e4e65a8

File tree

3 files changed

+214
-2
lines changed

3 files changed

+214
-2
lines changed

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,16 @@ need to move the old `aws_dynamodb_table` resource that is being `destroyed` to
4949
terraform state mv module.dynamodb_table.aws_dynamodb_table.autoscaled module.dynamodb_table.aws_dynamodb_table.autoscaled_ignore_gsi
5050
```
5151

52+
**Warning: AWS-managed warm throughput drift**
53+
54+
When using PAY_PER_REQUEST billing mode, AWS automatically adjusts warm throughput values for tables and GSIs based on usage patterns at no additional cost. This causes Terraform to detect drift even though no intentional changes were made. To ignore these AWS-managed adjustments while still detecting intentional configuration changes, you can enable the `ignore_warm_throughput_changes` setting.
55+
56+
**NOTE**: Setting `ignore_warm_throughput_changes` after the table is already created causes your table to be recreated. In this case, you will need to move the old `aws_dynamodb_table` resource that is being `destroyed` to the new resource that is being `created`. For example:
57+
58+
```
59+
terraform state mv module.dynamodb_table.aws_dynamodb_table.this module.dynamodb_table.aws_dynamodb_table.warm_throughput_ignore
60+
```
61+
5262
## Module wrappers
5363

5464
Users of this Terraform module can create multiple similar resources by using [`for_each` meta-argument within `module` block](https://www.terraform.io/language/meta-arguments/for_each) which became available in Terraform 0.13.

main.tf

Lines changed: 198 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
locals {
2-
dynamodb_table_arn = try(aws_dynamodb_table.this[0].arn, aws_dynamodb_table.autoscaled[0].arn, aws_dynamodb_table.autoscaled_gsi_ignore[0].arn, "")
2+
dynamodb_table_arn = try(aws_dynamodb_table.this[0].arn, aws_dynamodb_table.autoscaled[0].arn, aws_dynamodb_table.autoscaled_gsi_ignore[0].arn, aws_dynamodb_table.warm_throughput_ignore[0].arn, "")
33
}
44

55
resource "aws_dynamodb_table" "this" {
6-
count = var.create_table && !var.autoscaling_enabled ? 1 : 0
6+
count = var.create_table && !var.autoscaling_enabled && !var.ignore_warm_throughput_changes ? 1 : 0
77

88
name = var.name
99
billing_mode = var.billing_mode
@@ -435,6 +435,202 @@ resource "aws_dynamodb_table" "autoscaled_gsi_ignore" {
435435
}
436436
}
437437

438+
resource "aws_dynamodb_table" "warm_throughput_ignore" {
439+
count = var.create_table && !var.autoscaling_enabled && var.ignore_warm_throughput_changes ? 1 : 0
440+
441+
name = var.name
442+
billing_mode = var.billing_mode
443+
hash_key = var.hash_key
444+
range_key = var.range_key
445+
read_capacity = var.read_capacity
446+
write_capacity = var.write_capacity
447+
stream_enabled = var.stream_enabled
448+
stream_view_type = var.stream_view_type
449+
table_class = var.table_class
450+
deletion_protection_enabled = var.deletion_protection_enabled
451+
region = var.region
452+
restore_date_time = var.restore_date_time
453+
restore_source_name = var.restore_source_name
454+
restore_source_table_arn = var.restore_source_table_arn
455+
restore_to_latest_time = var.restore_to_latest_time
456+
457+
ttl {
458+
enabled = var.ttl_enabled
459+
attribute_name = var.ttl_attribute_name
460+
}
461+
462+
point_in_time_recovery {
463+
enabled = var.point_in_time_recovery_enabled
464+
recovery_period_in_days = var.point_in_time_recovery_period_in_days
465+
}
466+
467+
dynamic "attribute" {
468+
for_each = var.attributes
469+
470+
content {
471+
name = attribute.value.name
472+
type = attribute.value.type
473+
}
474+
}
475+
476+
dynamic "local_secondary_index" {
477+
for_each = var.local_secondary_indexes
478+
479+
content {
480+
name = local_secondary_index.value.name
481+
range_key = local_secondary_index.value.range_key
482+
projection_type = local_secondary_index.value.projection_type
483+
non_key_attributes = lookup(local_secondary_index.value, "non_key_attributes", null)
484+
}
485+
}
486+
487+
dynamic "global_secondary_index" {
488+
for_each = var.global_secondary_indexes
489+
490+
content {
491+
name = global_secondary_index.value.name
492+
hash_key = global_secondary_index.value.hash_key
493+
projection_type = global_secondary_index.value.projection_type
494+
range_key = lookup(global_secondary_index.value, "range_key", null)
495+
read_capacity = lookup(global_secondary_index.value, "read_capacity", null)
496+
write_capacity = lookup(global_secondary_index.value, "write_capacity", null)
497+
non_key_attributes = lookup(global_secondary_index.value, "non_key_attributes", null)
498+
499+
dynamic "on_demand_throughput" {
500+
for_each = try([global_secondary_index.value.on_demand_throughput], [])
501+
502+
content {
503+
max_read_request_units = try(on_demand_throughput.value.max_read_request_units, null)
504+
max_write_request_units = try(on_demand_throughput.value.max_write_request_units, null)
505+
}
506+
}
507+
508+
dynamic "warm_throughput" {
509+
for_each = try([global_secondary_index.value.warm_throughput], [])
510+
511+
content {
512+
read_units_per_second = try(warm_throughput.value.read_units_per_second, null)
513+
write_units_per_second = try(warm_throughput.value.write_units_per_second, null)
514+
}
515+
}
516+
}
517+
}
518+
519+
dynamic "replica" {
520+
for_each = var.replica_regions
521+
522+
content {
523+
region_name = replica.value.region_name
524+
kms_key_arn = lookup(replica.value, "kms_key_arn", null)
525+
propagate_tags = lookup(replica.value, "propagate_tags", null)
526+
point_in_time_recovery = lookup(replica.value, "point_in_time_recovery", null)
527+
deletion_protection_enabled = lookup(replica.value, "deletion_protection_enabled", null)
528+
consistency_mode = try(replica.value.consistency_mode, null)
529+
}
530+
}
531+
532+
server_side_encryption {
533+
enabled = var.server_side_encryption_enabled
534+
kms_key_arn = var.server_side_encryption_kms_key_arn
535+
}
536+
537+
dynamic "import_table" {
538+
for_each = length(var.import_table) > 0 ? [var.import_table] : []
539+
540+
content {
541+
input_format = import_table.value.input_format
542+
input_compression_type = try(import_table.value.input_compression_type, null)
543+
544+
dynamic "input_format_options" {
545+
for_each = try([import_table.value.input_format_options], [])
546+
547+
content {
548+
549+
dynamic "csv" {
550+
for_each = try([input_format_options.value.csv], [])
551+
552+
content {
553+
delimiter = try(csv.value.delimiter, null)
554+
header_list = try(csv.value.header_list, null)
555+
}
556+
}
557+
}
558+
}
559+
560+
s3_bucket_source {
561+
bucket = import_table.value.bucket
562+
bucket_owner = try(import_table.value.bucket_owner, null)
563+
key_prefix = try(import_table.value.key_prefix, null)
564+
}
565+
}
566+
}
567+
568+
dynamic "on_demand_throughput" {
569+
for_each = length(var.on_demand_throughput) > 0 ? [var.on_demand_throughput] : []
570+
571+
content {
572+
max_read_request_units = try(on_demand_throughput.value.max_read_request_units, null)
573+
max_write_request_units = try(on_demand_throughput.value.max_write_request_units, null)
574+
}
575+
}
576+
577+
dynamic "warm_throughput" {
578+
for_each = length(var.warm_throughput) > 0 ? [var.warm_throughput] : []
579+
580+
content {
581+
read_units_per_second = try(warm_throughput.value.read_units_per_second, null)
582+
write_units_per_second = try(warm_throughput.value.write_units_per_second, null)
583+
}
584+
}
585+
586+
dynamic "global_table_witness" {
587+
for_each = var.global_table_witness != null ? [var.global_table_witness] : []
588+
589+
content {
590+
region_name = global_table_witness.value.region_name
591+
}
592+
}
593+
594+
tags = merge(
595+
var.tags,
596+
{
597+
"Name" = format("%s", var.name)
598+
},
599+
)
600+
601+
timeouts {
602+
create = lookup(var.timeouts, "create", null)
603+
delete = lookup(var.timeouts, "delete", null)
604+
update = lookup(var.timeouts, "update", null)
605+
}
606+
607+
lifecycle {
608+
ignore_changes = [
609+
global_secondary_index[0].warm_throughput,
610+
global_secondary_index[1].warm_throughput,
611+
global_secondary_index[2].warm_throughput,
612+
global_secondary_index[3].warm_throughput,
613+
global_secondary_index[4].warm_throughput,
614+
global_secondary_index[5].warm_throughput,
615+
global_secondary_index[6].warm_throughput,
616+
global_secondary_index[7].warm_throughput,
617+
global_secondary_index[8].warm_throughput,
618+
global_secondary_index[9].warm_throughput,
619+
global_secondary_index[10].warm_throughput,
620+
global_secondary_index[11].warm_throughput,
621+
global_secondary_index[12].warm_throughput,
622+
global_secondary_index[13].warm_throughput,
623+
global_secondary_index[14].warm_throughput,
624+
global_secondary_index[15].warm_throughput,
625+
global_secondary_index[16].warm_throughput,
626+
global_secondary_index[17].warm_throughput,
627+
global_secondary_index[18].warm_throughput,
628+
global_secondary_index[19].warm_throughput,
629+
warm_throughput
630+
]
631+
}
632+
}
633+
438634
resource "aws_dynamodb_resource_policy" "this" {
439635
count = var.create_table && var.resource_policy != null ? 1 : 0
440636

variables.tf

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,12 @@ variable "ignore_changes_global_secondary_index" {
186186
default = false
187187
}
188188

189+
variable "ignore_warm_throughput_changes" {
190+
description = "Whether to ignore changes to warm_throughput in global secondary indices and table-level warm_throughput. Useful when AWS automatically adjusts these values based on usage patterns in PAY_PER_REQUEST mode"
191+
type = bool
192+
default = false
193+
}
194+
189195
variable "on_demand_throughput" {
190196
description = "Sets the maximum number of read and write units for the specified on-demand table"
191197
type = any

0 commit comments

Comments
 (0)