简体   繁体   English

如何将terraform中两个for_each循环的输出作为输入传递给其他tf资源

[英]How to pass output of two for_each loops in terraform as an input to other tf resource

I am trying to create a few Azure resources like VNET, Subnet and an NSG.我正在尝试创建一些 Azure 资源,例如 VNET、子网和 NSG。 I am making use of for_each meta argument to create multiple subnets and NSG's.我正在使用 for_each 元参数来创建多个子网和 NSG。 But, I am not able to figure out how to associate them using "azurerm_subnet_network_security_group_association".但是,我无法弄清楚如何使用“azurerm_subnet_network_security_group_association”将它们关联起来。 I am creating the output of subnet id's and NSG id's as a map, but I am not able to figure out how to create a association between subnet ID and NSG ID.我正在将子网 ID 和 NSG ID 的输出创建为映射,但我无法弄清楚如何在子网 ID 和 NSG ID 之间创建关联。 For ex: I have a subnet created called "public_subnet" and I want to associate "public_nsg" to public subnet and likewise for private.例如:我创建了一个名为“public_subnet”的子网,我想将“public_nsg”关联到公共子网,同样也关联到私有子网。 For now, I just want the assignment to be driven by just the names.现在,我只想让任务仅由名称驱动。

child module main.tf:子模块 main.tf:

resource "azurerm_virtual_network" "vnet" {
  name                = format("%s-%s-vnet", var.owner_custom, var.purpose_custom)
  location            = var.location
  resource_group_name = format("rg-%s-%s", var.owner_custom, var.purpose_custom)
  address_space       = var.address_space

}


resource "azurerm_subnet" "subnet" {
  for_each = var.subnets
  name = each.value["name"]
  address_prefixes = each.value["address_space"]
  resource_group_name = format("rg-%s-%s", var.owner_custom, var.purpose_custom)
  virtual_network_name = azurerm_virtual_network.vnet.name
}


resource "azurerm_network_security_group" "nsg" {
  for_each = var.nsg
  name = each.value["name"]
  location = var.location
  resource_group_name = format("rg-%s-%s", var.owner_custom, var.purpose_custom)
}


resource "azurerm_subnet_network_security_group_association" "nsg_association" {
  subnet_id = #need help here
  network_security_group_id = #need help here
}

child module variables.tf:子模块变量.tf:

variable "owner_custom" {
    description = "Short name of owner"
}

variable "purpose_custom" {
    description = "Custom purpose"
}
variable "location" {
  description = "Location where resource is to be created"
  
}
variable "address_space" {
  type = list
  description = "VNET CIDR Range"
}

variable "subnets" {
  description = "A map to create multiple subnets"
  type = map(object({
    name = string
    address_space = list(string)
  })) 
}

variable "nsg" {
  description = "A map of NSGs"
  type = map(object({
    name = string
  }))
  
}

child module output.tf:子模块 output.tf:

output "vnet_id" {
    value = azurerm_virtual_network.vnet.id
}

output "subnet_id" {
    value = tomap({
        for k, s in azurerm_subnet.subnet : k => s.id
    })
  
}

output "nsg_id" {
    value = tomap({
        for k,s in azurerm_network_security_group.nsg: k => s.id
    })
  
}

tfvars:变量:

#Referenced common across modules
owner_custom = "raghav"
purpose_custom = "demo"

#Referenced in resource-group module
owner = "test@test.com"
purpose = "test"
location = "australiaeast"
org = "org"

#Referenced in network module
address_space = ["10.10.0.0/21"]

subnets = {
    subnet1 = {
        name = "public_subnet"
        address_space = ["10.10.1.0/26"]
        }

    subnet2 = {
        name = "private_subnet"
        address_space = ["10.10.1.64/26"]
        }

    subnet3 = {
        name = "privatelink_subnet"
        address_space = ["10.10.1.128/26"]
        }
    
    subnet4 = {
        name = "AzureFirewallSubnet"
        address_space = ["10.10.1.192/26"]
        }
}

nsg = {
    public_nsg = {
        name = "public_nsg"
        }

    private_nsg = {
        name = "private_nsg"
        }
    }

From what you've described, it seems like your rule is that you want to use the part of the names before the first underscore as a sort of implied correlation key, which would mean that:根据您的描述,您的规则似乎是您希望将第一个下划线之前的名称部分用作一种隐含的相关键,这意味着:

  • public_subnet is associated with public_nsg public_subnetpublic_nsg相关联
  • private_subnet is associated with private_nsg private_subnetprivate_nsg相关联
  • privatelink_subnet is not associated with anything privatelink_subnet不与任何东西相关联
  • AzureFirewallSubnet is not associated with anything AzureFirewallSubnet不与任何东西相关联

The main task here then is to express that rule using some Terraform language expressions in order to create a lookup table from subnet to security group.此处的主要任务是使用一些 Terraform 语言表达式来表达该规则,以便创建从子网到安全组的查找表。

I'd typically start this by deriving some new data structures that capture the keys we'll use for matching, so that we can use those in the rest of the solution to look up these results concisely:我通常会从派生一些新的数据结构开始,这些数据结构捕获我们将用于匹配的键,以便我们可以在解决方案的其余部分中使用这些结构来简洁地查找这些结果:

locals {
  subnet_types = tomap({
    for k, s in var.subnets : k => split("_", s.name)[0]
  })
  nsg_types = tomap({
    for k, s in var.nsg : split("_", s.name)[0] => k
  })
}

This uses the split function to find all of the parts separated by underscores, and then [0] to select the first part.这使用split函数查找所有由下划线分隔的部分,然后[0]选择第一部分。 This should therefore produce the following mappings:因此,这应该产生以下映射:

local.subnet_types = {
  subnet1 = "public"
  subnet2 = "private"
  subnet3 = "privatelink"
  subnet4 = "AzureFirewallSubnet"
}
local.nsg_types = {
  public  = "public_nsg"
  private = "private_nsg
}

Notice that the values in local.subnet_ids correlate with the keys in local.nsg_types , which therefore gives enough information to reduce this into a mapping directly from subnet key to NSG key:请注意, local.subnet_ids 中的值与local.subnet_ids中的键local.nsg_types ,因此提供了足够的信息来将其简化为直接从子网键到 NSG 键的映射:

locals {
  subnet_nsgs = {
    for k, ty in local.subnet_ids :
    k => try(local.nsg_types[ty], null)
  }
}

This uses try to handle the situation where there isn't an NSG defined for a particular "type" keyword.这用于try处理没有为特定“类型”关键字定义 NSG 的情况。 The result of this should therefore be:因此,其结果应该是:

local.subnet_nsgs = {
  subnet1 = "public_nsg"
  subnet2 = "private_nsg"
  subnet3 = null
  subnet4 = null
}

This now has all of the information required to decide which security group associations to declare, but we will need one more transform to filter out the null elements (since we don't want to declare an association at all for those) and to pull in the other data we'll need to populate the resource arguments:这现在具有决定要声明哪些安全组关联所需的所有信息,但是我们需要再进行一次转换来过滤掉null元素(因为我们根本不想为这些声明关联)并拉入我们需要填充资源参数的其他数据:

resource "azurerm_subnet_network_security_group_association" "nsg_association" {
  for_each = {
    for subnet_key, nsg_key in local.subnet_nsgs : subnet_key => {
      subnet_id = azurerm_subnet.subnet[subnet_key].id
      nsg_id    = azurerm_network_security_group.nsg[nsg_key].id
    }
    if nsg_key != null
  }

  subnet_id                 = each.value.subnet_id
  network_security_group_id = each.value.nsg_id
}

This last for expression is swapping the subnet and NSG keys for the IDs that the remote system is using to track them, which is what we'll need for the resource arguments, and also includes the clause if nsg_key != null to filter out the ones that have no associated NSG.最后一个for表达式将子网和 NSG密钥交换为远程系统用来跟踪它们的 ID,这是我们需要的资源参数,还包括子句if nsg_key != null以过滤掉那些没有关联的 NSG。

With all of this done, you should end up with two associations with the following addresses and the appropriate corresponding subnet and NSG IDs:完成所有这些操作后,您应该最终得到两个与以下地址以及相应的子网和 NSG ID 的关联:

  • azurerm_subnet_network_security_group_association.nsg_association["subnet1"]
  • azurerm_subnet_network_security_group_association.nsg_association["subnet2"]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM