Reference Variable inside Module - terraform

I am trying to reference a variable declared inside a module to update another variable in the same module and i am unable to find a guide as to how i can reference the variable.
Here is my code sippet
module "cluster" {
source = "..."
var1 = value1 # directly passing value
var2 = module.cluster.var1 # I need to update this variable value based on value of var1
I am facing below error during terraform plan
Terraform v1.0.11
on linux_amd64
Configuring remote state backend...
Initializing Terraform configuration...
Error: Unsupported attribute
│
│ on main.tf line 04, in module "cluster":
│ 04: var2 = module.cluster.var1
│ ├────────────────
│ │ module.cluster is a object, known only after apply
│
│ This object does not have an attribute named "var1".
I have also tried using referencing using local.var1 shown below
module "cluster" {
source = "..."
var1 = value1 # directly passing value
var2 = local.var1 # I need to update this variable value based on value of var1
and then i encounter below error
Terraform v1.0.11
on linux_amd64
Configuring remote state backend...
Initializing Terraform configuration...
╷
│ Error: Reference to undeclared local value
│
│ on main.tf line 04, in module "cluster":
│ 04: var2 = local.var1
│
│ A local value with the name "var1" has not been declared.
╵
any lead will be helpful.
Regards

Your second attempt, using a local variable, is on the right track, but you have to actually declare the local variable:
locals {
var1 = value1
}
module "cluster" {
source = "..."
var1 = local.var1
var2 = local.var1

Related

Key Vault Secret Time Expiry

I am trying to set an expiry date that is dynamic in a Terraform template. The idea is to get current date and add 6 months to that date and use that as the expiry date for the secret, however I am struggling to do so.
I am trying to achieve this using the time_offset and timestamp() but it isn't working and I get the following error.
main.tf
resource "time_offset" "expiry_date" {
offset_months = 6
}
resource "azurerm_key_vault_secret" "local_admin_pwd" {
name = "LocalAdminPassword"
value = random_password.pwd.result
key_vault_id = azurerm_key_vault.keyvault.id
expiration_date = timestamp(time_offset.expiry_date.rfc3339)
}
error
│ Error: Too many function arguments
│
│ on key_vault/main.tf line 56, in resource "azurerm_key_vault_secret" "local_admin_pwd":
│ 56: expiration_date = timestamp(time_offset.expiry_date.rfc3339)
│ ├────────────────
│ │ while calling timestamp()
│
│ Function "timestamp" expects only 0 argument(s).
The built-in timestamp function does not expect any arguments:
Function "timestamp" expects only 0 argument(s).
The expiration_date argument should get the value from the attribute provided by the time_offset resource only:
expiration_date = time_offset.expiry_date.rfc3339

Terraform - How to initialize set variable in tfvars

Background
The Terraform document clearly states variable defined in the root module can be set in tfvars file.
Type Constraints
The type constructors allow you to specify complex types such as collections:
set(<TYPE>)
Assigning Values to Root Module Variables
When variables are declared in the root module of your configuration, they can be set in a number of ways:
In variable definitions (.tfvars) files, either specified on the command line or automatically loaded.
An input variable of type set can be defined in a root module.
variables.tf
variable "roles" {
description = "IAM roles to grant to the service account"
type = set(string)
}
Question
Please advise how to initialize the set variable in tfvars? Using function is not allowed, and as far as I looked around, it looks there is no example in the Terraform documentations. Or if setting set is not supported, is it clearly documented?
terraform.tfvars
roles = toset([
"roles/cloudsql.client",
"roles/bigquery.dataEditor",
"roles/storage.admin",
"roles/pubsub.edito",
"roles/secretmanager.secretAccessor",
"roles/artifactregistry.reader"
])
Error: Function calls not allowed
│
│ on sa.auto.tfvars line 1:
│ 1: roles = toset([
│ 2: "roles/cloudsql.client",
│ 3: "roles/bigquery.dataEditor",
│ 4: "roles/storage.admin",
│ 5: "roles/pubsub.edito",
│ 6: "roles/secretmanager.secretAccessor",
│ 7: "roles/artifactregistry.reader"
│ 8: ])
You just define it as:
roles = [
"roles/cloudsql.client",
"roles/bigquery.dataEditor",
"roles/storage.admin",
"roles/pubsub.edito",
"roles/secretmanager.secretAccessor",
"roles/artifactregistry.reader"
]
TF will automatically convert it to the correct type.

How to create string output with splat operator in terraform

I am creating several count - based ELBs with terraform.
e.g.
resource "aws_elb" "webserver_example" {
count = var.create_webserver
name = var.name
subnets = data.aws_subnet_ids.default.ids
security_groups = [aws_security_group.elb[count.index].id]
}
I therefore want to be able to get as outputs their http endpoints.
These outputs I assume shoul be strings, and their should somehow incorporate each elb's dns name.
However the following approach using splat, does not work
output "url" {
value = "http://${aws_elb.webserver_example.*.dns_name}:${var.elb_port}"
}
│ Error: Invalid template interpolation value
│
│ on outputs.tf line 2, in output "url":
│ 2: value = "http://${aws_elb.webserver_example.*.dns_name}:${var.elb_port}"
│ ├────────────────
│ │ aws_elb.webserver_example is empty tuple
│
│ Cannot include the given value in a string template: string required.
╵
Is there a way to print multiple count-based strings?
From what I was able to infer from just the code you provided, your var.create_webserver will have different count values (e.g. >= 0). The answer to your specific question is in this code block:
output "url" {
value = [
for dns_name in aws_elb.webserver_example.*.dns_name :
format("http://%s:%s", dns_name, var.elb_port)
]
}
However, be sure you introduce some way to make the names of your Security Groups and ELBs different, because that will be your next error. For example, name = "${var.name}-${count.index}".
Once you get to that point, you will have output that looks like this:
Outputs:
url = [
"http://so-0-2118247212.us-east-1.elb.amazonaws.com:443",
"http://so-1-1137510015.us-east-1.elb.amazonaws.com:443",
]

Can we change something in child modules ".terraform/modules"?

When I run terraform plan I got the following errors:
Error: Reference to undeclared input variable
│
│ on .terraform/modules/ec2-datapipeline/main.tf line 5, in resource "aws_instance" "this":
│ 5: count = "${var.count}"
│
│ An input variable with the name "count" has not been declared. This
│ variable can be declared with a variable "count" {} block.
╵
╷
│ Error: Incorrect attribute value type
│
│ on .terraform/modules/ec2-datapipeline/main.tf line 13, in resource "aws_instance" "this":
│ 13: vpc_security_group_ids = ["${var.vpc_security_group_ids}"]
│ ├────────────────
│ │ var.vpc_security_group_ids is a list of string, known only after apply
│
│ Inappropriate value for attribute "vpc_security_group_ids": element 0:
│ string required.
╵
╷
│ Error: Unsupported argument
│
│ on .terraform/modules/ec2-datapipeline/main.tf line 23, in resource "aws_instance" "this":
│ 23: root_block_device = "${var.root_block_device}"
│
│ An argument named "root_block_device" is not expected here. Did you mean to
│ define a block of type "root_block_device"?
╵
╷
│ Error: Unsupported argument
│
│ on .terraform/modules/ec2-datapipeline/main.tf line 24, in resource "aws_instance" "this":
│ 24: ebs_block_device = "${var.ebs_block_device}"
│
│ An argument named "ebs_block_device" is not expected here. Did you mean to
│ define a block of type "ebs_block_device"?
╵
╷
│ Error: Unsupported argument
│
│ on .terraform/modules/ec2-datapipeline/main.tf line 25, in resource "aws_instance" "this":
│ 25: ephemeral_block_device = "${var.ephemeral_block_device}"
│
│ An argument named "ephemeral_block_device" is not expected here. Did you
│ mean to define a block of type "ephemeral_block_device"?
╵
╷
│ Error: Error in function call
│
│ on .terraform/modules/ec2-datapipeline/main.tf line 36, in resource "aws_instance" "this":
│ 36: tags = "${merge(var.tags, map("Name", format("%s-%d", var.name, count.index+1)))}"
│ ├────────────────
│ │ count.index is a number, known only after apply
│ │ var.name will be known only after apply
│
│ Call to function "map" failed: the "map" function was deprecated in
│ Terraform v0.12 and is no longer available; use tomap({ ... }) syntax to
│ write a literal map.
When I fixed them in .terraform/modules/main.tf and variables.tf files, plan was successful and it went through when I trigger from CLI. But, when I actually push the code when I trigger a plan from UI it doesn't work.
So, when I do terraform init --upgrade. It came back to normal and I can see the same issues.
Could you please help me in solving this? thanks!
The stuff in .terraform/modules/ec2-datapipeline/main.tf is actually the main.tf file from an external module called "ec2-datapipeline" referenced somewhere in your own code (look for module "ec2-datapipeline").
You have to fix the bug in the source for "ec2-datapipeline", commit and tag it, then update the source reference in your own code.
The reason your changes disappear on reinitialization is, that you passed the --upgrade switch which tells Terraform to redownload the external module sources, even if they are cached locally in the .terraform/modules cache.

what's causing terraform error: Call to function "formatlist" failed: error on format iteration 0: unsupported value for "%s" at 5: string required

In my terraform code I have the following locals
locals {
merged_acl_contributors = concat(var.workspace.acl.contributors, azurerm_synapse_workspace.workspace.identity)
contributors = formatlist("user:%s:rwx", local.merged_acl_contributors)
}
var.workspace.acl.contributors does not have a value (just has []). When I try to deploy this I get:
│ Error: Error in function call
│
│ on modules/synapse_v2/main.tf line 10, in locals:
│ 10: contributors = formatlist("user:%s:rwx", local.merged_acl_contributors)
│ ├────────────────
│ │ local.merged_acl_contributors is tuple with 1 element
│
│ Call to function "formatlist" failed: error on format iteration 0:
│ unsupported value for "%s" at 5: string required.
identity in azurerm_synapse_workspace.workspace is a block with multiple attributes. You have to choose what you want. For example:
merged_acl_contributors = concat(var.workspace.acl.contributors, [azurerm_synapse_workspace.workspace.identity.principal_id])
Looking at local.merged_acl_contributors was the answer. The value was wrong. Instead of azurerm_synapse_workspace.identity, it needed to be azurerm_synapse_workspace.managedidentity.

Resources