Here is my scenario, I use module a lot, and need to set the default value for some optional arguments, but sometimes, when to handle two conflict optional arguments, add or not to add the optional argument will cause to be a total different resource, so I need to create two modules with and without this optional argument.
when to create a module for AWS_SECURITY_GROUP_RULE
cidr_blocks - (Optional) List of CIDR blocks. Cannot be specified with source_security_group_id.
source_security_group_id - (Optional) The security group id to allow access to/from, depending on the type. Cannot be specified with cidr_blocks.
module "aws_security_group_rule" "allow_all" {
type = "ingress"
from_port = 0
to_port = 65535
protocol = "tcp"
cidr_blocks = ["${var.cider_blocks}"]
source_security_group_id = "${var.source_sg_id}"
security_group_id = "sg-123456"
}
variable "cider_blocks" {
type = "list"
default = []
}
variable "source_sg_id" {
type = "string"
default = ""
}
These two optional arguments is conflict, so I need to create two modules like:
module "aws_security_group_rule" "allow_all" {
type = "ingress"
from_port = 0
to_port = 65535
protocol = "tcp"
cidr_blocks = ["${var.cider_blocks}"]
security_group_id = "sg-123456"
}
and
module "aws_security_group_rule" "allow_all" {
type = "ingress"
from_port = 0
to_port = 65535
protocol = "tcp"
source_security_group_id = "${var.soure_sg_id}"
security_group_id = "sg-123456"
}
Is there anyway to solve issue like this? Maybe all the optional arguments should have a default value to identify it enabled or not and add them to the document will be better.
Thank you for your time.
Hi @spotlight-dev! One question I have here - is this an example or actual code you are trying to use? You generally do a lot better by composing modules of related application functionality, not as units of reusability.
@jen20 I am the guy spotlight-dev :) Thank you for your reply.
It is the actual code I used in the project, and I almost create module for every aws resource, and then reuse it in the actual resource definition. So I thought the optional parameter should have a default value to behave like a feature switch.
It is the wrong way to use module? And I also referred to https://github.com/hashicorp/best-practices/tree/master/terraform, use the similar directory layout. Anything suggestion about the best practice.
composing modules of related application functionality, not as units of reusability
Is there an alternative suggestion about how to do the latter? My use case is that I'm working on reusable Jenkins deployment code, to be leveraged by different teams in my (large) organization. There are Terraform modules that I instruct users to include, though the specific needs of each deployment might be different. For example: whether their Jenkins instance(s) need an AWS IAM Instance Profile or not. The "make variables for everything a user may want to configure" approach would (I think) require what @hanks describes.
My other thought about how to accomplish this was to instruct users to use Terraform overrides, but it wasn't clear to me if it's possible to have a resource outside of a module corresponding to a resource within a module. In other words, I would be looking to do something like
# override.tf
resource "aws_instance" "module.aws_instance.jenkins" {
iam_instance_profile = "foo"
}
This would give a lot more flexibility, as not all of the arguments would need to be exposed as variables. Thoughts?
I have a similar problem:
in the module for our aws_ecs_task_definition we have the optional task_role_arn, but not all services have a task role and I can't find a solution to set the default value to omitted or None.
resource "aws_ecs_task_definition" "task_definition" {
depends_on = [
"data.template_file.task_definition_template"
]
family = "${var.service_name}-${var.environment}"
container_definitions = "${data.template_file.task_definition_template.rendered}"
task_role_arn = "${aws_iam_role.ecs_task_role.arn}"
lifecycle {
create_before_destroy = true
}
}
Hi all! Sorry for the long silence here.
Terraform 0.12 introduced a mechanism to conditionally omit an argument:
task_role_arn = length(aws_iam_role.ecs_task_role) > 0 ? aws_iam_role.ecs_task_role.arn[0] : null
The general pattern here is to use the conditional operator ? : with one of the result expressions set to null. When used as a resource argument, null is equivalent to omitting the argument altogether. Internally, providers can't even tell the difference between a null value and omitting the argument altogether.
For more complex situations this can still require some creative interface design for your module variables, but the mechanism for conditionally omitting arguments is now present, so we're going to close this out. Thanks for sharing these use-cases!
I'm going to lock this issue because it has been closed for _30 days_ โณ. This helps our maintainers find and focus on the active issues.
If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.
Most helpful comment
I have a similar problem:
in the module for our
aws_ecs_task_definitionwe have the optionaltask_role_arn, but not all services have a task role and I can't find a solution to set the default value toomittedorNone.