Let's list the data we need to pass to the module:
- Name of the application
- VPC ID
- Subnet ID
That should be sufficient for now. Update the module inside template.tf to look as follows:
module "mighty_trousers" { source = "./modules/application" vpc_id = "${aws_vpc.my_vpc.id}" subnet_id = "${aws_subnet.public.id}" name = "MightyTrousers" }
Passing data like this is not enough though. We need to define variables inside the module template. The thing is, our tempate.tf is a module itself, a special module named root module. That's what you saw on the last graph we drew--resources were coming from the root module. So, we were actually already using modules all this time, and every module, including the root module, can be configured with variables.
Variables are defined with the variable keyboard, followed by the variable name and optional default value inside curly braces:
variable number_of_servers { default = 1 }
There are many ways to define variables, and there are multiple types of variables, but let's save our in-depth exploration for the next chapter. For now, let's add the following lines to the top of the ./modules/application/application.tf file:
variable "vpc_id" {} variable "subnet_id" {} variable "name" {}
To use the variable, you need to reference it via a special var keyword, as follows: ${var.my_variable}. Replace all the resource references with variables:
resource "aws_security_group" "allow_http" { name = "${var.name} allow_http" description = "Allow HTTP traffic" vpc_id = "${var.vpc_id}" ingress { from_port = 80 to_port = 80 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } egress { from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] } } resource "aws_instance" "app-server" { ami = "ami-9bf712f4" instance_type = "t2.micro" subnet_id = "${var.subnet_id}" vpc_security_group_ids = ["${aws_security_group.allow_http.id}"] tags { Name = "${var.name}" } }
Now you should be able to run again via the terraform get command:
$> terraform get Get: file:///home/kshirinkin/work/packt-terraform-rewrites/modules/application
This created a symlink to your module inside the .terraform directory:
$> ls -la .terraform/modules total 12 drwxr-xr-x. 2 kshirinkin kshirinkin 4096 Jan 3 16:08 . drwxr-xr-x. 3 kshirinkin kshirinkin 4096 Jan 3 16:08 .. lrwxrwxrwx. 1 kshirinkin kshirinkin 66 Jan 3 16:08 8a6e0ac9202efe2b1f0a69ae2d5138bb -> /home/kshirinkin/work/packt-terraform-rewrites/modules/application
You should be able to run the terraform apply command now. Let's add a second module, just to verify that we are still doing things right:
module "crazy_foods" { source = "./modules/application" vpc_id = "${aws_vpc.my_vpc.id}" subnet_id = "${aws_subnet.public.id}" name = "CrazyFoods" }
Run the terraform get and terraform plan commands to check whether Terraform will do everything as expected, and pay attention to this part of the output:
+ module.mighty_trousers.aws_security_group.allow_http description: "Allow HTTP traffic" name: "MightyTrousers allow_http"
Note how the name of the resource was built; it includes the module name and a module keyword. This doesn't mean that you can reference this module by this name though. Try to do it as follows:
module "crazy_foods" { source = "./modules/application" vpc_id = "${aws_vpc.my_vpc.id}" subnet_id = "${aws_subnet.public.id}" name = "CrazyFoods ${module.mighty_trousers.aws_security_group.allow_http.id}" }
You will get an error saying * module.crazy_foods: missing dependency: module.mighty_trousers.output.aws_security_group.allow_http.id. You cannot simply reference resources inside a module from outside the module. You have to use outputs.