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
7.98k stars 968 forks source link

Merging terraform.required_providers #2470

Open yordis opened 1 year ago

yordis commented 1 year ago

I have the following file system structure

.
├── digitalocean
│ └── mybusiness
│     ├── genesis
│     │ ├── terragrunt.hcl
│     └── shared
│         └── k8s
│             └── shared-1
│                 ├── base
│                 │ ├── terragrunt.hcl # I need to configure terraform block here
│                 └── provider.hcl # I need to configure terraform block here
└── terragrunt.hcl # I need to configure terraform block here

I need to be able to configure the terraform block at multiple levels. Ideally, setting up terraform.required_version is always the same for all of them; but the difficulty comes with setting up terraform.required_providers because it depends on the project.

Maybe have something similar to remote_state but for the terraform block.

Example:

# terragrunt.hcl
terraform_better_name_because_it_conflicts {
  config = {
    required_version = "1.2.4"
  }
  generate = {
    path      = "providers.tf"
    if_exists = "skip"
    # ....
  }
}
# digitalocean/mybusiness/terragrunt.hcl
terraform_better_name_because_it_conflicts {
  config = {
    required_providers {
      digitalocean = {
        source  = "digitalocean/digitalocean"
        version = "2.23.0"
      }
    }
  }
}
# digitalocean/mybusiness/shared/k8s/shared-1/terragrunt.hcl
terraform_better_name_because_it_conflicts {
  config = {
    required_providers {
      kubernetes = {
        source  = "hashicorp/kubernetes"
        version = "2.15.0"
      }
      helm = {
        source  = "hashicorp/helm"
        version = "2.7.1"
      }
   }
  }
}
# digitalocean/mybusiness/shared/k8s/shared-1/base/terragrunt.hcl
terraform_better_name_because_it_conflicts {
  config = {
    required_providers {
      tls = {
        source  = "hashicorp/tls"
        version = "4.0.4"
      }
   }
  }
}

Merging all those configs would be an ideal, or a similar experience.

simonholt commented 1 year ago

I'm not sure this is entirely the same as my use case, but if it is, I solved is using override files. Each of my providers looks something like this:

generate "aws_provider" {
  path      = "_aws_provider.tf"
  if_exists = "overwrite_terragrunt"
  contents  = <<EOF
provider "aws" {
...
}
EOF
}
generate "aws_provider_required_providers" {
  path      = "_aws_provider_override.tf"
  if_exists = "overwrite_terragrunt"
  contents  = <<EOF
terraform {
  required_providers {
    aws = {
      source = "hashicorp/aws"
      version = "~> 4.32"
    }
  }
}
EOF
}

Meanwhile, my backend.hcl looks like this, and it's this that defines terraform required_version:

generate "backend" {
  path      = "_backend.tf"
  if_exists = "overwrite_terragrunt"
  contents  = <<EOF
terraform {
  required_version = ">= 1.2.9"
  backend "s3" {
    bucket         = "my-tf-bucket"
    key            = "${lower(trimprefix(path_relative_to_include(), "../"))}.tfstate"
    region         = "eu-west-1"
    dynamodb_table = "my-state-lock"
  }
}
EOF
}
yordis commented 1 year ago

@simonholt I am not sure if that were the same use case. You would need more than one terraform.required_providers block code to be generated.

Being said, I may be wrong!

yordis commented 5 months ago

@denis256 do you know which files I could visit to dig into how to add this feature?