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
8k stars 971 forks source link

Mocked outputs not working for validate command #2345

Open timblaktu opened 1 year ago

timblaktu commented 1 year ago

I pushed the example code to repro the issue in this repo. It is a simplified project of mine that produces the primary error on terragrunt run-all validate:

Unsupported attribute; This object does not have an attribute named "availability_zone_names".

This is the oft-reported error-case of having not yet applied any of this infra yet, but my understanding is that validate is supposed to work in this case with mocked outputs. In fact, that's the prime use case for having mocked outputs. (Right?)

.  <---- Repo root dir has no config, just a container
├── globals.hcl
├── modules  <------------- No config, just a container
│   ├── terragrunt.hcl      Empty file
│   ├── account  <--------- No config, just a container
│   │   ├── data
│   │   │   ├── main.tf
│   │   │   └── terragrunt.hcl
│   │   └── terragrunt.hcl        # Empty
│   ├── region  <----------- No config, just a container
│   │   ├── data
│   │   │   ├── main.tf
│   │   │   └── terragrunt.hcl
│   │   └── terragrunt.hcl        # Empty
│   └── vpc
│       └── terragrunt.hcl
├── script  <--------------   All modules need access to
│   └── before-hook.sh      # the before_hook in script/
├── terraform.tfstate.d
│   └── proto67
└── terragrunt.hcl

I feel I have tried all obvious permutations of specifying these paths in my .hcl files:

  1. terraform.source
  2. terraform.before_hook.execute
  3. dependency.config_path

and using all various ways of specifying a path, e.g. for modules/region/data:

a. "../../..//modules/region/data" b. "${get_parent_terragrunt_dir()}//modules/region/data" c. "${get_terragrunt_dir()}" # I know this one's incorrect

I now always use the infamous double-slash in terraform.source, but the requirements around its placement is still quite fuzzy.

What IS clear is that regardless of the source being local or remote, the // MUST be early enough in the path to enable terragrunt to copy from the correct node in the directory tree to provide all code needed to be referenced in the temp dir that it runs from.

Bringing all these pieces and mocks together.. Although now that I'm:

  1. Using the double-slash correctly, which in my case means always putting it just before //modules so that script/before_hook.sh and friends can be accessed from the terragrunt temp/cache dir for all modules
  2. Using relative paths (a. above) everywhere
  3. Using dependency mocking religiously (I think):
    1. mock_outputs in all dependency stanzas.
    2. NOT using skip_outputs in ANYdependency stanzas.
      1. ..although I've tried skipping outputs to no avail.
    3. mock_outputs_allowed_terraform_commands = ["fmt", "validate"]
    4. mock_outputs_merge_strategy_with_state = "deep_map_only"
      1. ..although I've tried "no_merge" and "shallow" to no avail

...terragrunt run-all validate is still producing unresolveable Unsupported Argument errors from terragrunt not recognizing the output name of a module declared elsewhere as a dependency, and in this example, specifically the availability_zone_names output of modules/region/data, which has appropriate mocks defined.

The full transcript of running the validate command with debug logging on is at my repo here.

denis256 commented 1 year ago

Hi, I checked mentioned repository, outputs were attempted to fetch through dependency.region_data.availability_zone_names, however, output variables are available in outputs field: dependency.region_data.availability_zone_names -> dependency.region_data.outputs.availability_zone_names

See more examples in: https://terragrunt.gruntwork.io/docs/reference/config-blocks-and-attributes/#dependency