Dependencies in Terraform Graph

Terraform Dependencies, Graph Theory and Lists

14755 VIEWS

· · ·

This blog provides some basic examples of dealing with dependencies in Terraform and the graph theory behind it and also some examples of utilising the new variable types made available in Terraform 0.7.


This latest release to the repository includes some examples of forcing ordering of resource creation using modular dependencies, the graph theory that demonstrates how Terraform is viewing those dependencies and also an example of lists usage, one of the new first class data types released as part of Terraform 0.7.

To force a modular dependency using variables you should first add a dummy variable to the module you wish to be dependent on another, like below for example with the ‘dependency’ variable:

# tag variables
variable owner		  { default = “” }
variable dependency { default = “” }

With dummy ‘dependency’ variable in place it means that a variable can be passed to the module, even if it won’t be used as part of a resource. Using this dummy variable during the modular declaration we can use an output variable from another module (see below), this implicitly forces the dependent module to wait for the other to be created first as it has to wait for the output to become available.

module “demo-node” {
	source = “../../../modules/compute/nodes/demo_node”

	# instance configuration
	ami			= “${var.ami}”
	instance_type	= “${var.demo_node_instance_type}”
	count		= “${var.demo_node_instance_count}”
	key_name		= “${var.demo_node_ssh_key_name}”

	owner		= “${var.owner}”
	dependency	= “${module.demo-node-dependency.demo_node_dependency_instance_id}”
}
###################

#### Demo Node Dependency ####
variable demo_node_dependency_instance_type	{ default = “t2.micro” }
variable demo_node_dependency_instance_count { default = “1” }
variable demo_node_dependency_ssh_key_name { default = “” }

module “demo-node-dependency” {
	source = “../../../modules/computer/nodes/demo_node_dependency”

	ami			= “${var.ami}”
	instance_type	= “${var.demo_node_dependency_instance_type}”
	count		= “${var.demo_node_dependency_instance_count}”
	key_name		= “${var.demo_node_dependency_ssh_key_name}”

You need to ensure that you have assigned an output within the module you wish for another module to be dependent on!

# outputs produced at the end of a terraform apply: id of the instances, id of
# security group(s) they are part of
output “demo_node_dependency_instance_id”	{ value = [ “${aws_instance.demo-node-dependency.*.id}” ] }
output “demo_node_dependency_ip”			{ value = [ “${aws_instance.demo-node-dependency.*.public_ip}” ] }
output “demo_node_dependency_sg_id”		{ value = [ “${aws_security_group.demo-dependency-sg.id}” }

With these variable dependencies in place it forms a work flow as follows:

From this image you can see that because of the variable dependencies out original ‘demo-node’ module (which includes the ‘demo-sg’ that is part of the module, hence why the instance is dependent on the security group because the security group is created before it, ready for the instance to be attached to) is now dependent on the ‘demo-node-dependency’ module. All of which of dependent on the AWS provider as they are all resources of the AWS provider.

In order to pass a list of ports into a firewall resource for Google Cloud Platform I opted in to using one of the new first class data types, the list (the map data type is also now available), which proved to be much less complex than trying to use the split/join syntax that had to be used previously.

Simply declare your array list in your ‘terraform.tfvars

allow_ports = [“22”]

Pass it through to the module as a list

module “allow-tcp-fw” {
	source = “../../../modules/networking/firewalls/allow_tcp”
	
	fw_name			= “${var.fw.name}”
	parent_network_id	= “${module.demo-network.network_id}”
	alloe_ports		= [“${var.allow_ports}”]
}

Ensure that the variable is declared as a list within the module

variable “allow_ports”	{ type = “list” description = “Array of the ports to allow”}

And use the variable as part of the resource that expects an series of values as the parameter

# creates an allow TCP firewall in GCP
resource “google_compute_firewall” “ ssh-access” {
	name	= “${var.fw_name}”
	network	= “${var.parent_network_id}”

	allow{
		protocol   = “tcp”
		ports	= [“${var.allow_ports}”]
	}
}

That’s it for now guys, I hope all of this has been helpful in your Terraform endeavours, feel free to drop me an email/comment on this post should you have any questions.


Jordan Taylor is a DevOps Practitioner. His goal is to learn every DevOps tool and technology, developing an arsenal of knowledge that covers every aspect of the DevOps space. With a specialization in automation, configuration management, cloud orchestration and CI/CD, Jordan is always looking to implement forward-thinking ideas that result in ultimate efficiency and value, while up-skilling and enabling those around him in the technologies used to innovate. Jordan's current favorite tools are Terraform, Docker and Vault.


Discussion

Leave a Comment

Your email address will not be published. Required fields are marked *

Menu
Skip to toolbar