Skip to content

Stack generate: get_original_terragrunt_dir and get_terragrunt_dir can’t reliably resolve the current stack directory #5175

@philipmckenna-symphony

Description

@philipmckenna-symphony

Describe the bug

Functions such as get_original_terragrunt_dir and get_terragrunt_dir are not sufficient for consistently acquiring the terragrunt stack directory that is currently being generated.

i.e. when running terragrunt stack generate outside of a directory containing a terragrunt.stack.hcl during each discovered stacks generation:

  • if invoked within the locals:
    • get_original_terragrunt_dir will return the directory in which the command is being run from
    • get_terragrunt_dir will return the stack directory
  • if invoked in terragrunt config targeted via read_terragrunt_config
    • get_original_terragrunt_dir will return the directory in which the command is being run from
    • get_terragrunt_dir will return the directory of the read_terragrunt_config target

Steps To Reproduce

The following small repo provides a reproduction that can be observed.

But here is a tldr:

# live/common/stack_config.hcl
locals {
  calling_dir  = get_original_terragrunt_dir()
  stack_name   = basename(local.calling_dir)

  tags = {
    get_terragrunt_dir          = get_terragrunt_dir()
    get_original_terragrunt_dir = get_original_terragrunt_dir()
  }
}
# catalog/units/test-module/main.tf
variable "tags" {
  type = map(any)
}

variable "stack_name" {
  type = string
}

output "tags" {
  value = var.tags
}

output "stack_name" {
  value = var.stack_name
}

# catalog/units/test-module/terragrunt.hcl
terraform {
  source = "./"
}

inputs = {
  tags         = values.tags
  stack_name   = values.stack_name
}
# live/account/env/region/test1/terragrunt.stack.hcl

locals {
  common = read_terragrunt_config(find_in_parent_folders("common/stack_config.hcl"))
  values = local.common.locals
}

unit "test1" {
  source = "${get_repo_root()}/catalog/units/test-module"
  path   = "test1"

  values = local.values
}

When running terragrunt stack generate from the live directory level produces the following values:

calling_dir = "<redacted>/stacks-file-functions/live/account"
stack_name  = "live"
tags = {
  get_original_terragrunt_dir = "<redacted>/stacks-file-functions/live"
  get_terragrunt_dir          = "<redacted>/stacks-file-functions/live/common"
}

When running terragrunt stack generate from the account directory level produces the following values:

calling_dir = "<redacted>/stacks-file-functions/live/account"
stack_name  = "account"
tags = {
  get_original_terragrunt_dir = "<redacted>/stacks-file-functions/live/account"
  get_terragrunt_dir          = "<redacted>/stacks-file-functions/live/common"
}

Expected behavior

I would expect in this scenario that get_original_terragrunt_dir would always fetch the directory where read_terragrunt_config was invoked from.

I would expect that if this capability where not possible with the current functions that a new one could possibly be added for this use case, i.e. get_terragrunt_stack_dir

Must haves

  • Steps for reproduction provided.

Nice to haves

  • Terminal output
  • Screenshots

Versions

  • Terragrunt version: v0.93.7
  • OpenTofu/Terraform version: v1.9.8
  • Environment Ubuntu 24.04

Additional context

From the code I can see the following:

# config/stack.go
func ReadStackConfigFile(ctx context.Context, l log.Logger, opts *options.TerragruntOptions, filePath string, values *cty.Value) (*StackConfig, error) {
	l.Debugf("Reading Terragrunt stack config file at %s", filePath)

	stackOpts := opts.Clone()
	stackOpts.TerragruntConfigPath = filePath

	parser := NewParsingContext(ctx, l, stackOpts)

	file, err := hclparse.NewParser(parser.ParserOptions...).ParseFromFile(filePath)
	if err != nil {
		return nil, errors.New(err)
	}

	//nolint:contextcheck
	return ParseStackConfig(l, parser, opts, file, values)
}

whereby opts is cloned and stackOpts.TerragruntConfigPath is set to the filepath currently being generated.
However, for some reason unknown to me this is ignored via the get_terragrunt_dir, likely for the same reasons that made get_original_terragrunt_dir get introduced.

A few possible other options would be to explore reassigning OriginalTerragruntConfigPath and leverage get_original_terragrunt_dir or TerragruntStackConfigPath and exposing access to it via a function.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions