terraform Resource share - terraform

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.

Related

Terraform Organization

I'm new to Terraform and have been spending some time reading up and had a couple of questions related to the best way to structure the code. My plan is to store my Terraform code all in a single repository for all my projects. The infrastructure (Azure) consists of Virtual Machines and an AKS cluster. 98% of our VMs are all exactly the same except for subscription (uat/prod), size, resource group, name and maybe few differences in data disks. My first idea was to create a single environment for virtual machines with multiple .tfvars files for each of the VMs I want to manage? Like this:
└── terraform/
├── virtual_machines/
│ ├── main.tf
│ ├── variables.tf
│ ├── outputs.tf
│ ├── vm1.tfvars
│ ├── vm2.tfvars
│ └── vm3.tfvars
└── aks/
└── aks_project/
├── main.tf
├── variables.tf
└── outputs.tf
Then I can just specify what .tfvars files to point to when applying?
The second idea would be to put the shared vm code in a module then create a directory for each VM like this:
└── terraform/
├── virtual_machines/
│ ├── modules/
│ │ └── virtual_machines/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ └── outputs.tf
│ ├── vm1/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ └── outputs.tf
│ ├── vm2/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ └── outputs.tf
│ └── vm3/
│ ├── main.tf
│ ├── variables.tf
│ └── outputs.tf
└── aks/
└── aks_project/
├── main.tf
├── variables.tf
└── outputs.tf
With each VM directory sourcing from the modules and including the variable values needed for each?
Are either of these approaches make sense for what I'm looking to do? What would you suggest for or use for organizing your terraform code?
Your second approach looks like a better start, as it applies Hashicorp's recommendation of using modules whenever it's possible.
Then you can simply define each VM in a separate .tf file (or group all of them in one), each one of these files should use your local VM module that sets your defaults, and then provide multiple tfvars for each environment.
So you would have something like:
.
├── main.tf
└── virtual_machines
├── modules
│ └── virtual_machines
│ ├── README.md
│ ├── main.tf
│ ├── outputs.tf
│ └── variables.tf
├── dev.tfvars
├── uat.tfvars
├── prod.tfvars
├── variables.tf
├── locals.tf
├── vm1.tf
└── vm2.tf
Where vm1.tf is using your local module and sets its custom parameters, for example:
module "vm1" {
source = "./modules/virtual_machines"
name = "my-vm1-name"
environment = var.environment
}
My var.environment here is defined by my tfvars file which will be picked up for each environment, if I'm on dev I would run my plan or apply with dev.tfvars.
Read more at:
https://cloud.google.com/docs/terraform/best-practices-for-terraform#module-structure
https://www.hashicorp.com/blog/structuring-hashicorp-terraform-configuration-for-production#considerations-for-defining-modules
https://developer.hashicorp.com/terraform/tutorials/modules/pattern-module-creation?in=terraform%2Fmodules&product_intent=terraform
https://www.terraform-best-practices.com/examples/terraform
Also, you may want to consider options like terragrunt for this scenario of configuration DRY.
I hope this answer helps, it's based on my opinions and my experience. You may have a different use case, and a different setup, and you may have other answers from smarter people suggesting different approaches since there's nothing such as a "Best terraform project structure".

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
# ...
}

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.

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

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.

Resources