Skip to content

feat: Added option to ignore changes to GSIs #72

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

Conversation

lobsterdore
Copy link
Contributor

@lobsterdore lobsterdore commented May 25, 2023

Description

This relates to this issue - hashicorp/terraform-provider-aws#671.

When using autoscaling with a provisioned table that has a GSI applying a TF change whilst the indices are scaled will reset capacity, which can be dangerous. This change has an option to ignore changes to global_secondary_index, which seems to be the only way to deal with this issue at present.

Motivation and Context

Without this change, using this module in the context described above can be dangerous.

Breaking Changes

This change should be backwards compatible.

How Has This Been Tested?

  • I have updated at least one of the examples/* to demonstrate and validate my change(s)
  • I have tested and validated these changes using one or more of the provided examples/* projects
  • I have executed pre-commit run -a on my pull request

@lobsterdore
Copy link
Contributor Author

lobsterdore commented May 25, 2023

I am going to test this properly, is this sort of change acceptable at all?

Copy link
Member

@antonbabenko antonbabenko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is a valid case since there has been no visible traction for this issue in the Terraform AWS provider for the last 5 years.

@lobsterdore
Copy link
Contributor Author

I think this is a valid case since there has been no visible traction for this issue in the Terraform AWS provider for the last 5 years.

Yeah it does seem to be a long term problem! Thanks for this, I will clean up the PR and get it tested.

@lobsterdore lobsterdore force-pushed the add-ignore-changes-global-secondary-indices-option branch from 375f03d to 65b0b22 Compare May 25, 2023 14:25
@lobsterdore
Copy link
Contributor Author

I'll ping back once I've fully tested this.

@lobsterdore
Copy link
Contributor Author

Tested the autoscaling example and it's all working as expected (output attached):

> terraform apply

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # random_pet.this will be created
  + resource "random_pet" "this" {
      + id        = (known after apply)
      + length    = 2
      + separator = "-"
    }

  # module.dynamodb_table.aws_appautoscaling_policy.index_read_policy["TitleIndex"] will be created
  + resource "aws_appautoscaling_policy" "index_read_policy" {
      + alarm_arns         = (known after apply)
      + arn                = (known after apply)
      + id                 = (known after apply)
      + name               = (known after apply)
      + policy_type        = "TargetTrackingScaling"
      + resource_id        = (known after apply)
      + scalable_dimension = "dynamodb:index:ReadCapacityUnits"
      + service_namespace  = "dynamodb"

      + target_tracking_scaling_policy_configuration {
          + disable_scale_in   = false
          + scale_in_cooldown  = 0
          + scale_out_cooldown = 0
          + target_value       = 70

          + predefined_metric_specification {
              + predefined_metric_type = "DynamoDBReadCapacityUtilization"
            }
        }
    }

  # module.dynamodb_table.aws_appautoscaling_policy.index_write_policy["TitleIndex"] will be created
  + resource "aws_appautoscaling_policy" "index_write_policy" {
      + alarm_arns         = (known after apply)
      + arn                = (known after apply)
      + id                 = (known after apply)
      + name               = (known after apply)
      + policy_type        = "TargetTrackingScaling"
      + resource_id        = (known after apply)
      + scalable_dimension = "dynamodb:index:WriteCapacityUnits"
      + service_namespace  = "dynamodb"

      + target_tracking_scaling_policy_configuration {
          + disable_scale_in   = false
          + scale_in_cooldown  = 0
          + scale_out_cooldown = 0
          + target_value       = 70

          + predefined_metric_specification {
              + predefined_metric_type = "DynamoDBWriteCapacityUtilization"
            }
        }
    }

  # module.dynamodb_table.aws_appautoscaling_policy.table_read_policy[0] will be created
  + resource "aws_appautoscaling_policy" "table_read_policy" {
      + alarm_arns         = (known after apply)
      + arn                = (known after apply)
      + id                 = (known after apply)
      + name               = (known after apply)
      + policy_type        = "TargetTrackingScaling"
      + resource_id        = (known after apply)
      + scalable_dimension = "dynamodb:table:ReadCapacityUnits"
      + service_namespace  = "dynamodb"

      + target_tracking_scaling_policy_configuration {
          + disable_scale_in   = false
          + scale_in_cooldown  = 50
          + scale_out_cooldown = 40
          + target_value       = 45

          + predefined_metric_specification {
              + predefined_metric_type = "DynamoDBReadCapacityUtilization"
            }
        }
    }

  # module.dynamodb_table.aws_appautoscaling_policy.table_write_policy[0] will be created
  + resource "aws_appautoscaling_policy" "table_write_policy" {
      + alarm_arns         = (known after apply)
      + arn                = (known after apply)
      + id                 = (known after apply)
      + name               = (known after apply)
      + policy_type        = "TargetTrackingScaling"
      + resource_id        = (known after apply)
      + scalable_dimension = "dynamodb:table:WriteCapacityUnits"
      + service_namespace  = "dynamodb"

      + target_tracking_scaling_policy_configuration {
          + disable_scale_in   = false
          + scale_in_cooldown  = 50
          + scale_out_cooldown = 40
          + target_value       = 45

          + predefined_metric_specification {
              + predefined_metric_type = "DynamoDBWriteCapacityUtilization"
            }
        }
    }

  # module.dynamodb_table.aws_appautoscaling_target.index_read["TitleIndex"] will be created
  + resource "aws_appautoscaling_target" "index_read" {
      + arn                = (known after apply)
      + id                 = (known after apply)
      + max_capacity       = 30
      + min_capacity       = 10
      + resource_id        = (known after apply)
      + role_arn           = (known after apply)
      + scalable_dimension = "dynamodb:index:ReadCapacityUnits"
      + service_namespace  = "dynamodb"
      + tags_all           = (known after apply)
    }

  # module.dynamodb_table.aws_appautoscaling_target.index_write["TitleIndex"] will be created
  + resource "aws_appautoscaling_target" "index_write" {
      + arn                = (known after apply)
      + id                 = (known after apply)
      + max_capacity       = 30
      + min_capacity       = 10
      + resource_id        = (known after apply)
      + role_arn           = (known after apply)
      + scalable_dimension = "dynamodb:index:WriteCapacityUnits"
      + service_namespace  = "dynamodb"
      + tags_all           = (known after apply)
    }

  # module.dynamodb_table.aws_appautoscaling_target.table_read[0] will be created
  + resource "aws_appautoscaling_target" "table_read" {
      + arn                = (known after apply)
      + id                 = (known after apply)
      + max_capacity       = 10
      + min_capacity       = 5
      + resource_id        = (known after apply)
      + role_arn           = (known after apply)
      + scalable_dimension = "dynamodb:table:ReadCapacityUnits"
      + service_namespace  = "dynamodb"
      + tags_all           = (known after apply)
    }

  # module.dynamodb_table.aws_appautoscaling_target.table_write[0] will be created
  + resource "aws_appautoscaling_target" "table_write" {
      + arn                = (known after apply)
      + id                 = (known after apply)
      + max_capacity       = 10
      + min_capacity       = 5
      + resource_id        = (known after apply)
      + role_arn           = (known after apply)
      + scalable_dimension = "dynamodb:table:WriteCapacityUnits"
      + service_namespace  = "dynamodb"
      + tags_all           = (known after apply)
    }

  # module.dynamodb_table.aws_dynamodb_table.autoscaled_gsi_ignore[0] will be created
  + resource "aws_dynamodb_table" "autoscaled_gsi_ignore" {
      + arn              = (known after apply)
      + billing_mode     = "PROVISIONED"
      + hash_key         = "id"
      + id               = (known after apply)
      + name             = (known after apply)
      + range_key        = "title"
      + read_capacity    = 5
      + stream_arn       = (known after apply)
      + stream_enabled   = false
      + stream_label     = (known after apply)
      + stream_view_type = (known after apply)
      + tags             = (known after apply)
      + tags_all         = (known after apply)
      + write_capacity   = 5

      + attribute {
          + name = "age"
          + type = "N"
        }
      + attribute {
          + name = "id"
          + type = "N"
        }
      + attribute {
          + name = "title"
          + type = "S"
        }

      + global_secondary_index {
          + hash_key           = "title"
          + name               = "TitleIndex"
          + non_key_attributes = [
              + "id",
            ]
          + projection_type    = "INCLUDE"
          + range_key          = "age"
          + read_capacity      = 10
          + write_capacity     = 10
        }

      + point_in_time_recovery {
          + enabled = false
        }

      + server_side_encryption {
          + enabled     = false
          + kms_key_arn = (known after apply)
        }

      + timeouts {
          + create = "10m"
          + delete = "10m"
          + update = "60m"
        }

      + ttl {
          + enabled = false
        }
    }

Plan: 10 to add, 0 to change, 0 to destroy.

Changes to Outputs:
  + dynamodb_table_arn = (known after apply)
  + dynamodb_table_id  = (known after apply)

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

random_pet.this: Creating...
random_pet.this: Creation complete after 0s [id=grown-chicken]
module.dynamodb_table.aws_dynamodb_table.autoscaled_gsi_ignore[0]: Creating...
module.dynamodb_table.aws_dynamodb_table.autoscaled_gsi_ignore[0]: Still creating... [10s elapsed]
module.dynamodb_table.aws_dynamodb_table.autoscaled_gsi_ignore[0]: Creation complete after 13s [id=my-table-grown-chicken]
module.dynamodb_table.aws_appautoscaling_target.table_read[0]: Creating...
module.dynamodb_table.aws_appautoscaling_target.table_write[0]: Creating...
module.dynamodb_table.aws_appautoscaling_target.index_write["TitleIndex"]: Creating...
module.dynamodb_table.aws_appautoscaling_target.index_read["TitleIndex"]: Creating...
module.dynamodb_table.aws_appautoscaling_target.index_write["TitleIndex"]: Creation complete after 1s [id=table/my-table-grown-chicken/index/TitleIndex]
module.dynamodb_table.aws_appautoscaling_policy.index_write_policy["TitleIndex"]: Creating...
module.dynamodb_table.aws_appautoscaling_target.table_write[0]: Creation complete after 1s [id=table/my-table-grown-chicken]
module.dynamodb_table.aws_appautoscaling_target.index_read["TitleIndex"]: Creation complete after 1s [id=table/my-table-grown-chicken/index/TitleIndex]
module.dynamodb_table.aws_appautoscaling_target.table_read[0]: Creation complete after 1s [id=table/my-table-grown-chicken]
module.dynamodb_table.aws_appautoscaling_policy.table_write_policy[0]: Creating...
module.dynamodb_table.aws_appautoscaling_policy.index_read_policy["TitleIndex"]: Creating...
module.dynamodb_table.aws_appautoscaling_policy.table_read_policy[0]: Creating...
module.dynamodb_table.aws_appautoscaling_policy.index_write_policy["TitleIndex"]: Creation complete after 0s [id=DynamoDBWriteCapacityUtilization:table/my-table-grown-chicken/index/TitleIndex]
module.dynamodb_table.aws_appautoscaling_policy.table_write_policy[0]: Creation complete after 0s [id=DynamoDBWriteCapacityUtilization:table/my-table-grown-chicken]
module.dynamodb_table.aws_appautoscaling_policy.table_read_policy[0]: Creation complete after 0s [id=DynamoDBReadCapacityUtilization:table/my-table-grown-chicken]
module.dynamodb_table.aws_appautoscaling_policy.index_read_policy["TitleIndex"]: Creation complete after 0s [id=DynamoDBReadCapacityUtilization:table/my-table-grown-chicken/index/TitleIndex]

Apply complete! Resources: 10 added, 0 changed, 0 destroyed.

Outputs:

dynamodb_table_arn = "arn:aws:dynamodb:eu-west-1:xxxxxxxxx:table/my-table-grown-chicken"
dynamodb_table_id = "my-table-grown-chicken"

@lobsterdore
Copy link
Contributor Author

I've updated the README as well, let me know if it needs anymore detail @antonbabenko.

@lobsterdore lobsterdore force-pushed the add-ignore-changes-global-secondary-indices-option branch from f5b020b to 2f62e3d Compare May 25, 2023 19:02
Copy link
Member

@antonbabenko antonbabenko left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Almost perfect!

@@ -35,6 +35,13 @@ There are two separate Terraform resources used for the DynamoDB table: one is f
terraform state mv module.dynamodb_table.aws_dynamodb_table.this module.dynamodb_table.aws_dynamodb_table.autoscaled
```

**Warning: autoscaling with global secondary indexes**
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adding this note!

@lobsterdore lobsterdore force-pushed the add-ignore-changes-global-secondary-indices-option branch from 2f62e3d to af27940 Compare May 25, 2023 19:38
This relates to this issue - hashicorp/terraform-provider-aws#671.

When using autoscaling with a provisioned table that has a GSI
applying a TF change whilst the indices are scaled will reset
capacity, which can be dangerous. This change has an option
to ignore changes to global_secondary_index, which seems to be
the only way to deal with this issue at present.
@lobsterdore lobsterdore force-pushed the add-ignore-changes-global-secondary-indices-option branch from af27940 to b621b44 Compare May 25, 2023 20:06
@lobsterdore
Copy link
Contributor Author

@antonbabenko fixed those issues.

@antonbabenko antonbabenko changed the title feat: Adds Option to Ignore Changes to GSIs feat: Added option to ignore changes to GSIs May 25, 2023
@antonbabenko antonbabenko merged commit 44187e9 into terraform-aws-modules:master May 25, 2023
antonbabenko pushed a commit that referenced this pull request May 25, 2023
## [3.3.0](v3.2.0...v3.3.0) (2023-05-25)

### Features

* Added option to ignore changes to GSIs ([#72](#72)) ([44187e9](44187e9))
@antonbabenko
Copy link
Member

This PR is included in version 3.3.0 🎉

@github-actions
Copy link

I'm going to lock this pull request because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues. If you have found a problem that seems related to this change, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jun 25, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants