Region not being set by Terragrunt

terragrunt

#1

I have a Terragrunt file as follows:

terragrunt = {
  terraform {
    source = "git::git@github.com:gruntwork-io/module-vpc.git//modules/vpc-mgmt?ref=v0.3.2"
  }
}
vpc_name = "management"
cidr_block = "10.90.0.0/18"
aws_region = "ap-southeast-1"
num_nat_gateways = 1

All of the vars are being correctly set, except aws_region. when I run terragrunt plan, I get prompted to enter the region:

[terragrunt] 2017/11/22 17:10:43 Running command: terraform plan
provider.aws.region
  The region where AWS operations will take place. Examples
  are us-east-1, us-west-2, etc.

  Default: us-east-1
  Enter a value:

Does anyone know how to correctly define the region?


#2

Ah, this is a common source of confusion.

The modules you find in the /modules folder of gruntwork-io repos are designed to be used in your Terraform code—not directly with Terragrunt. That’s because for the majority of those modules, you need to configure other information to use the module, and providing that configuration typically requires writing some Terraform code. Examples:

  • You need to configure the provider. For the AWS provider, this includes the region to use, which explains the error you’re seeing now. The provider block should almost always be specified in the “root”, so we can’t define it directly in our modules.

  • You may need to configure Terraform itself, such as what backend to use for storing state, and which version of Terraform to use.

  • You may need to fetch information from other Terraform modules using the terraform_remote_state data source. For example, you might fetch the VPC ID from a VPC module or the database URL from an RDS module.

  • You may need to deploy several modules together and pass the outputs from one as the inputs to another (e.g., see the vpc-network-acls example which uses the VPC and network-acls modules).

So, the typical pattern you want to follow is:

  1. In one repo, which we typically call infrastructure-modules, you write Terraform code (.tf) that uses modules from the gruntwork-io org and provides all the configuration mentioned above.

  2. In another repo, which we typically call infrastructure-live, you write Terragrunt code (.tfvars) that uses your own modules from infrastructure-modules and sets variables for them.

The terragrunt-infrastructure-modules-example and terragrunt-infrastructure-live-example are reasonable examples to follow.

So, for the VPC code you’re trying to use, you’d probably create infrastructure-modules/vpc-mgmt/main.tf with contents that look something like this:

provider "aws" {
  region = "us-east-1"
}

terraform {
  required_version = "= 0.10.8"

  # The backend configuration will be filled in by Terragrunt
  backend "s3" {}
}

module "vpc" {
  source = "git::git@github.com:gruntwork-io/module-vpc.git//modules/vpc-mgmt?ref=v0.3.2"

  # ... set all the VPC params here ...

  # Note that any params that differ between environments should be exposed as variables
  vpc_name   = "${var.vpc_name}"
  cidr_block = "${var.cidr_block}"
}

And in infrastructure-live/stage/mgmt/vpc/terraform.tfvars, you might have something like this:

terragrunt = {
  terraform {
    source = "git::git@github.com:<YOUR_GITHUB_ORG>/infrastructure-modules.git//vpc-mgmt?ref=v0.0.1"
  }
}

vpc_name   = "stage"
cidr_block = "10.0.0.0/18"

#3

Thanks - that makes sense.


#4

how would that look if we are trying to set region up in global tfvars ? such as this

terragrunt = {
terraform {
extra_arguments “conditional_vars” {
commands = [
“apply”,
“plan”,
“import”,
“push”,
“refresh”
]

  required_var_files = [
    "${get_parent_tfvars_dir()}/terraform.tfvars"
  ]

  optional_var_files = [
    "${get_parent_tfvars_dir()}/${get_env("TF_VAR_env", "dev")}.tfvars",
    "${get_parent_tfvars_dir()}/${get_env("TF_VAR_region", "us-east-1")}.tfvars",
    "${get_tfvars_dir()}/${get_env("TF_VAR_env", "dev")}.tfvars",
    "${get_tfvars_dir()}/${get_env("TF_VAR_region", "us-east-1")}.tfvars"
  ]
}

}

do we just leave region out all together in our base tf files?


#5

@rykelley I’m not sure I understand your question. Can you provide a little more context for your use case and what you’re trying to do?


#6

@jim,
NOTE: This question left for reference, and self-answered in the EDIT below.
Above, you advise setting the region variable in the main.tf of the module.
But is it not the case that one creates modules to be reusable, i.e. deploying the same module code in more than one region? I have a vpc mod which I want to deploy exactly the same in more than one region, so in this case, I would want to avoid setting the region in the module. I’ve tried as the OP, and a few other ways, but because I had removed the region var instantiation in the module, like the OP, I’m getting an interactive for the region var when I do a tgp.

I moved my module main.tf (which only contained the provider “aws” block with the region in and the s3 backend) into my environment, but I’m now getting:

Acquiring state lock. This may take a few moments...
var.region
  Region module deployed in

  Enter a value:

instead of what @Jeff_Gray and I got first (as per the original post). I’m a bit stuck trying to get the region out of the module code but still be usable.

EDIT:
OK, rechecking the example gruntworks code

The terragrunt-infrastructure-modules-example and terragrunt-infrastructure-live-example are reasonable examples to follow.

I realised that in order to not force your (in my case, vpc) module to be deployed in a specific region in the module code itself, but instead specify the region in region-specific code outside of the module codebase, abstract the region variable in your region-specific environment terraform.tfvars file:

    terragrunt = {
    terraform {
        source = "git::ssh://git@bitbucket.org/phosphre/my.modules.git//vpc"
    }

    include = {
        path = "${find_in_parent_folders()}"
    }
}

aws_region = "eu-west-1"

and then refer to this in your module code so that when terragrunt aggregates the config, the module code can use this reference.
And then move your main.tf back into your module code (don’t forget to check in, and do a terragrunt get --terragrunt-source-update).


#7

Yea, your modules can expose an aws_region input variable and you can set that to different values in terraform.tfvars files for different regions.