< Home

A list of frequently used snippets I use during deployments

RDS Enable/Disable protection

Disable

Sometimes… well, we screwed something up and need to recreate an environment. We do this with a simple terraform destroy but get stuck due to deletion protections.

This snippet quickly disables all RDS deletion protections:

aws rds describe-db-instances --query "DBInstances[*].DBInstanceIdentifier" --output text | tr '\t' '\n' | while read -r db; do aws rds modify-db-instance --db-instance-identifier $db --apply-immediately --no-deletion-protection ; done

Enable

Wait, who turned off deletion protection? Are they insane?!

Turn it back on!

aws rds describe-db-instances --query "DBInstances[*].DBInstanceIdentifier" --output text | tr '\t' '\n' | while read -r db; do aws rds modify-db-instance --db-instance-identifier $db --apply-immediately --deletion-protection ; done

ELB Enable/Disable protection

Disable

Sometimes… well, we screwed something up and need to recreate an environment. We do this with a simple terraform destroy but get stuck due to deletion protections.

This snippet quickly disables all ALB and NLB deletion protections:

aws elbv2 describe-load-balancers --query "LoadBalancers[*].LoadBalancerArn" --output text | tr '\t' '\n' | while read -r arn; do aws elbv2 modify-load-balancer-attributes --load-balancer-arn $arn --attributes "Key=deletion_protection.enabled,Value=false"; done
aws elbv2 describe-load-balancers --query "LoadBalancers[?Type=='network'].LoadBalancerArn" --output text | tr '\t' '\n' | while read -r arn; do aws elbv2 modify-load-balancer-attributes --load-balancer-arn $arn --attributes "Key=load_balancing.cross_zone.enabled,Value=false"; done

Note: The network load balancer also requires disabling the cross_zone feature, or it will act as a secondary deletion protection.

Enable

Wait, who turned off deletion protection? Are they insane?!

Turn it back on!

aws elbv2 describe-load-balancers --query "LoadBalancers[*].LoadBalancerArn" --output text | tr '\t' '\n' | while read -r arn; do aws elbv2 modify-load-balancer-attributes --load-balancer-arn $arn --attributes "Key=deletion_protection.enabled,Value=true"; done
aws elbv2 describe-load-balancers --query "LoadBalancers[?Type=='network'].LoadBalancerArn" --output text | tr '\t' '\n' | while read -r arn; do aws elbv2 modify-load-balancer-attributes --load-balancer-arn $arn --attributes "Key=load_balancing.cross_zone.enabled,Value=true"; done

Generate a list for depends_on for the aws_api_gateway_deployment resource

Anyone who has ever created an API Gateway in Terraform has probably encountered this problem: The aws_api_gateway_deployment resource tries to be deployed before the methods and integrations are fully set up.

This snippet generates a depends_on list for the aws_api_gateway_deployment resource, ensuring deployment only happens after all integrations are created.

A frequent error is:

Error: Error creating API Gateway Deployment: BadRequestException: No integration defined for method

This occurs because the integration resource has yet to be created, but the deployment has already run.

Since integrations tend to be one of the last parts of the API Gateway setup, I chose to base the dependency list on them. While not many resources depend on aws_api_gateway_integration, it is dependent on almost everything else.

egrep -oh '"aws_api_gateway_integration" "[a-z|A-Z|_|0-9]+"' *.tf | sed -e "s/\"//g" | sed -e "s/ /./g" | sed -e "s/$/,/g"

If you have multiple API Gateways, adjust the *.tf pattern to match the correct files.

This will result in a list like:

aws_api_gateway_integration.example.example_get,
aws_api_gateway_integration.example.example_post,
aws_api_gateway_integration.example_hello.example_get,
aws_api_gateway_integration.example_world.example_put,
aws_api_gateway_integration.example_world.example_post,
aws_api_gateway_integration.example_tom.example_get,
aws_api_gateway_integration.example_tom.example_post,

You can integrate this into your aws_api_gateway_deployment:

resource "aws_api_gateway_deployment" "rest_api_gateway_deployment" {
    depends_on = [
        aws_api_gateway_integration.example.example_get,
        aws_api_gateway_integration.example.example_post,
        aws_api_gateway_integration.example_hello.example_get,
        aws_api_gateway_integration.example_world.example_put,
        aws_api_gateway_integration.example_world.example_post,
        aws_api_gateway_integration.example_tom.example_get,
        aws_api_gateway_integration.example_tom.example_post,        
    ]
    ...
}

Now, Terraform will automatically place the aws_api_gateway_deployment step almost at the end.

Update the File tag

Some of you know that I am a very declarative person when it comes to Terraform. I strongly believe that most extra work arises from having too many poorly structured modules. Too much effort is spent handling edge cases that don’t need special handling. Dynamic blocks are bad, and imperative functions ruin Terraform code.

One downside of this approach is that an environment can have a lot of files because we separate all resources into their own files for cleanliness. I personally like this setup, but it takes some getting used to.

To make this more manageable, we add a File tag to all resources, indicating the filename that holds the resource. However, since IT people are generally lazy, they never update this manually. While Terraform doesn’t care where resources are placed, humans do.

So, here’s a one-liner that goes over all .tf files and corrects the File tag—but only for resources that already have a File tag present:

for file in *.tf; do gsed -i -r "s/(File\s+=\s+\").*\"/\1${file}\"/g" $file; done;
< Home