How to name resources dynamically based on the env they are in? - terraform

I'm trying to unify naming of resources, depending on the environment (dev, stage or prod). I will illustrate with an example.
Let's say I want to create an aws iam user resource like:
resource "aws_iam_user" "iam_foo" {
name = "foo_dev"
}
Here I hard-coded "dev" into the name of the resource. But ideally I would like that to be done dynamically based on the folder it is located in (folder resembles an environment like dev or prod).
The folder structure looks something like:
├── README.md
├── meow-development
│   ├── locals.tf -> ../locals.tf
│   ├── main.tf
│   └── s3.tf
├── meow-production
│   ├── locals.tf -> ../locals.tf
│   ├── main.tf
│   └── s3.tf
├── meow-staging
│   ├── locals.tf -> ../locals.tf
│   ├── main.tf
│   └── s3.tf
So what I am trying to achieve is something like:
resource "aws_iam_user" "iam_foo" {
name = naming_function(name) # Not intended as actual code
}
The naming function takes a name as input and names it according to the env. So if this resource is created under dev, then naming_function(woof) should return the string "woof_dev"
So my questions are:
How can I name things dynamically?
Is using a naming convention that includes the environment such as meow_{env_name} correct?

Create a terraform.tfvars inside the meow-development folder with
env_name = "dev"
In the main.tf inside the meow-development folder:
resource "aws_iam_user" "iam_foo" {
name = "foo_${var.env_name}"
}
Same for other environments. Regarding naming convention, depends on the resource, having env as part of the name is considered a best practice.

Related

How to use variables defined in terraform.tfvars in main.tf

structure in my terraform source
├── main.tf
├── outputs.tf
├── serverless
│   ├── main.tf
│   ├── outputs.tf
│   ├── terraform.tfvars
│   ├── variables.tf
│   └── versions.tf
├── variables.tf
└── versions.tf
question
How can I use variables defined in terraform.tfvars in main.tf?
My code is based on this example and add the following code with it(replaced ~/examples/serverless with ~/serverless).
terraform-aws-modules/terraform-aws-rds-aurora
https://github.com/terraform-aws-modules/terraform-aws-rds-aurora
code in serverless/terraform.tfvars
SAMPLE_VALUE="xxx"
code in serverless/main.tf
variable "SAMPLE_VALUE" {}
deploy command
$ terraform apply
official document
It lacks of usage in other .tf file
Variable Definitions (.tfvars) Files
https://www.terraform.io/language/values/variables#variable-definitions-tfvars-files
If you create your variable in variable file, you can use it in the same directory's main.tf with var. In your case, the variable you are trying to locate should be located to its place in main.tf using var.SAMPLE_VALUE
There is pretty clear explanation with example here ;
https://jhooq.com/terraform-variable-and-tfvars-file/#2-terraform-tfvars-file---terraformtfvars
I succeeded to overcome this problem to define variable "SAMPLE_VALUE" {} both serverless/main.tf and ~/main.tf.
Thanks everyone for reply!!

Why terraform validate is giving error on my declared varaibles?

├── comp-B
│   ├── comp-B.tf
│   ├── outputs.tf
│   ├── terraform.tfvars
│   ├── variables.tf
│   └── vcn.tf
├── main.tf
├── outputs.tf
├── provider.tf
└── variables.tf
The argument "vcns" is required, but no definition was found
I have defined the vcns in comp-B/variables.tf and vcns value in terraform.tfvars
But still getting the error.
Without seeing your source code I can't be sure, but I'm assuming that what you mean by this directory tree is that the root main.tf contains a module block with source = "./comp-B", and the error you saw is indicating that module block as the source of the problem.
The terraform.tfvars file is only for setting variables in the root module, which means the ones defined in your root variables.tf. If you want to pass those values on to a child module then you can include an argument in the module block which refers to the variable:
module "example" {
source = "./comp-B"
vcns = var.vcns
# ...
}

Terragrunt Best practice: dependencies between modules

I have a terragrunt project like this
├── common_vars.hcl
├── envs
│   ├── dev
│   │   ├── env_vars.hcl
│   │   ├── rds-aurora
│   │   │   └── terragrunt.hcl
│   │   ├── rds-sg
│   │   │   └── terragrunt.hcl
│   │   └── vpc
│   │   └── terragrunt.hcl
│   └── prod
│   ├── env_vars.hcl
│   ├── rds-sg
│   │   └── terragrunt.hcl
│   └── vpc
│   └── terragrunt.hcl
├── modules
│   ├── aws-data
│   │   ├── main.tf
│   │   └── outputs.tf
│   ├── rds-aurora
│   │   └── main.tf
│   ├── rds-sg
│   │   └── main.tf
│   └── vpc
│   └── main.tf
└── terragrunt.hcl
The rds-sg is the security group depends on the vpc.
The terragrunt.hcl under dev and prod has the same code like this.
terraform {
source = format("%s/modules//%s", get_parent_terragrunt_dir(), path_relative_to_include())
}
include {
path = find_in_parent_folders()
}
dependencies {
paths = ["../vpc"] # not dry
}
dependency "vpc" {
config_path = "../vpc" # not dry
}
inputs = {
vpc_id = dependency.vpc.outputs.vpc_id # if something changes or we need more inputs
}
As described in the comments, some codes are not so DRY. If I want to change something like change to another vpc or add more inputs, then I need to modify this file everywhere.
So I want something in the main.tf under modules
module "rds-sg" {
source = "terraform-aws-modules/security-group/aws//modules/mysql"
name = "${var.name_prefix}-db-sg"
description = "Security group for mysql 3306 port open within VPC"
vpc_id = ""
# I want something like
# vpc_id = dependency.vpc.outputs.vpc_id
}
Is that possible? or some better practices to solve this problem?
Thanks very much.
Maybe using terraform_remote_state can fix this problem. Any better idea?
This comment may explain this problem better.
https://github.com/gruntwork-io/terragrunt/issues/759#issuecomment-687610130
I would use Data sources to read any ID for any resources:
Add this to the module that uses VPC ID.
data "aws_vpc" "this" {
filter {
name = "tag:Name"
values = [var.name]
}
}
...
vpc_id = data.aws_vpc.this.id
This way you are making sure to read from AWS API not from State file, which has on plan validation also.

terraform Resource share

I have a terraform template module that looks like this
.
├── example
│   ├── main.tf
│   └── variables.tf
├── policies.tf
├── roles.tf
├── main.tf
├── provider.tf
└── variable.tf
inside the main.tf inside example path I have a resource that depends on a resource that is part of me main.tf how can I call resource with depends_on = [] if they're not part of the same file and path
if they're not part of the same file and path
You can't do this. You have to re-think your architecture and probably change it so that such dependency does not happen.

Source Terraform Module From Sub-Directories In a BitBucket Repository With A different branch

I have a terraform modules repository with different set of modules with below structure
BitBucket Repository(URL: git#bitbucket.org:/{repoName}.git?ref=develop
└── modules
├── s3
│   ├── locals.tf
│   ├── main.tf
│   ├── output.tf
│   └── variables.tf
└── tfstate
└── main.tf
develop is the branch that I want to use which I have given in the source URL. I am calling the module repository as given below:
├── examples
│   ├── gce-nextgen-dev.tfvars
│   └── main.tf
main.tf
module "name" {
source = "git#bitbucket.org:{url}/terraform-modules.git? ref=develop/"
bucketName = "terraformbucket"
environment = "dev"
tags = map("ExtraTag", "ExtraTagValue")
}
How can I call the modules from sub-directories which is in a BitBucket repository.
It works if I remove the ref=develop from the URL and just give git#bitbucket.org:{url}/terraform-modules.git//modules//s3
But I don't want to use master but develop branch in this case.

Resources