I’m trying to write up some terraform code which will create a function and preferably create a new execution role, however the user does have the option of attaching an existing role.
variable "create_role" {
description = "Controls whether IAM role for Lambda Function should be created"
type = bool
default = true
}
variable "lambda_role_arn" {
description = " IAM role ARN attached to the Lambda Function. This governs both who / what can invoke your Lambda Function, as well as what resources our Lambda Function has access to. See Lambda Permission Model for more details."
type = string
}
resource "aws_lambda_function" "lambda_function" {
function_name = function_name
role = var.create_role ? aws_iam_role.lambda[0].arn : var.lambda_role_arn
The drawback with this method is that there is a chance of create_role = false and lambda_role_arn being undefined.
If there a method of only allowing lambda_role_arn to be null IF create_role is true?
Thanks in advance.
2
Answers
In this situation the objective can be achieved with the
try
function:If the first value can be successfully resolved (corresponding to the managed role), then it will be returned and assigned. Otherwise the next variadic argument will be returned and assigned (corresponding to the input variable). If neither can be resolved (signifying role not managed nor input), then the
null
type will be returned and assigned as desired (effectively ignoring the parameter value).Note the
coaslece
function that provides analogous null-coaslescing functionality cannot be used as it does not permit returningnull
.One way to solve this would be to prevent the invalid situation from occurring in the first place by making a single variable which controls both of these behaviors together. This sort of design is also often easier for users of a module to understand, because they can see everything related to a particular behavior all in one place.
Based on your requirements, I would probably design this so that the module declares its own role only if the caller doesn’t provide one:
The idea of there being an automatic default behavior when an argument is left unset is a pretty common situation in Terraform — lots of resource type arguments work like that, for example — so a design like the above fits in with typical Terraform design idiom: either specify an explicit
lambda_role_arn
in the caller’smodule
block, or omit it to get the default one.However, in some situations that might be considered a little too "magical". For example, it might be true that for this particular module the common case is to pass in a role while having it automatically declared inline is the unusual case that must be explicitly selected. If that were true then I would choose a slightly different approach where the user of the module must specify how the role ARN is to be assigned, but can choose either option:
In this variation the caller of the module must choose between one of the two possible modes; omitting the argument altogether is invalid:
(Side note: I called the boolean attribute "automatic" instead of "create" because it’s a bit of a misnomer to say that the module "creates" the role. Instead, the module declares the role and then on the first
terraform apply
Terraform will plan to create it, but after that the role will already exist and so the module will just continue to manage it in whatever way needed to keep the remote object matching the changes to the configuration over time. Not a big deal if you do still want to call itcreate
, but I find that tends to confuse some folks new to Terraform who aren’t yet accustomed to its declarative programming model.)