I got something like this:
global_tags = {
"Tag_Name1" = "Tag_Value1"
"Tag_Name2" = "Tag_Value2"
}
virtual_machine = {
"my-host-1.foo.bar" {
cores = 3
memory = 2048
host_tags = {
"Tag_Name3" = "Tag_Value3"
"Tag_Name4" = "Tag_Value4"
}
}
"my-host-2.foo.bar" {
cores = 5
memory = 4096
host_tags = {
"Tag_Name5" = "Tag_Value5"
"Tag_Name6" = "Tag_Value6"
}
}
}
variable "global_tags" {
type = map(any)
default = null
}
variable "virtual_machine" {
type = map(object({
cores = number
memory = bool
host_tags = map(any)
}))
}
data "vsphere_tag_category" "tag_cat" {
for_each = var.global_tags
name = each.key
}
data "vsphere_tag" "global_tags" {
for_each = var.global_tags
name = each.value
category_id = data.vsphere_tag_category.tag_cat[each.key].id
}
locals {
global_tag_ids = [
for tags in data.vsphere_tag.global_tags :
tags.id
]
}
locals {
all_host_tags = flatten([
for hostname, outer_value in var.virtual_machines : [
for tag_key, tag_value in outer_value.custom_tags : {
hostname = hostname
tag_key = tag_key
tag_value = tag_value
}
]
])
}
data "vsphere_tag_category" "host_tag_cats" {
for_each = { for v in local.all_host_tags : "${v.hostname}.${v.tag_key}" => v }
name = each.value.tag_key
}
data "vsphere_tag" "host_tags" {
for_each = { for v in local.all_host_tags : "${v.hostname}.${v.tag_key}" => v }
name = each.value.tag_value
category_id = data.vsphere_tag_category.host_tag_cats[each.key].id
}
resource "vsphere_virtual_machine" "test" {
for_each = var.virtual_machine
name = each.key
num_cpus = each.value.cores
cpu_hot_add_enabled = true
memory_hot_add_enabled = true
memory = each.value.memory
...
tags = local.global_tag_ids
clone {
template_uuid = data.vsphere_virtual_machine.test.id
}
}
I want to assign the tags to the host. with the "global_tags" this is no problem. this works fine. but now i want to merge the global_tags_ids with the ids from the host_tags. my problem here is, that i only want to assign the global_tags with the appropriate host_tags. so nothing get mixed up. has someone an idea to achieve that?
I tried to access these keys via the mapping keys, but i only get it right, when i set an explicit key.
I want to pass a merged array to "tags" in this ressource, so host1 gets the global tag + his host_tags and so on.
Sorry for the slow reply (I'm the guy who tried to answer on IRC then went silent once I saw the complexity).
Here's how I would approach this problem, it might be possible to clean it up even more or do some shortcuts in the processing.
Instead of having multiple data sources one for the global tags and one for the host tags, I have attempted to combine all of the category+tag variations into a single list that I then use as the input for a single datasource referencing all tags using category name + tag name as the key.
Then when iterating over the tags to be used there's only one source with a uniform format to the key, for readability I pulled the lookup into some extra locals but this could also have been done inline.
I'm not able to run it using your resources but I ended up with the following code that I think does what you want.
locals {
global_tag_details = [for category_name, tag_name in var.global_tags : { category_name : category_name, tag_name : tag_name }]
host_tag_details = flatten([for hostname, host_details in var.virtual_machine : [for category_name, tag_name in host_details.host_tags : { category_name : category_name, tag_name : tag_name }]])
all_tag_details = distinct(concat(local.global_tag_details, local.host_tag_details))
all_category_names = distinct([for tag_details in local.all_tag_details : tag_details.category_name])
all_tags_map = { for tag_details in local.all_tag_details : "${tag_details.category_name}.${tag_details.tag_name}" => tag_details }
}
data "vsphere_tag_category" "this" {
for_each = toset(local.all_category_names)
name = each.key
}
data "vsphere_tag" "this" {
for_each = local.all_tags_map
name = each.value.tag_name
category_id = data.vsphere_tag_category.this[each.value.category_name].id
}
locals {
global_tag_ids = [for category_name, tag_name in var.global_tags : data.vsphere_tag.this["${category_name}.${tag_name}"].id]
hostname_tag_ids = { for hostname, host_details in var.virtual_machine : hostname => [for category_name, tag_name in host_details.host_tags : data.vsphere_tag.this["${category_name}.${tag_name}"].id] }
}
resource "vsphere_virtual_machine" "this" {
for_each = var.virtual_machine
name = each.key
tags = concat(local.hostname_tag_ids[each.key], local.global_tag_ids)
}