Terraform module: one lesson learned hard way

Terraform modules , if defined “manually” ,watch for output.tf. Whatever you define in the output of that module is what that that module is going to return when used.
For eg. If you created one EC2 module that creates the webserver, and in output.tf file, one of the output definitions is something like this


#CASE - 0
#/module/EC2/output.tf

output "instance_detail" {

 value = {

 web_public_ip  = aws_instance.webserver.public_ip

 web_public_dns = aws_instance.webserver.public_dns

 web_private_ip = aws_instance.webserver.private_ip

 }

}

Now you used this module and output needed was public_ip and public_dns ,
the usual way to call such output is

# Output.tf for normal instance

output "mission_public_ip" {
value = {
    public_ip  = aws_instance.instancename.public_ip
    public_dns = aws_instance.instancename.public_dns
    }
}

This should return dns and ip on execution. Which it will, if this is made using normal instance.
But if you are using module , that too one you made..

#CASE-1
#output.tf module call for outputs
output "mission_public_ip" {
value = {
    public_ip  = module.instancename.public_ip
    public_dns = module.instancename.public_dns
    }
}

This will spew out error, that the module.instance is an object and public_ip will be known only after apply.
Now looking at error you add.. dependency but now the error changes and says,

"The `module.instance` does not have attribute named `public_ip`" 

solution? Check output.tf of the module
Whatever “name” that is given in the module, is the only allowed attribute outside module.

#CASE-2
#output.tf module call for outputs
output "mission_public_ip" {
value = {
    Details = module.instancename.instance_detail
    }
}

This will work (based on CASE- 0) since module has instance_detail attribute defined.

Outputs:

Details = {
  "web_private_ip" = "172.31.15.10"
  "web_public_dns" = "ec2-65-0-122-48.ap-south-1.compute.amazonaws.com"
  "web_public_ip" = "65.0.122.48"
}

BEST PRACTICE

  • Create modules carefully, mindful of variables and outputs
  • Create well thought-out output.tf, keep standard nomenclature.
    • define important attributes separate and by-their-own-names
      • E.g. public-ip should be public_ip, public dns should be public_dns
  • Keep standard variable names and double-check for clarity.
  • Whenever required to do so keep as much as possible attributes in output.tf
  • Document the structure and attributes, refer Terraform module registry.

This could be a little difficult to comprehend but when you create a module, these are the trippers. Being watchful helps along the way.

Happy module making!