Modules in Action
Learn how to work with modules in detail.
Code#
/
- main.tf
We have written quite a lot of code. Let’s dive into it piece by piece and explain what it is all doing.
-
In a module, you can take arguments.
This allows you to give the user a chance to specify things about this instance of a module.
-
The module that we have written creates two AWS SQS queues.
One of the queues is a dead letter queue of the other.
-
For our module, we allow the user to specify the name of the queue.
We do this by defining the variable
queue_name
.
variables.tf
#
Variables have a special meaning when used with a module; they become the input values for your module. Note
that inside a module, Terraform does not care what the file names are as long as they end in .tf
.
However, there is a convention where variables go in a file called variables.tf
, so we will
stick with that. As the queue_name
variable does not have a default, a value must be given when the module is used. Variables in modules act in the same way as they do at the top level (which we learned in the
Variables chapter). If you do not give a default value, you have to provide a value for the variable when using the module.
As queue_name
does not have a default, it is a required parameter that must
be set when using this module. The other two variables we have defined, max_receive_count
and visibility_timeout
, have defaults so they do not have to be given values when using the module.
main.tf
#
Next, let’s look at the main.tf
file inside the module. You can see that we use the passed-in
variables by using the var.<variable_name>
syntax.
The other interesting thing about the code is
that we set the redrive_policy
of the first queue to have a dead letter queue of the second
queue.
We do this by using the interpolation syntax we learned earlier. This allows Terraform to dynamically put the arn from the second queue in the redrive policy when it creates the first queue.
output.tf
#
The last file that makes up our module is output.tf
. This is where our outputs (or return values)
from the module are specified. It is optional to return values out of a module, but most modules do
return values to make them easier to use. Outputs are defined using the output blocks that we
learned back in the Outputs chapter. Returned values in a module can be used in the main Terraform project.
Top level main.tf
#
If we look at the top-level main.tf
file, we can see how we create an instance of a module:
Creating instance of a module#
To create an instance of a module, we start with the keyword module
. This is followed by the
identifier you want to refer to that instance of the module. You then surround the module
block in {
and }
. Inside the module block, every module has a property called source
. The source
property
is where the code is for the module.
You can see that we are using the local path ./sqs-with-backoff
.
This tells Terraform that it can find the code for this module in a local folder with that name. We
then give a value of work-queue
to the queue_name
property.
Note that we are not specifying
the max_receive_count
or visibility_timeout
. We do not need to, as they both have default values.
If we wanted to, we could provide values for them, which would be used instead of the defaults.
Referencing the value returned by module#
At the bottom of the main.tf
, we output the names of the two queues created in the module. This works because we referenced the values returned by the module. To reference a value returned by a module, you use the following syntax: module.<module_identifier>.<output_name>
. So, to reference the value of the main queue, you would use module.work_queue.queue_name
. The keyword module is constant.
Running the project#
Clicking the run button will run terraform init
and then terraform apply
. When prompted, say yes if you want to run it in the project. You will see that two AWS SQS queues are created. One is a dead letter queue of the
other and the queue names are printed to the console when Terraform finishes running.
Modules’ real power#
The real power of modules is that they allow you to place logic in a single place and then reuse it across your Terraform project. You can have multiple instances of a module in a single
Terraform project. Add the following code to the top-level main.tf
in your project:
Above, we define the second instance of the same module. If you run the project now, you will see that Terraform creates two more queues, one being a dead letter of the second.
This is a good way to write code, as it allows us to change how our queues are constructed only once and apply that change to the whole of your project by running terraform apply
.
For example, try changing the max_message_size
property on one of the queues inside the module and run Terraform again. You will see that both queues are updated.
If you had written this code with all of the SQS resources in the top-level Terraform project, you would have had four Terraform resources defined (one for each queue). If you wanted to make a change, you would have had to update each resource with that change. This approach would quickly become unmanageable if you had tens or even hundreds of instances of your module.
Define structure using modules#
Using modules also allows you to define a structure for how items should look. In our example, we
prefixed our queue names with awesome_co-
. This is a great technique if you want to name all of your queues in a certain way. You could optionally take a variable that is the name of the environment. The module will prefix the name of the environment onto the queue name so the queue
names will not clash.