Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Configuring multiple cloud providers - only one level of includes #3714

Open
antgel opened this issue Dec 28, 2024 · 0 comments
Open

Configuring multiple cloud providers - only one level of includes #3714

antgel opened this issue Dec 28, 2024 · 0 comments
Labels
bug Something isn't working

Comments

@antgel
Copy link

antgel commented Dec 28, 2024

Hi all,

I've been using Terragrunt for a long-time but am stumped as to the best way to implement multi-cloud infrastructure. I want to use AWS and Azure, and the logical layout looks something like:

./terragrunt.hcl
./aws
./aws/providers.hcl
./aws/main # account
./aws/main/account.hcl
./aws/main/us-east-1
./aws/main/us-east-1/region.hcl
./aws/main/us-east-1/staging
./aws/main/us-east-1/staging/env.hcl
./aws/main/us-east-1/staging/some_app
./aws/main/us-east-1/staging/some_app/terragrunt.hcl
./azure
./azure/providers.hcl
./azure/main # subscription
./azure/main/subscription.hcl
./azure/main/eastus
./azure/main/eastus/region.hcl
./azure/main/eastus/production
./azure/main/eastus/production/env.hcl
./azure/main/eastus/production/some_app
./azure/main/eastus/production/some_app/terragrunt.hcl

I've tried to be semi-inspired by https://github.com/iancoralogix/multi-cloud-terragrunt-filesystem but I'm not sure if that's the right approach. The files there include providers.hcl but nothing seems to include the root terragrunt.hcl.

I'll share some code because I think it will help you understand what I'm trying to do, even though the code doesn't work right now as either I fall into multiple includes or I can't access variables that I think I should be able to access.

terragrunt.hcl - I tried to put the generic stuff here that everything uses

locals {
  provider_vars = read_terragrunt_config(find_in_parent_folders("providers.hcl"))
  region_vars = read_terragrunt_config(find_in_parent_folders("region.hcl"))
  environment_vars = read_terragrunt_config(find_in_parent_folders("env.hcl"))

  environment  = local.environment_vars.locals.environment

  namespace = "some-company"
}

inputs = merge(
  local.provider_vars.locals,
  local.region_vars.locals,
  local.environment_vars.locals,
  local.namespace
)

aws/providers.hcl - Here we see something that I think could be an antipattern in naming. In a past life I had GCP and AWS in a Terra config but the actual infra was only in AWS, I used gcp_region and aws_region to differentiate. In the setup below, should I just call it region whichever cloud provider it is and let the directory context determine the intention? Look at the bottom of this file; if I called it region instead of aws_region, perhaps that could move to the top level terraform.hcl?

locals {
  account_vars = read_terragrunt_config(find_in_parent_folders("account.hcl"))
  aws_account_name = local.account_vars.locals.aws_account_name
  aws_account_id   = local.account_vars.locals.aws_account_id
  aws_region       = local.region_vars.locals.aws_region
}

generate "provider" {
  path      = "provider.tf"
  if_exists = "overwrite_terragrunt"
  contents  = <<EOF
provider "aws" {
  region = "${local.aws_region}"

  allowed_account_ids = ["${local.aws_account_id}"]
  default_tags {
    tags = {
      environment = "${local.environment}"
      terraformed = "true"
    }
  }
}

EOF
}

remote_state {
  backend = "s3"
  config = {
    bucket         = "terraform-state-${local.aws_account_name}-${local.aws_region}"
    dynamodb_table = "terraform-locks"
    encrypt        = true
    key            = "${path_relative_to_include()}/terraform.tfstate"
    region         = local.aws_region
  }
  generate = {
    path      = "backend.tf"
    if_exists = "overwrite_terragrunt"
  }
}

inputs = merge(
  local.account_vars.locals,
	{
    env_aws_region_dash = "${local.environment}-${local.aws_region}"
    env_aws_region_dot  = "${local.environment}.${local.aws_region}"
    aws_region_env_dash = "${local.aws_region}-${local.environment}"
    aws_region_env_dot  = "${local.aws_region}.${local.environment}"
	}
)

azure/providers.hcl - Same here, should azure_region even be a thing or just region? Should I refer to subscription as account as in AWS?

locals {
  subscription_vars = read_terragrunt_config(find_in_parent_folders("subscription.hcl"))
  azure_region            = local.region_vars.locals.azure_region
  azure_subscription_id   = local.subscription_vars.locals.azure_subscription_id
}

generate "provider" {
  path      = "provider.tf"
  if_exists = "overwrite_terragrunt"
  contents  = <<EOF

provider "azurerm" {
  features {}
}
EOF
}

remote_state {
  backend = "azurerm"
  config = {
    storage_account_name = local.namespace
    container_name       = "terraform-state"
    key                  = "${path_relative_to_include()}/terraform.tfstate"
    resource_group_name  = local.namespace
  }
  generate = {
    path      = "backend.tf"
    if_exists = "overwrite_terragrunt"
  }
}

Lastly for now, ./azure/main/eastus/production/some_app/terragrunt.hcl:

terraform {
  source = "git::[email protected]:redacted.git//some_app"
}

include "providers" {
  path = find_in_parent_folders("providers.hcl")
}

My current error is:

ERRO[0000] Not all locals could be evaluated:           
ERRO[0000]      - azure_region [REASON: Can't evaluate expression at /redacted/azure/providers.hcl:7,29-66 because local reference 'region_vars' is not evaluated. Either it is not ready yet in the current pass, or there was an error evaluating it in an earlier stage.] 

I can see why. Because region_vars is supposed to be generic and defined in the top-level terragrunt.hcl. But if I add:

include "root" {
  path = "${get_path_to_repo_root()}/terragrunt.hcl"
}

to azure/providers.hcl I get Only one level of includes is allowed.

If I add the same include to ./azure/main/eastus/production/some_app/terragrunt.hcl so that it contains:

include "root" {
  path = "${get_path_to_repo_root()}/terragrunt.hcl"
}

include "providers" {
  path = find_in_parent_folders("providers.hcl")
}

I get the same error about azure/providers.hcl failing on line 7.

Grateful for any assistance. I'm sure that both my architecture and my understanding of Terragrunt's behaviour could be improved.

@antgel antgel added the bug Something isn't working label Dec 28, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant