Как удалить элемент декартова произведения двух списков в Terraform?

Я хотел бы создать набор правил сетевой безопасности (nsg) в Azure между разными подсетями с помощью Terraform. Для этого я написал следующий код:

#here, a set of subnets are created according to the value of count. 
resource "azurerm_subnet" "mysubnets" {
    count = var.subnet_number
    name = join("-", ["subnet", count.index])
    resource_group_name = var.rgname
    virtual_network_name = azurerm_virtual_network.Global_VNet.name
    address_prefix = join(".", ["10.0", "${count.index}", "0/24"])
}

product переменная ниже создана для создания правила nsg с парами подсетей. Это позволяет перебирать пару подсетей. Я получаю address_prefixes внутри объявления ресурса azurerm_network_security_rule

locals {
  product = "${setproduct(azurerm_subnet.mysubnets, azurerm_subnet.mysubnets)}"
}

resource "azurerm_network_security_rule" "myNSGrule" {
      count                       = var.subnet_number * var.subnet_number
      source_address_prefix       = lookup(element(local.product, count.index)[0],"address_prefix")
      destination_address_prefix  = lookup(element(local.product, count.index)[1],"address_prefix")
      name                        = join("-", ["nsg","${count.index}"])
      priority                    = 100 + count.index
      direction                   = "Outbound"
      access                      = "Allow"
      protocol                    = "*"
      source_port_range           = "*"
      destination_port_range      = "*"
      resource_group_name         = var.rgname
      network_security_group_name = azurerm_network_security_group.myNSG.name

}


resource "azurerm_virtual_network" "Global_VNet" {
  name                = var.vnetname
  resource_group_name = var.rgname
  address_space       = var.VNetAddressSpace
  location            = var.location
}

resource "azurerm_network_security_group" "myNSG" {
  name                = join("-", ["${var.rgname}", "nsg"])
  location            = var.location
  resource_group_name = var.rgname
}


#NSG subnet association
 resource "azurerm_subnet_network_security_group_association" "LabNSGAssoc" {
  count                     = var.subnet_number
  subnet_id                 = azurerm_subnet.mysubnets[count.index].id
  network_security_group_id = azurerm_network_security_group.myNSG.id
} 

Я хочу избежать правил nsg, в которых префикс назначения и источника идентичны, как показано ниже:  введите описание изображения здесь

Я пробовал несколько разных функций Terraform, но не нашел решения. Есть ли у вас какие-либо идеи?


person MoonHorse    schedule 06.05.2020    source источник
comment
Неясно, как конфигурация относится к вопросу, но похоже, что вы спрашиваете, как создать карту из списка, где каждый элемент является ключом, а массив каждого элемента, который не идентичен ключу, является значением . Это точно?   -  person Matt Schuchard    schedule 06.05.2020
comment
Я думаю, что в переменной набора все элементы разные. Но идея у вас есть. Я пробовал функцию отличного () с отличным (setproduct (azurerm_subnet.mysubnets, azurerm_subnet.mysubnets)). Но это не устраняет. Я добавлю еще несколько комментариев, чтобы прояснить это.   -  person MoonHorse    schedule 06.05.2020
comment
Без конкретной информации о вашей конфигурации вы должны иметь возможность делать что-нибудь с лямбдой, например: [for i, j in zipmap(<subnet_list>, <subnet_list>): {i: j} if i != j]. Хотя это, вероятно, сработает, это также кажется неоптимальным, поскольку я размышляю о вашей конфигурации и просто наплевываю на нее.   -  person Matt Schuchard    schedule 06.05.2020
comment
я пытаюсь реализовать этот алгоритм в Terraform   -  person MoonHorse    schedule 06.05.2020


Ответы (1)


Вы можете фильтровать коллекцию, используя необязательное предложение if в for выражении :

locals {
  product = [
    for pair in setproduct(azurerm_subnet.mysubnets, azurerm_subnet.mysubnets) : pair
    if pair[0] != pair[1]
  ]
}

Предложение if отфильтровывает любые элементы, для которых данное условие не выполняется, поэтому с указанным выше условием результат будет включать только те элементы, у которых первый и второй элементы pair различны.

person Martin Atkins    schedule 08.05.2020
comment
В этом цикле я получил две записи одного и того же правила брандмауэра с разными приоритетами, хотя я избегаю правил NSG, в которых адрес назначения и префикс источника идентичны. - person MoonHorse; 25.05.2020
comment
Как ни странно, создается такое же количество правил nsg, хотя оно должно быть меньше, поскольку должно устранять правила nsg, в которых адрес назначения и префикс источника идентичны - person MoonHorse; 25.05.2020
comment
Если вы ничего не изменили, кроме выражения local.product, выражение count в вашем правиле безопасности будет неверным. Вы можете попробовать использовать length(local.product) вместо var.subnet_number * var.subnet_number, чтобы получить число после фильтрации, хотя это не сработает, если подсети неизвестны во время планирования. Если вам нужна дополнительная помощь с count здесь, я бы предложил задать новый вопрос, потому что он отличается от того, что вы изначально задавали здесь. - person Martin Atkins; 26.05.2020
comment
верно. Я получил ошибку: недопустимый аргумент счетчика в строке 37 network.tf в ресурсе azurerm_network_security_rule myNSGrule: 37: count = length (local.product) Значение счетчика зависит от атрибутов ресурса, которые не могут быть определены до тех пор, пока не будут применены, поэтому Terraform не может предсказать, сколько экземпляров будет создан. Чтобы обойти это, используйте аргумент -target, чтобы сначала применить только те ресурсы, от которых зависит счетчик. - person MoonHorse; 26.05.2020
comment
он работает с правильным числом отсчетов. var.subnet_number * var.subnet_number - var.subnet_number работает как число счетчика. - person MoonHorse; 26.05.2020