gruntwork-io / terragrunt

Terragrunt is a flexible orchestration tool that allows Infrastructure as Code written in OpenTofu/Terraform to scale.
https://terragrunt.gruntwork.io/
MIT License
8.04k stars 975 forks source link

Destroy executes top-most terragrunt.hcl #1891

Closed riy closed 2 years ago

riy commented 3 years ago

Terraform Version: 1.0.9 Terragrunt Version: 0.34.4

I have a problem where running... terragrunt destroy --terragrunt-working-dir ./environments/hub/eu-central-1/network ... leads to this error message:

$ terragrunt destroy --terragrunt-working-dir ./environments/
Error: Error in function call

  on environments/terragrunt.hcl line 9, in locals:
   9:   aws_accounts_vars = read_terragrunt_config(find_in_parent_folders("region.hcl"))

Call to function "find_in_parent_folders" failed: ParentFileNotFound: Could not find a region.hcl in any of the parent folders of environments/terragrunt.hcl. Cause: Traversed all the way to the root..

ERRO[0000] Encountered error while evaluating locals.
ERRO[0000] environments/terragrunt.hcl:9,46-69: Error in function call; Call to function "find_in_parent_folders" failed: ParentFileNotFound: Could not find a aws_accounts.hcl in any of the parent folders of environments/terragrunt.hcl. Cause: Traversed all the way to the root..
ERRO[0000] Unable to determine underlying exit code, so Terragrunt will exit with error code 1

This is the same error message that is shown if I make this call: terragrunt destroy --terragrunt-working-dir ./environments

So to me the call terragrunt destroy --terragrunt-working-dir ./environments/hub/eu-central-1/network looks like it will work on ./environments/hub/eu-central-1/network/terragrunt.hcl (this works fine and destroys what I want Terraform to destroy) and then (this is my assumption, as the error message looks like it) it will execute ./environments/terragrunt.hcl. Obviously the ./environments/terragrunt.hcl doesn't have any value by itself, it only makes sense if it's included by a terragrunt.hcl folder somewhere deep down. But for some reason it seems to get executed by itself as well.

The directory structure is like this:

└─ environments/
  └─ terragrunt.hcl
  └─ hub/
    └─ eu-central-1/
      └─ region.hcl
        └─ network/
          └─ terragrunt.hcl

My ./environments/hub/eu-central-1/network/terragrunt.hcl looks like this:

...
include "root" {
  path   = find_in_parent_folders()
  expose = true
}
...

My ./environments/terragrunt.hcl looks like this:

locals {
  ...
  # Automatically load region-level variables
  region_vars      = read_terragrunt_config(find_in_parent_folders("region.hcl"))
  ...
}

What confuses me is that this doesn't happen with plan or apply, but on destroy only. Is there some kind of special behaviour, something specific I have to account for when using destroy or is this a bug?

yorinasub17 commented 3 years ago

Part of this is being addressed in https://github.com/gruntwork-io/terragrunt/pull/1889. For now, the error message is just noise - it can be safely ignored.

This is caused by the new feature introduced in https://github.com/gruntwork-io/terragrunt/releases/tag/v0.33.0, where terragrunt tries to identify all the modules that depend on the module being destroyed and give you a warning. When parsing fails during the identification stage, it falls back to the previous behavior.

riy commented 3 years ago

Awesome - thank you for the quick response!

camlow325 commented 3 years ago

Thanks much for reporting this issue. We're seeing the same in our environment and can confirm that the behavior starts with the v0.33.0 release.

We've noticed one additional behavior with a run_cmd() function invoked from a local variable assignment from the terragrunt.hcl file. The target of the run_cmd() function is a shell script. The shell script has a shebang line like this in it:

#!/usr/bin/env bash

When run on macOS Big Sur (Version 11.6) during a terragrunt destroy, the shebang line seems to be ignored since the script is run from the bash executable which ships with the OS, version 3.2, rather than the one in the executable path, version 5.0. This problem only seems to happen with terragrunt destroy. The script is run under the expected version of bash, 5.0, with a terragrunt plan or terragrunt apply. In terragrunt versions 0.32.6 and earlier, the script is run under bash version 5.0 for a terragrunt destroy.

The release notes for v0.33.0 stated:

To avoid the prompt and restore previous behavior, you can pass in --terragrunt-non-interactive

Using terragrunt destroy --terragrunt-non-interactive didn't seem to make any difference in terms of the destroy problems. On v.35.4, we can still reproduce the problems with the top-most terragrunt.hcl file unexpectedly being parsed with the current Terragrunt directory being the top-most rather than the child directory and the problem of a shell script shebang not being honored for the script run via run_cmd.

I'd be happy to file a separate issue for the shebang script behavior if this would be helpful for tracking purposes. Thanks again!

brikis98 commented 2 years ago

Just hit this too. I created a small way to repro the issue: https://github.com/brikis98/temp-terragrunt-repro

With Terragrunt v0.34.3, apply works fine in the test/eu-west-1/test/services/test-service folder, but destroy shows:

Error: Error in function call

  on /private/tmp/terra/test/terragrunt.hcl line 2, in locals:
   2:   account_vars = read_terragrunt_config(find_in_parent_folders("account.hcl"))

Call to function "find_in_parent_folders" failed: ParentFileNotFound: Could not find a account.hcl in any of the parent folders of /private/tmp/terra/test/terragrunt.hcl. Cause: Traversed all the way to
the root..

ERRO[0001] Encountered error while evaluating locals.    prefix=[/private/tmp/terra/test]
WARN[0001] Failed to detect where module is used Error processing module at '/private/tmp/terra/test/terragrunt.hcl'. How this module was found: Terragrunt config file found in a subdirectory of /private/tmp/terra. Underlying error: /private/tmp/terra/test/terragrunt.hcl:2,41-64: Error in function call; Call to function "find_in_parent_folders" failed: ParentFileNotFound: Could not find a account.hcl in any of the parent folders of /private/tmp/terra/test/terragrunt.hcl. Cause: Traversed all the way to the root..
null_resource.foo: Refreshing state... [id=4521199244037115484]

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

Terraform will perform the following actions:

  # null_resource.foo will be destroyed
  - resource "null_resource" "foo" {
      - id       = "4521199244037115484" -> null
      - triggers = {
          - "aws_account_id" = "111122223333"
          - "aws_region"     = "eu-west-1"
          - "vpc_name"       = "foo-vpc"
        } -> null
    }

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

Changes to Outputs:
  - aws_account_id = "111122223333" -> null
  - aws_region     = "eu-west-1" -> null
  - vpc_name       = "foo-vpc" -> null

Do you really want to destroy all resources?
  Terraform will destroy all your managed infrastructure, as shown above.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value:

So you get a scary looking error at the top, though the code still seems to run OK.

With v0.35.9, you now get a less scary warning on destroy:

WARN[0001] Failed to detect where module is used Error processing module at '/private/tmp/terra/test/terragrunt.hcl'. How this module was found: Terragrunt config file found in a subdirectory of /private/tmp/terra. Underlying error: /private/tmp/terra/test/terragrunt.hcl:4,40-63: Error in function call; Call to function "find_in_parent_folders" failed: ParentFileNotFound: Could not find a region.hcl in any of the parent folders of /private/tmp/terra/test/terragrunt.hcl. Cause: Traversed all the way to the root..
null_resource.foo: Refreshing state... [id=6956728805374583994]

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

Terraform will perform the following actions:

  # null_resource.foo will be destroyed
  - resource "null_resource" "foo" {
      - id       = "6956728805374583994" -> null
      - triggers = {
          - "aws_account_id" = "111122223333"
          - "aws_region"     = "eu-west-1"
          - "vpc_name"       = "foo-vpc"
        } -> null
    }

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

Changes to Outputs:
  - aws_account_id = "111122223333" -> null
  - aws_region     = "eu-west-1" -> null
  - vpc_name       = "foo-vpc" -> null

Do you really want to destroy all resources?
  Terraform will destroy all your managed infrastructure, as shown above.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value:

So that's an improvement, but the warning is still quite misleading. @denis256 Any idea how to clean that up?

denis256 commented 2 years ago

Hi, will check and try to remove or reduce the log level for misleading error

brikis98 commented 2 years ago

Should be fixed by #1915 and released in https://github.com/gruntwork-io/terragrunt/releases/tag/v0.35.12.