Pass terraform output from one file to another - terraform

I have following structure:
modules
|_ test1
| |_vpc.tf
|_test2
|_subnet.tf
I have created a vpc in test1/vpc.tf
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
}
I am getting vpc id in output like:
output "vpc_id" {
value = aws_vpc.main.id
}
How can I pass this id to test2/subnet.tf file? I am searching online and can't seem to find an answer for this.

Create a variable in subnet.tf:
variable "vpc_id" {
type = string
}
Then in your main terraform file where you are utilizing both of these modules, you would take the output from the vpc module and pass it to the input of the subnet module:
module "vpc" {
source = "modules/test1"
}
module "subnet" {
source = "modules/test2"
vpc_id = module.vpc.vpc_id
}

Related

Dynamic resources for_each output in terraform module

Terraform v1.0.0
Provider: aws v3.49.0
I created dynamic AWS subnets resources with a for_each from a module.
The resources creation is working fine, however being able to output dynamically created resources is not working and cannot find proper documentation for it.
The subnet module is
resource "aws_subnet" "generic" {
vpc_id = var.vpc_id
cidr_block = var.cidr_block
map_public_ip_on_launch = var.public_ip_on_launch
tags = {
Name = var.subnet_tag_name
Environment = var.subnet_environment
}
}
With simple module output defined
output "subnet_id" {
value = aws_subnet.generic.id
}
Then from root module, I am creating a for_each loop over a list variable to create multiple dynamic resources from the module
module "subnets" {
source = "../modules/networking/subnet"
for_each = var.subnets
vpc_id = "vpc-09d6d4c17544f3a49"
cidr_block = each.value["cidr_block"]
public_ip_on_launch = var.public_ip_on_launch
subnet_environment = var.subnet_environment
subnet_tag_name = each.value["subnet_tag_name"]
}
When I run this without defining outputs in the root module, things get created normally. The problem comes when I try to define the outputs
output "subnets" {
value = module.subnets.*.id
description = "Imported VPC ID"
}
It comes up with this error
│ Error: Unsupported attribute
│
│ on output.tf line 2, in output "subnets":
│ 2: value = module.subnets.*.id
│
│ This object does not have an attribute named "id".
I tried different output definitions. Would appreciate guidance on how to properly define outputs of instances dynamically created with a for_each module.
Per the Terraform documentation, the "splat" operator (*) can only be used with lists, and since you're using for_each your output will be a map.
You need to use map/list comprehension to achieve what you want.
For an output that is a map of key/value pairs (note that I've changed the output description to something that makes more sense):
output "subnets" {
value = {
for k, v in module.subnets:
k => v.subnet_id
}
description = "Subnet IDs"
}
For a list that only contains the subnet IDs:
output "subnets" {
value = [
for k, v in module.subnets:
v.subnet_id
]
description = "Subnet IDs"
}

Unable to Create Terraform Resource Group when using modules

I am optimizing my terraform code by using modules. When i create a resource group module it works perfectly well but it creates two resource groups
i.e.
Temp-AppConfiguration-ResGrp
Temp-AppServices-ResGrp
instead it should only create
Temp-AppConfiguration-ResGrp
Code Resourcegroup.tf.
resource "azurerm_resource_group" "resource" {
name = "${var.environment}-${var.name_apptype}-ResGrp"
location = var.location
tags = {
environment = var.environment
}
}
output "resource_group_name" {
value = "${var.environment}-${var.name_apptype}-ResGrp"
}
output "resource_group_location" {
value = var.location
}
Variable.tf
variable "name_apptype" {
type = string
default = "AppServices"
}
variable "environment" {
type = string
default = "Temp"
}
variable "location" {
type = string
default = "eastus"
}
Main.tf
module "resourcegroup" {
source = "../Modules"
name_apptype = "AppConfiguration"
}
I want to pass name_apptype in main.tf when calling resource group module. So that i don't need to update variable.tf every time.
Any suggestions
where i am doing wrong. Plus i am also unable to output the value, i need it so that i could pass resource group name in the next module i want to create.
Thanks
You need to do that in the Main.tf
module "resourcegroup" {
source = "../Modules"
name_apptype = "AppConfiguration"
}
module "resourcegroup-appservices" {
source = "../Modules"
name_apptype = "AppServices"
}
These create a 2 resources groups with the values that you need, additionally you can remove the default value from the name_apptype variable.
If you want to create with the same module both resource groups you need to use count to iterate over an array of names

Terraform output defined are empty [duplicate]

I'm trying to setup some IaC for a new project using Hashicorp Terraform on AWS. I'm using modules because I want to be able to reuse stuff across multiple environments (staging, prod, dev, etc.)
I'm struggling to understand where I have to set an output variable within a module, and how I then use that in another module. Any pointers to this would be greatly appreciated!
I need to use some things created in my VPC module (subnet IDs) when creating EC2 machines. My understanding is that you can't reference something from one module in another, so I am trying to use an output variable from the VPC module.
I have the following in my site main.tf
module "myapp-vpc" {
source = "dev/vpc"
aws_region = "${var.aws_region}"
}
module "myapp-ec2" {
source = "dev/ec2"
aws_region = "${var.aws_region}"
subnet_id = "${module.vpc.subnetid"}
}
dev/vpc simply sets some values and uses my vpc module:
module "vpc" {
source = "../../modules/vpc"
aws_region = "${var.aws_region}"
vpc-cidr = "10.1.0.0/16"
public-subnet-cidr = "10.1.1.0/24"
private-subnet-cidr = "10.1.2.0/24"
}
In my vpc main.tf, I have the following at the very end, after the aws_vpc and aws_subnet resources (showing subnet resource):
resource "aws_subnet" "public" {
vpc_id = "${aws_vpc.main.id}"
map_public_ip_on_launch = true
availability_zone = "${var.aws_region}a"
cidr_block = "${var.public-subnet-cidr}"
}
output "subnetid" {
value = "${aws_subnet.public.id}"
}
When I run terraform plan I get the following error message:
Error: module 'vpc': "subnetid" is not a valid output for module "vpc"
Outputs need to be passed up through each module explicitly each time.
For example if you wanted to output a variable to the screen from a module nested below another module you would need something like this:
child-module.tf
output "child_foo" {
value = "foobar"
}
parent-module.tf
module "child" {
source = "path/to/child"
}
output "parent_foo" {
value = "${module.child.child_foo}"
}
main.tf
module "parent" {
source = "path/to/parent"
}
output "main_foo" {
value = "${module.parent.parent_foo}"
}

Terraform module throws error about requiring a string

I've been trying to split my terraform code from one large file into separate modules. I keep running into an issue where the following error appears when running Terraform Plan.
Error: Incorrect attribute value type
on modules/nsg/main.tf line 11, in resource "azurerm_network_security_group" "InternalProdNSGPrivate":
11: resource_group_name = "${module.rg.main-rg-id}"
Inappropriate value for attribute "resource_group_name": string required.
I created an outputs.tf file which has the following:
output "main-rg-id" {
value = "${azurerm_resource_group.InternalProd}"
}
The main.tf for this module has the following:
module "global_variables" {
source = "../global_variables"
}
resource "azurerm_resource_group" "InternalProd" {
name = "Internal"
location = "${module.global_variables.location}"
}
In the main.tf file for the NSG i have the following configured:
module "rg" {
source = "../rg"
}
module "global_variables" {
source = "../global_variables"
}
resource "azurerm_network_security_group" "InternalProdNSGPrivate" {
name = "Internal-NSG"
location = "${module.global_variables.location}"
resource_group_name = "${module.rg.main-rg-id}"
....
}
Not sure where im going wrong here with the configuration. Tried looking at multiple different resources, blogs, etc. but no luck.
azurerm_resource_group.InternalProd is an object representing the whole of resource "azurerm_resource_group" "InternalProd".
To produce just the id of that object, you can access attribute id like this:
output "main-rg-id" {
value = azurerm_resource_group.InternalProd.id
}

Unable to reference vpc_id for a subnet within modules

Have a modules/network/testvpc and modules/network/subnet module configurations .
mainfolder/modules/network/testvpc/main.tf
variable "vpccidr" {type="list"}
variable "vpcname" {type="list"}
resource "aws_vpc" "customVpc" {
count = "${length(var.vpccidr)}"
cidr_block = "${element(var.vpccidr,count.index)}"
tags {
Name = "${element(var.vpcname,count.index)}"
}
mainfolder/modules/network/subnet/main.tf
variable "subcidr" {type="list"}
variable "subname" {type="list"}
resource "aws_subnet" "subnet" {
count = "${length(var.subcidr)}"
vpc_id = "${element(aws_vpc.customVpc.*.id, count.index)}"
cidr_block = "${element(var.subcidr, count.index)}"
tags {
Name = "${element(var.subname, count.index)}"
}
}
mainfolder/main.tf
module "testvpc" {
source = "./modules/network/testvpc"
vpccidr="${var.vpccidr}"
vpcname="${var.vpcname}"
}
module "subnet" {
source = "./modules/network/subnet"
subcidr = "${var.subcidr}"
subname = "${var.subname}"
}
mainfolder/var.tf
variable "vpccidr" {type="list"}
variable "vpcname" {type="list"}
variable "subcidr" {type="list"}
variable "subname" {type="list"}
mainfolder/terraform.tfvars
- vpccidr=["10.1.0.0/16","10.2.0.0/16","10.3.0.0/16"]
vpcname=["vpc-shared","vpc-sand","vpc-preprod"]
subcidr=["10.1.1.0/24","10.2.1.0/24","10.3.1.0/24"]
subname=["sub-shared","sub-sand","sub-preprod"]
-
While running terraform validate -var-file=terraform.tfvars getting the following error
Error: resource 'aws_subnet.subnet' config: unknown
resource 'data.aws_vpc.customVpc' referenced in variable
data.aws_vpc.customVpc.*.id
Is it because aws_subnet is not able to locate vpc_id since the resource aws_vpc is not created it . I am calling both the testvpc and subnet as modules in the mainfolder/main.tf . What am i missing .
Secondly is the loop in the aws_vpc and aws_subnet proper . It should create vpc-shared 10.1.0.0/16 and sub-shared within that vpc and so on
You need to use module outputs because you are trying to reference resources in a separate module. That won't work because
Modules encapsulate their resources. A resource in one module cannot directly depend on resources or attributes in other modules, unless those are exported through outputs.
So in mainfolder/modules/network/testvpc/main.tf, add an output like so
output "vpc_ids" { value=["${aws_vpc.customVpc.*.id}"] }
Then add a variable in mainfolder/modules/network/subnet/main.tf like so
variable "vpc_ids" {type="list"}
and use it within that module (instead of trying to directly reference resources from the /testvpc/main.tf module)
resource "aws_subnet" "subnet" {
count = "${length(var.subcidr)}"
vpc_id = "${element(var.vpc_ids, count.index)}"
etc, etc
}
and finally now from your mainfolder/main.tf
module "testvpc" {
source = "./modules/network/testvpc"
vpccidr="${var.vpccidr}"
vpcname="${var.vpcname}"
}
module "subnet" {
source = "./modules/network/subnet"
subcidr = "${var.subcidr}"
subname = "${var.subname}"
vpc_ids = "${module.testvpc.vpc_ids}"
}

Resources