Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

targeting all resources exept one in terraform(the opposite of "-target" parameter)

I have at least 20 resources managed by my terraform configuration, i want to deploy all my resources exept one, i know that i can add "-target" parameter, but i have to specify the name of all resources(name of at least 20 resources) to be targeted in "-target" for me it's an issue because i often add/remove resources in my terraform configuration, so i need if there is a solution like the opposite of "-target" to specify only a resource to be ignored when applying terraform configuration.

PS: i don't want to delete my resource configuration to be ignored

like image 820
JSecurity Avatar asked Jan 25 '26 08:01

JSecurity


2 Answers

There currently is no feature or functionality in Terraform that enables you to exclude a resource in a plan or apply, which would be the opposite of the -target flag There is an Open Feature Request (for a few years) to get this functionality added to Terraform.

In the meantime, one of the best alternatives is to make your resources controlled using a switch.

resource "aws_instance" "example" {
  count = var.exclude_ec2_instance ? 0 : 1
  ... 
}

You can then exclude the resource given the following command:

terraform plan -out=tfplan -var='exclude_ec2_instance=true'
like image 101
Highway of Life Avatar answered Jan 27 '26 00:01

Highway of Life


There is no option to do this in terraform at the moment.
Here's a bash script I'm using as a workaround that could interest you:

terraform-apply-exclude.bash

#!/usr/bin/env bash

WORKFILE=terraform-apply-exclude-cmd.bash
RESOURCE_TO_IGNORE="$1"

reset_workfile() {
  if [ -d $WORKFILE ]; then
    rm $WORKFILE
  fi
  echo "#!/usr/bin/env bash" > $WORKFILE
  echo "terraform apply \\" >> $WORKFILE
}
write_resources_to_apply_in_workfile() {
  local RESOURCES_TO_APPLY="$1"
  # Formatting to ensure the cmd will be runnable:
  # - Single quote around all resource paths
  # - Escape double quotes if any inside the squarebrakets
  echo -e "${RESOURCES_TO_APPLY//\"/\\\"}" | xargs -I {} echo " -target '{}'  \\" >> $WORKFILE
}

# Extract all the resources that would be updated, created or destroyed
RESOURCES_TO_APPLY=$(terraform plan -no-color | grep --color=never "  # " | grep -E --color=never 'will be updated|created|destroy|must be replaced' | awk -F' ' '{print $2}' )

reset_workfile

if [ -z "$RESOURCE_TO_IGNORE" ]; then
  echo "If you want to ignore 1 resource, use the following syntax:"
  echo "$0 \"terraform_path_of_the_resource_you_want_to_ignore\"."
  echo "No resource to ignore. Still putting result in '$WORKFILE'."
  echo "If you want to exclude more than 1 resource, you can manually edit the file '$WORKFILE' and then run it."
  write_resources_to_apply_in_workfile "$RESOURCES_TO_APPLY"
  exit 1;
fi
RESOURCE_TO_IGNORE=${RESOURCE_TO_IGNORE//\"/\\\"}
RESOURCE_TO_IGNORE=${RESOURCE_TO_IGNORE//[/\\[}  # ]] Fix syntaxing highlighting for code editor
RESOURCE_TO_IGNORE=${RESOURCE_TO_IGNORE//]/\\]} 
echo "Resource to ignore: $RESOURCE_TO_IGNORE"

RESOURCES_TO_APPLY=$(echo "$RESOURCES_TO_APPLY" | grep --color=never -E -v "$RESOURCE_TO_IGNORE")
write_resources_to_apply_in_workfile "$RESOURCES_TO_APPLY"

When you use it, make sure to escape the " inside the path to the resource to be excluded.

It should look like this:

# Basic example, with no exclusion up-front (the easiest way, but a bit more manual)
$ bash terraform-apply-exclude.bash
$ <edit the 'terraform-apply-exclude-cmd.bash' file and remove the resource to exclude>
$ bash terraform-apply-exclude-cmd.bash

# Simple resource path example
$ bash terraform-apply-exclude.bash "aws_s3_bucket.bucket" 
$ bash terraform-apply-exclude-cmd.bash

# Example with a more complex setup, in this case, a module with a `for_each` meta-argument
$ bash terraform-apply-exclude.bash "module.buckets[\"vacation_pictures\"].aws_s3_bucket.bucket"
$ bash terraform-apply-exclude-cmd.bash

In case you're wondering why the complexity, and you didn't already know about count and for_each, that's why the bash string parsing is for.


Also, in case you're encountering errors, it's possible it's because we're not running the same bash, grep and/or awk version. Here are the version that I'm running with:

  • bash: GNU bash, version 5.2.2(1)-release (x86_64-pc-linux-gnu)
  • awk: GNU Awk 5.1.0, API: 3.0 (GNU MPFR 4.1.0, GNU MP 6.2.1)
  • grep: grep (GNU grep) 3.8
like image 31
Jean-Benoit Harvey Avatar answered Jan 27 '26 00:01

Jean-Benoit Harvey