I have a module which uses a variable of object type
variable "table" {
type = object({
name = string
read_capacity = number
write_capacity = number
arn = string
policy_name = string
})
}
I am not able to understand how to initialize this and pass to the module
locals {
table_dev_configs = {
arn = "arn:aws:dynamodb:us-east-2:123456789:table/my-table-dev"
name = "some_name"
policy_name = "some_policy"
read_capacity = 20
write_capacity = 20
}
}
module "my_table_dev" {
source = "../../modules/my_table"
table = local.table_dev_configs
}
I mean locals.table_dev_configs looks I am initializing a Map instead of an object.
../modules/my_table.tf
resource "aws_dynamodb_table" "my_table" {
name = var.table.name
read_capacity = var.table.read_capactity
write_capacity = var.table.write_capactity
hash_key = "id"
}
Doing it the Map way gives me this error:
│ Error: Unsupported attribute
│
read_capacity = var.table.read_capactity
│ ├────────────────
│ │ var.table is a object, known only after apply
│
│ This object does not have an attribute named "read_capactity".
╵
What is the right way to initialize an object?
Instead of
read_capacity = var.table.read_capactity
write_capacity = var.table.write_capactity
it should be
read_capacity = var.table.read_capacity
write_capacity = var.table.write_capacity
Related
I am trying to add tags to a launch template so that the ec2 nodes are tagged and named..
When I add the hardcoded tags inside the module it works, but the idea is to have dynamic tags and be able to merge with the local ones.
module
resource "aws_autoscaling_group" "ecs_asg" {
name = var.name_asg
max_size = var.max_size
min_size = var.min_size
.
.
.
service_linked_role_arn = var.service_linked_role_arn
tags = var.asg_tags
launch_template {
id = aws_launch_template.launch_template.id
version = "$Latest"
}
}
variables.tf
variable "asg_tags" {
type = map(string)
default = {}
}
main.tf
name_asg = "leo-nombre-asg"
max_size = var.max_size
min_size = var.min_size
.
.
.
asg_tags = merge(
local.tags,
{
propagate_at_launch=true,
},
)
locals.tf
locals {
tags = {
"Accountable" = "business"
"Deploy" = "terraform"
"Role" = "services"
}
}
terraform validate
│ Error: Incorrect attribute value type
│
│ on modules\ecs\main.tf line 38, in resource "aws_autoscaling_group" "ecs_asg":
│ 38: tags = var.asg_tags
│ ├────────────────
│ │ var.asg_tags is a map of string
│
│ Inappropriate value for attribute "tags": set of map of string required.
The two fixes necessary here are both for the type in the asg_tags parameter argument value:
asg_tags = [merge(local.tags, { "propagate_at_launch" = "true" })]
Here we use the list/set constructor to cast the type set(map(string)). Terraform will coerce to set instead of list with the constructor as long as the type is specified to be set instead. Since we need to fix the type declaration anyway to be compatible with the resource attribute schema, this is convenient to do:
variable "asg_tags" {
type = set(map(string))
default = {}
}
Module giving "Reference to undeclared resource" when I am creating a Google Container cluster and I am using two resources with same dynamic input value "node_config"
This is my main.tf file
resource "google_container_cluster" "primary" {
name = var.name
location = var.location
description = var.description
project = var.project
# We can't create a cluster with no node pool defined, but we want to only use
# separately managed node pools. So we create the smallest possible default
# node pool and immediately delete it.
# default_max_pods_per_node = var.default_max_pods_per_node
enable_tpu = var.enable_tpu
enable_shielded_nodes = var.enable_shielded_nodes
enable_legacy_abac = var.enable_legacy_abac
enable_kubernetes_alpha = var.enable_kubernetes_alpha
enable_intranode_visibility = var.enable_intranode_visibility
node_locations = var.node_locations
resource_labels = var.resource_labels
remove_default_node_pool = var.remove_default_node_pool
initial_node_count = var.initial_node_count
dynamic "node_config" {
for_each = var.node_config
content {
disk_size_gb = node_config.value["disk_size_gb"]
disk_type = node_config.value["disk_type"]
image_type = node_config.value["image_type"]
labels = node_config.value["labels"]
local_ssd_count = node_config.value["local_ssd_count"]
machine_type = node_config.value["machine_type"]
metadata = node_config.value["metadata"]
min_cpu_platform = node_config.value["min_cpu_platform"]
oauth_scopes = node_config.value["oauth_scopes"]
preemptible = node_config.value["preemptible"]
dynamic "shielded_instance_config" {
for_each = node_config.value.shielded_instance_config
content {
enable_integrity_monitoring = shielded_instance_config.value["enable_integrity_monitoring"]
enable_secure_boot = shielded_instance_config.value["enable_secure_boot"]
}
}
tags = node_config.value["tags"]
}
}
}
resource "google_container_node_pool" "primary_preemptible_nodes" {
name = var.nodepool_name
location = var.location
project = var.project
cluster = google_container_cluster.primary.name
node_count = var.nodepool_node_count
node_locations = var.node_locations
dynamic "node_config" {
for_each = var.ndpool_node_config
content {
disk_size_gb = ndpool_node_config.value["disk_size_gb"]
disk_type = ndpool_node_config.value["disk_type"]
preemptible = ndpool_node_config.value["preemptible"]
image_type = ndpool_node_config.value["image_type"]
machine_type = ndpool_node_config.value["machine_type"]
oauth_scopes = ndpool_node_config.value["oauth_scopes"]
}
}
}
This my module definition inside module folder
module "google_container_cluster" {
source = "../"
name = var.name
location = var.location
description = var.description
project = var.project
# We can't create a cluster with no node pool defined, but we want to only use
# separately managed node pools. So we create the smallest possible default
# node pool and immediately delete it.
# default_max_pods_per_node = var.default_max_pods_per_node
enable_tpu = var.enable_tpu
enable_shielded_nodes = var.enable_shielded_nodes
enable_legacy_abac = var.enable_legacy_abac
enable_kubernetes_alpha = var.enable_kubernetes_alpha
enable_intranode_visibility = var.enable_intranode_visibility
node_locations = var.node_locations
resource_labels = var.resource_labels
remove_default_node_pool = var.remove_default_node_pool
initial_node_count = var.initial_node_count
node_config = var.node_config
nodepool_name = var.nodepool_name
nodepool_node_count = var.nodepool_node_count
}
My terraform.tfvars are as follows
name = "tf-gcp-cluster"
location = "us-central1-c"
description = "Cluster Creation using TF"
project = "gcp-terraform-prjt"
#default_max_pods_per_node = ""
enable_tpu = false
enable_shielded_nodes = false
enable_legacy_abac = false
enable_kubernetes_alpha = false
enable_intranode_visibility = false
node_locations = []
resource_labels = {
"test" = "tftestgcp"
}
remove_default_node_pool = true
initial_node_count = 1
node_config = [{
disk_size_gb = "10"
disk_type = "pd-standard"
image_type = "cos_containerd"
labels = {
"test" = "tf-container-cluster"
}
local_ssd_count = "0"
machine_type = "e2-micro"
metadata = {
"key" = "value"
}
min_cpu_platform = ""
oauth_scopes = [
"https://www.googleapis.com/auth/cloud-platform"
]
preemptible = true
shielded_instance_config = [{
enable_integrity_monitoring = false
enable_secure_boot = false
}]
tags = ["value"]
}]
nodepool_name = "tf-nodepool"
nodepool_node_count = 1
ndpool_node_config = [{
disk_size_gb = 10
disk_type = "pd-standard"
image_type = "cos_container"
machine_type = "e2-micro"
oauth_scopes = [
"https://www.googleapis.com/auth/cloud-platform"
]
preemptible = false
}]
I have supplied value for both "node_config" and "ndpool_node_config" but for some reason it is giving me following error when i run terraform plan command
╷
│ Error: Reference to undeclared resource
│
│ on ../main.tf line 57, in resource "google_container_node_pool" "primary_preemptible_nodes":
│ 57: disk_size_gb = ndpool_node_config.value["disk_size_gb"]
│
│ A managed resource "ndpool_node_config" "value" has not been declared in module.google_container_cluster.
╵
╷
│ Error: Reference to undeclared resource
│
│ on ../main.tf line 58, in resource "google_container_node_pool" "primary_preemptible_nodes":
│ 58: disk_type = ndpool_node_config.value["disk_type"]
│
│ A managed resource "ndpool_node_config" "value" has not been declared in module.google_container_cluster.
╵
╷
│ Error: Reference to undeclared resource
│
│ on ../main.tf line 59, in resource "google_container_node_pool" "primary_preemptible_nodes":
│ 59: preemptible = ndpool_node_config.value["preemptible"]
│
│ A managed resource "ndpool_node_config" "value" has not been declared in module.google_container_cluster.
╵
╷
│ Error: Reference to undeclared resource
│
│ on ../main.tf line 60, in resource "google_container_node_pool" "primary_preemptible_nodes":
│ 60: image_type = ndpool_node_config.value["image_type"]
│
│ A managed resource "ndpool_node_config" "value" has not been declared in module.google_container_cluster.
╵
╷
│ Error: Reference to undeclared resource
│
│ on ../main.tf line 61, in resource "google_container_node_pool" "primary_preemptible_nodes":
│ 61: machine_type = ndpool_node_config.value["machine_type"]
│
│ A managed resource "ndpool_node_config" "value" has not been declared in module.google_container_cluster.
╵
╷
│ Error: Reference to undeclared resource
│
│ on ../main.tf line 62, in resource "google_container_node_pool" "primary_preemptible_nodes":
│ 62: oauth_scopes = ndpool_node_config.value["oauth_scopes"]
│
│ A managed resource "ndpool_node_config" "value" has not been declared in module.google_container_cluster.
I want the value to be passed down as i have defined them, if i remove it created the node_pool with default values rather than the values defined by me.
I am new to terraform and trying to change the existing script were we used to create 1 route 53 zone and corresponding route 53 record , now the requirement is to add one more zone and 53 record (correspondingly) , i am trying multi level map , i need your help correct my code
tf.vars
variable "facade_hostname" = {
type = "map"
default = {
old_mobile_facade_hostname = "xxx.morgen.nl"
new_mobile_facade_hostname = "xxx.test.nl"
}
}
dns_config = {
old_dns_records = {
mobile_facade = {
name = "xxx.morgen.nl",
ttl = "5",
type = "A",
records = [
"1.2.3.4"]
}
},
new_dns_records = {
mobile_facade = {
name = "xxx.test.nl",
ttl = "5",
type = "A",
records = [
"5.6.7.8"]
}
}
}
varibles.tf
variable "dns_config" {
type = map(object({
name = string
ttl = string
type = string
records = string
}))
default = {}
}
variable "facade_hostname" {
type = map(object({
old_mobile_facade_hostname = string
new_mobile_facade_hostname = string
}))
default = {}
}
and finally my resource creation
resource "aws_route53_zone" "private" {
for_each = var.facade_hostname
count = var.dns_config != "" && var.facade_hostname != "" ? 1 : 0
name = var.facade_hostname
force_destroy = true
vpc {
vpc_id = module.vpc_private.vpc_id
}
}
resource "aws_route53_record" "A" {
for_each = var.facade_hostname
count = var.dns_config != "" && var.facade_hostname!= "" ? 1 : 0
zone_id = aws_route53_zone.private[count.index].zone_id
name = var.dns_config.facade_hostname.name
ttl = var.dns_config.facade_hostname.ttl
type = var.dns_config.facade_hostname.type
records = var.dns_config.facade_hostname.records
allow_overwrite = true
}
Error i am encountering, when running the terraform init
╷
│ Error: Invalid combination of "count" and "for_each"
│
│ on route53.tf line 2, in resource "aws_route53_zone" "private":
│ 2: for_each = var.facade_hostname
│
│ The "count" and "for_each" meta-arguments are mutually-exclusive, only one
│ should be used to be explicit about the number of resources to be created.
╵
╷
│ Error: Invalid combination of "count" and "for_each"
│
│ on route53.tf line 12, in resource "aws_route53_record" "A":
│ 12: for_each = var.facade_hostname
│
│ The "count" and "for_each" meta-arguments are mutually-exclusive, only one
│ should be used to be explicit about the number of resources to be created.
╵
aws-vault: error: exec: Failed to wait for command termination: exit status 1
Thanks
Finally after spending some time , this seems a working solution incase if it helps any one in future , to create couple of hosted zone and create different A record based on hosted zone,
resource "aws_route53_zone" "private" {
for_each = var.mobile_facade_hostname
name = each.key
force_destroy = true
vpc {
vpc_id = module.vpc_private.vpc_id
}
}
resource "aws_route53_record" "A" {
for_each = aws_route53_zone.private
zone_id = each.value["zone_id"]
name = trimsuffix(each.value["name"], ".")
type = "A"
ttl = "5"
records = [var.mobile_facade_hostname[trimsuffix(each.value["name"], ".")]]
My tfvars
mobile_facade_hostname = { "x.y.nl" = "1.2.3.4", "a.b.nl" = "5.6.7.8" }
variables.tf
variable "mobile_facade_hostname" {
type = map(string)
default = {}
}
While defining my module, I do this:
module "activate_alarms" {
source = "../_modules/aws/.."
config = module.config
alarm_arns = ["arn:aws:cloudwatch:eu-central-123:test-alarm"]
}
variable "alarm_arns" {
type = list(string)
}
resource "aws_lambda_function" "processing_lambda" {
filename = data.archive_file.lambda_zip.output_path
function_name = local.processing_lambda_name
handler = "enable_disable_alarms.lambda_handler"
source_code_hash = data.archive_file.lambda_zip.output_base64sha256
role = aws_iam_role.lambda_role.arn
runtime = "python3.9"
tags = var.config.tags
environment {
variables = {
alarm_arns = local.alarm_arns
}
}
}
However, I get an error:
Error: Incorrect attribute value type
│
│ on ../_modules/aws/enable_disable_alarms/processing_lambda.tf line 20, in resource "aws_lambda_function" "processing_lambda":
│ 20: variables = {
│ 23: alarm_arns = local.alarm_arns
│ 30: }
│ ├────────────────
│ │ local.alarm_arns is a list of string, known only after apply
│
│ Inappropriate value for attribute "variables": element "alarm_arns": string required.
What's the correct way to pass a list of strings?
Edit:
locals {
config = var.config
alarm_arns = "${var.alarm_arns}"
}
You can't pass list(string) directly as environment into lambda. You have to make it into string first, e.g.:
environment {
variables = {
alarm_arns = jsonencode(var.alarm_arns)
}
}
Then in your lambda you would have to convert it back to list of strings according to your programming language.
I am trying to write a terraform code for creating workspaces and will be using the same for future creation as well. I am facing an issue while referencing the bundle_ids since there are multiple bundles available and it changes according to the req. each time. if someone can suggest a better approach to this.
resource "aws_workspaces_workspace" "this" {
directory_id = var.directory_id
for_each = var.workspace_user_names
user_name = each.key
bundle_id = [local.bundle_ids["${each.value}"]]
root_volume_encryption_enabled = true
user_volume_encryption_enabled = true
volume_encryption_key = var.volume_encryption_key
workspace_properties {
user_volume_size_gib = 50
root_volume_size_gib = 80
running_mode = "AUTO_STOP"
running_mode_auto_stop_timeout_in_minutes = 60
}
tags = var.tags
}
terraform.tfvars
directory_id = "d-xxxxxxx"
##Add the Workspace Username & bundle_id;
workspace_user_names = {
"User1" = "n"
"User2" = "y"
"User3" = "k"
}
locals.tf
locals {
bundle_ids = {
"n" = "wsb-nn"
"y" = "wsb-yy"
"k" = "wsb-kk"
}
}
Terraform plan
Error: Incorrect attribute value type
│
│ on r_aws_workspaces.tf line 8, in resource "aws_workspaces_workspace" "this":
│ 8: bundle_id = [local.bundle_ids["${each.value}"]]
│ ├────────────────
│ │ each.value will be known only after apply
│ │ local.bundle_ids is object with 3 attributes
│
│ Inappropriate value for attribute "bundle_id": string required.
At the movement you have a list, but it should be string. Assuming everything else is correct, the following should address your error:
bundle_id = local.bundle_ids[each.value]