In this post, I outline the steps needed to take an input from a terraform parent (or calling) module and pass it to a config file on a target EC2 instance.
What are Terraform Modules?
Using modules in terraform helps to organise and reuse code, allowing a module to be defined once and used many times. For example, a development team may want to quickly create and destroy a number of EC2 instances. Creating a module to do this would allow them to specify a small number of parameters each time, and for all the instances to be created in a consistent manner.
Parent Modules
Simply put, a parent module (also known as a “calling module” is a module that is calling other child modules in terraform.
The parent module acts as a wrapper for the child modules, providing input variables and outputs that are used by the child modules to perform their tasks.
Child Modules
A child module in terraform is a module that is called and used by another (parent) module. Child modules encapsulate specific infrastructure components and allow for the reuse of terraform code, making it easier to manage and maintain complex infrastructure. Child modules are defined and referenced within the parent module, with inputs and outputs being passed between the parent and child modules to configure and manage infrastructure components.
Example
This example shows how a parameter is defined in a parent (calling) module and passed through to a child module.
This example is based on a real implementation, and the related child module can be found here . The associated parent module therefore looks like this:
#main.tf file for deploying neo4j-terraform
module "neo4j-environment" {
source = "github.com/neo4j/neo4j-aws-terraform/tree/main"
//source = "../neo4j-terraform"
//Required values (no defaults are provided)
neo4j_password = "pw_for_neo4j_user"
public_key_value = "ssh-rsa AAAAB3NzaC1A.....b+oTz7tb0WF2aiOPp0="
private_key_path = "~/.ssh/my-ssh-key"
//The following Optional values can be omitted if the defaults are satisfactory.
//Default is "t3.medium"
instance_type = "t3.medium"
//Default is 3. Valid values are 1, or 3 -> 10 (inclusive)
node_count = 3
//Default is "10.0.0.0/16"
vpc_base_cidr = "10.0.0.0/16"
//Default is "0.0.0.0/0"
ssh_source_cidr = "0.0.0.0/0"
neo4j_source_cidr = "0.0.0.0/0"
//Default is false
install_gds = "false"
//Default is false
install_bloom = "false"
//Default is true
install_apoc = "true"
//Default is "neo4j-tf-cloud"
env_prefix = "my-neo4j-environment"
//Default is "us-east-1"
target_region = "us-east-1"
//Default is "None"
gds_key = "None"
//Default is "None"
bloom_key = "None"
}
output "ssh_commands" {
value = module.neo4j-environment.ssh_commands
}
output "neo4j_browser_url" {
value = module.neo4j-environment.neo4j_browser_url
}
Flow Diagram
The following diagram shows the flow in more detail (from right to left):
The parent (or calling) module is defined in the “main.tf” file and will be the same (or very similar) as the example code shown above.
The child module contains references to this variable in its code: The variable is defined in variables.tf and used in both the instances.tf and outputs.tf files. It is also used by the template file (neo4j.tftpl) which handles the EC2 instance post-install (user-data) script. The contents of the variable is finally shown by a terraform output once the environment has been created.