Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jamengual/6198224a42e28fc33d83b4ae7f38d051 to your computer and use it in GitHub Desktop.
Save jamengual/6198224a42e28fc33d83b4ae7f38d051 to your computer and use it in GitHub Desktop.
Accidentally abort a large terragrunt run?

Oops, now you've got a bunch of locked modules. Here's a brute force method to remove every lock from dynamodb. Use this with caution.

Lets say your terraform is configured like this:

terraform {
  required_version = "= 1.0.8"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 3.60"
    }
  }
  backend "s3" {
    bucket         = "my-terraform-bucket"
    region         = "us-east-1"
    key            = "my-terraform-module"
    dynamodb_table = "terraform-lock"
  }
}

List all locks

Terraform will leave two types of entries in dynamodb:

  1. The path is locked:
{
  "LockID": {"S": "my-terraform-bucket/my-terraform-module"}
  "Info": {"S": "{\"ID\":\"abc-123-def-456\",\"Operation\":\"OperationTypePlan\",\"Info\":\"\",\"Who\":\"jim@COMPY9000\",\"Version\":\"1.0.8\",\"Created\":\"2591-09-30T02:00:03.4748211Z\",\"Path\":\"my-terraform-bucket/my-terraform-module\"}",
}
  1. The path is not locked:
{
  "LockID": {"S": "my-terraform-bucket/my-terraform-module"}
  "Digest": {"S": "abc1234567",
}

Filter for just those entries with "Info" keys:

  aws dynamodb scan \
    --table-name 'terraform-lock' \
    --filter-expression 'begins_with(LockID, :lock_id)' \
    --expression-attribute-values '{":lock_id": {"S": "my-terraform-bucket"}}' \
    --query 'Items[?Info].Info.S' \
    --output text | jq

Parse Info and further filter.

The Info key is stringified JSON. Parse it and filter it by what you want. Here, I'm searching for my username@my-compy.

You can use jq or anything. Just output the Path at the end.

  aws dynamodb scan \
    --table-name 'terraform-lock' \
    --filter-expression 'begins_with(LockID, :lock_id)' \
    --expression-attribute-values '{":lock_id": {"S": "my-terraform-bucket"}}' \
    --query 'Items[?Info].Info.S' \
    --output text | jq --raw-olutput 'if .Who == "jim@COMPY9000" then .Path else "" end'

Wrap the whole thing in a BASH list comprehension

  • Ctrl + A to move cursor to the beginning
  • for i in $(
  • Ctrl + E to move cursor to the end
  • ); do echo $i; done
  • Enter to validate that you've got your list of locks to delete
 for i in $(aws dynamodb scan \
    --table-name 'terraform-lock' \
    --filter-expression 'begins_with(LockID, :lock_id)' \
    --expression-attribute-values '{":lock_id": {"S": "my-terraform-bucket"}}' \
    --query 'Items[?Info].Info.S' \
    --output text | jq --raw-output 'if .Who == "jim@COMPY9000" then .Path else "" end'); 
 do
   echo $i;
 done

Delete the locks

Hope the previous step looked good, now it's time to delete those entries!

 for i in $(aws dynamodb scan \
    --table-name 'terraform-lock' \
    --filter-expression 'begins_with(LockID, :lock_id)' \
    --expression-attribute-values '{":lock_id": {"S": "my-terraform-bucket"}}' \
    --query 'Items[?Info].Info.S' \
    --output text | jq --raw-output 'if .Who == "jim@COMPY9000" then .Path else "" end'); 
 do;
   aws dynamodb delete-item --table-name 'terraform-lock' --key '{"LockID":{"S":"'$i'"}}';
 done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment