I am trying to use a map variable(which has 2 lambda names). Also, I want to pass a local variable inside the key values, as shown in the example below.However, I get an error as variable not allowed here. Any suggestions/advice?
variables.tf:
variable "lambdas" {
type = map(string)
default = {
"lambda1_name-${local.global_suffix}" = "lambda_function1",
"lambda2_name-${local.global_suffix}" = "lambda_function2"
}
}
locals{
global_suffix = "${var.env}-${var.project}${var.branch_hash}"
}
main.tf:
resource "aws_lambda_function" "main" {
for_each = var.lambdas
function_name = each.key
handler = "${each.value}.${var.handler}"
filename = "${path.module}/modules/lambda-main/${each.value}.zip"
source_code_hash = data.archive_file.init[each.key].output_base64sha256
role = module.lambda_iam_role.arn
runtime = "python3.6"
memory_size = "2048"
timeout = "900"
tags = local.tags
description = "${var.project} Lambda Function"
}
I am trying to use one lambda resource block to create 2 lambda functions(hence using the map variable)
Your variable default values can't by dynamic. They must be static values. Thus, instead of having var.lambdas, in your case it would be better to use locals:
variable "lambdas" {
type = map(string)
default = {
"lambda1_name" = "lambda_function1",
"lambda2_name" = "lambda_function2"
}
}
locals {
lambdas = {for key, value in var.lambdas: "${key}-${local.global_suffix}" => value}
}
Them you would:'
resource "aws_lambda_function" "main" {
for_each = local.lambdas
....
}
Related
I am trying to create a Data Source for Assume Role Policy according to the terraform documentation,
Defining the "PRINCIPALS" code block and assigning the harcoded data works without a problem, but I want to assign the dynamic values from a tfvars file. When using the same dynamic block for "STATEMENT" it does not recognize the values even though it is similar to the initial block, I hope I have made myself understood.
variables.tf
variable "assume_role" {
description = "Assume example"
type = map(object({
sid = string
effect = string
actions = list(string)
principals = map(string)
}))
}
main.tf
data "aws_iam_policy_document" "assume-role-policy" {
dynamic "statement" {
for_each = var.assume_role
content {
actions = lookup(statement.value, "actions")
effect = lookup(statement.value, "effect")
sid = lookup(statement.value, "sid")
# this way works fine.. but with the dynamic block doesn't
# principals {
# type = "Service"
# identifiers = ["glue.amazonaws.com"]
# }
dynamic "principals" {
for_each = lookup(statement.value, "principals", {})
content {
type = lookup(principals.value, "type")
identifiers = lookup(principals.value, "identifiers")
}
}
}
}
}
resource "aws_iam_role" "instance" {
name = "instance_role_example"
assume_role_policy = data.aws_iam_policy_document.assume-role-policy.json
}
inn.tfvars
assume_role = {
assume = ({
sid = "1010"
effect = "Allow"
actions = ["sts:AssumeRole"]
principals = {
type = "Service"
identifiers = "glue.amazonaws.com"
}
})
}
Result:
Thank you very much in advance
It does not work, because there is nothing in principals to iterate over. You have only a single map, not a list of maps, nor a map of maps. You just directly access the fields (no iteration required):
dynamic "principals" {
for_each = lookup(statement.value, "principals", {})
content {
type = lookup(statement.value.principals, "type")
identifiers = [lookup(statement.value.principals, "identifiers")]
}
}
I have a file fsx.tf with 2 resource blocks and a file prod.tfvars:
My fsx.tf looks like:
resource "aws_fsx_ontap_storage_virtual_machine" "fsx_svm" {
for_each = var.fsx_svm
file_system_id = aws_fsx_ontap_file_system.fsx.id
name = each.value.name
}
resource "aws_fsx_ontap_volume" "fsx_volumes" {
for_each = var.fsx_volumes
name = var.name
storage_virtual_machine_id = each.value.storage_virtual_machine_id
My prod.tfvars looks like:
fsx_svm = {
svm01 = {
name = "svm01-single-az"
}
}
fsx_volumes = {
vol01 = {
name = "FS"
storage_virtual_machine_id = fsx_svm.svm01.id
}
}
I get the following error:
Error: expected length of storage_virtual_machine_id to be in the range (21 - 21), got fsx_svm.svm01.id
OR
Variables not allowed here
How to set the attribute id of resource aws_fsx_ontap_storage_virtual_machine in the variable of fsx_volumes ? My goal is to be able to reuse the resource block for other .tfvars files.
In this case the best way to do this may be resource chaining with for_each [1]. This means instead of having to rely on variables you can just do this:
resource "aws_fsx_ontap_storage_virtual_machine" "fsx_svm" {
for_each = var.fsx_svm
file_system_id = aws_fsx_ontap_file_system.fsx.id
name = each.value.name
}
resource "aws_fsx_ontap_volume" "fsx_volumes" {
for_each = aws_fsx_ontap_storage_virtual_machine.fsx_svm
name = "${each.key}-${var.name}"
storage_virtual_machine_id = each.value.id
}
[1] https://developer.hashicorp.com/terraform/language/meta-arguments/for_each#chaining-for_each-between-resources
I have created 2 modules. One for SQS and another for SSM. My SQS creates 4 queues and i am trying to create corresponding entries in the parameter store for their url and arn. I am importing the SSM module inside my SQS module such that it creates the parameters right after SQS creation is done.
This is what my SQS module looks like :-
resource "aws_sqs_queue" "FirstStandardSQSQueue" {
name = "sqs-${var.stage}-one"
message_retention_seconds = var.SQSMsgRetention
redrive_policy = jsonencode({
deadLetterTargetArn = aws_sqs_queue.FirstDeadLetterQueue.arn
maxReceiveCount = 2
})
}
resource "aws_sqs_queue" "FirstDeadLetterQueue" {
name = "sqs-dead-letter-${var.stage}-one"
receive_wait_time_seconds = var.SQSRecvMsgWaitTime
}
resource "aws_sqs_queue" "SecondStandardSQSQueue" {
name = "sqs-${var.stage}-two"
message_retention_seconds = var.SQSMsgRetention
redrive_policy = jsonencode({
deadLetterTargetArn = aws_sqs_queue.SecondDeadLetterQueue.arn
maxReceiveCount = 3
})
}
resource "aws_sqs_queue" "SecondDeadLetterQueue" {
name = "sqs-dead-letter-${var.stage}-two"
receive_wait_time_seconds = var.SQSRecvMsgWaitTime
}
module "ssm" {
source = "../ssm/"
// How do i create a dynamic map???
for_each = var.Queues
name = "/new/${var.stage}/${each.key}"
type = "SecureString"
value = "${each.value}"
}
My SSM module looks like this :-
resource "aws_ssm_parameter" "main" {
name = var.name
type = var.type
value = var.value
}
I am trying to create either a map or somehow dynamically be able to pass values in my ssm module using for_each? I tried setting up something like this :-
variable "Queues" {
type = map
default = {
"FirstStandardSQSQueueUrl" = aws_sqs_queue.FirstStandardSQSQueue.url
"FirstStandardSQSQueueArn" = aws_sqs_queue.FirstStandardSQSQueue.arn
"SecondStandardSQSQueueUrl" = aws_sqs_queue.SecondStandardSQSQueue.url
"SecondStandardSQSQueueArn" = aws_sqs_queue.SecondStandardSQSQueue.arn
}
}
But this is invalid because i keep running into
Error: Variables not allowed line 40: Variables may not be used here.
Can someone suggest a better/right way to do it? Thank you.
As the error msg writes, you can't have dynamic variables. locals should be used instead.
locals {
Queues = {
"FirstStandardSQSQueueUrl" = aws_sqs_queue.FirstStandardSQSQueue.url
"FirstStandardSQSQueueArn" = aws_sqs_queue.FirstStandardSQSQueue.arn
"SecondStandardSQSQueueUrl" = aws_sqs_queue.SecondStandardSQSQueue.url
"SecondStandardSQSQueueArn" = aws_sqs_queue.SecondStandardSQSQueue.arn
}
}
Then you refer to the value as local.Queues in other parts of your code.
Variable
ip_set = [
{
name: "test-ip-set-1"
ip_list: ["10.0.0.1/32", "10.0.0.1/32"]
}
]
I want to loop through the ip_set variable and create IP sets per the length of ip_set and loop through ip_list within that dictionary
For e.g.
resource "aws_waf_ipset" "ipset" {
for_each = {for name, ip_list in var.ip_set: name => ip_list}
name = each.value.name
ip_set_descriptors {
type = "IPV4"
value = each.value.ip_list[ip_list_element_1]
}
ip_set_descriptors {
type = "IPV4"
value = each.value.ip_list[ip_list_element_2]
}
Error
If I do
ip_set_descriptors {
type = "IPV4"
value = tostring(each.value[*].ip_list)
}
I get
Invalid value for "v" parameter: cannot convert tuple to string.
FYI. value in ip_set_descriptors needs to be a string and I don't know how many elements are there
You can use dynamic blocks:
resource "aws_waf_ipset" "ipset" {
for_each = {for name, ip_list in var.ip_set: name => ip_list}
name = each.value.name
dynamic "ip_set_descriptors" {
for_each = each.value.ip_list
content {
type = "IPV4"
value = ip_set_descriptors.value
}
}
I would like to create AWS SSM Parameters using Terraform, with the parameters being passed in as input variables.
I see there is a for_each feature, but how can this be applied to top level properties within a terraform resource? From the documentation, the use of for_each appears to be restricted to not work on top level properties of a resource, am I misunderstanding?
This is what I am trying to accomplish:
main.tf
resource "aws_ssm_parameter" "ssm_parameters" {
for_each = var.params
content {
name = name.value
type = "String"
overwrite = true
value = paramValue.value
tags = var.tags
lifecycle {
ignore_changes = [
tags,
value
]
}
}
}
variables.tf
variable "params" {
default = [
{
name = "albUrl"
paramValue = "testa"
},
{
name = "rdsUrl1"
paramValue = "testb"
},
{
name = "rdsUrl2"
valparamValueue = "testc"
},
]
}
You can use for each, but you need to modify its syntax and fix syntax in your var.params:
variable "params" {
default = [
{
name = "albUrl"
paramValue = "testa"
},
{
name = "rdsUrl1"
paramValue = "testb"
},
{
name = "rdsUrl2"
paramValue = "testc"
},
]
}
Then to use for each, and create 3 ssm parameters:
resource "aws_ssm_parameter" "ssm_parameters" {
for_each = {for v in var.params: v.name => v.paramValue}
type = "String"
name = each.key
value = each.value
overwrite = true
}
In the above you have to project your list(map) to a map as it is required for for_each.