Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

azurerm_network_interface_application_gateway_backend_address_pool_association backend_address_pool addressable key #16855

Open
1 task done
johnastiles opened this issue May 18, 2022 · 12 comments

Comments

@johnastiles
Copy link

Is there an existing issue for this?

  • I have searched the existing issues

Community Note

  • Please vote on this issue by adding a 👍 reaction to the original issue to help the community and maintainers prioritize this request
  • Please do not leave "+1" or "me too" comments, they generate extra noise for issue followers and do not help prioritize the request
  • If you are interested in working on this issue or have submitted a pull request, please leave a comment

Terraform Version

1.1.9

AzureRM Provider Version

3.6.0

Affected Resource(s)/Data Source(s)

azurerm_network_interface_application_gateway_backend_address_pool_association

Terraform Configuration Files

resource "azurerm_resource_group" "example" {
  name     = "example-resources"
  location = "West Europe"
}

resource "azurerm_virtual_network" "example" {
  name                = "example-network"
  address_space       = ["10.0.0.0/16"]
  location            = azurerm_resource_group.example.location
  resource_group_name = azurerm_resource_group.example.name
}

resource "azurerm_subnet" "frontend" {
  name                 = "frontend"
  resource_group_name  = azurerm_resource_group.example.name
  virtual_network_name = azurerm_virtual_network.example.name
  address_prefixes     = ["10.0.1.0/24"]
}

resource "azurerm_subnet" "backend" {
  name                 = "backend"
  resource_group_name  = azurerm_resource_group.example.name
  virtual_network_name = azurerm_virtual_network.example.name
  address_prefixes     = ["10.0.2.0/24"]
}

resource "azurerm_public_ip" "example" {
  name                = "example-pip"
  location            = azurerm_resource_group.example.location
  resource_group_name = azurerm_resource_group.example.name
  allocation_method   = "Dynamic"
}

# since these variables are re-used - a locals block makes this more maintainable
locals {
  backend_address_pool_name      = "${azurerm_virtual_network.example.name}-beap"
  frontend_port_name             = "${azurerm_virtual_network.example.name}-feport"
  frontend_ip_configuration_name = "${azurerm_virtual_network.example.name}-feip"
  http_setting_name              = "${azurerm_virtual_network.example.name}-be-htst"
  listener_name                  = "${azurerm_virtual_network.example.name}-httplstn"
  request_routing_rule_name      = "${azurerm_virtual_network.example.name}-rqrt"
}

resource "azurerm_application_gateway" "network" {
  name                = "example-appgateway"
  resource_group_name = azurerm_resource_group.example.name
  location            = azurerm_resource_group.example.location

  sku {
    name     = "Standard_Small"
    tier     = "Standard"
    capacity = 2
  }

  gateway_ip_configuration {
    name      = "my-gateway-ip-configuration"
    subnet_id = azurerm_subnet.frontend.id
  }

  frontend_port {
    name = local.frontend_port_name
    port = 80
  }

  frontend_ip_configuration {
    name                 = local.frontend_ip_configuration_name
    public_ip_address_id = azurerm_public_ip.example.id
  }

  backend_address_pool {
    name = local.backend_address_pool_name
  }

  backend_http_settings {
    name                  = local.http_setting_name
    cookie_based_affinity = "Disabled"
    port                  = 80
    protocol              = "Http"
    request_timeout       = 1
  }

  http_listener {
    name                           = local.listener_name
    frontend_ip_configuration_name = local.frontend_ip_configuration_name
    frontend_port_name             = local.frontend_port_name
    protocol                       = "Http"
  }

  request_routing_rule {
    name                       = local.request_routing_rule_name
    rule_type                  = "Basic"
    http_listener_name         = local.listener_name
    backend_address_pool_name  = local.backend_address_pool_name
    backend_http_settings_name = local.http_setting_name
  }
}

resource "azurerm_network_interface" "example" {
  name                = "example-nic"
  location            = azurerm_resource_group.example.location
  resource_group_name = azurerm_resource_group.example.name

  ip_configuration {
    name                          = "testconfiguration1"
    subnet_id                     = azurerm_subnet.frontend.id
    private_ip_address_allocation = "Dynamic"
  }
}

resource "azurerm_network_interface_application_gateway_backend_address_pool_association" "example" {
  network_interface_id    = azurerm_network_interface.example.id
  ip_configuration_name   = "testconfiguration1"
  backend_address_pool_id = azurerm_application_gateway.network.backend_address_pool[0].id
}

Debug Output/Panic Output

│ Error: Cannot index a set value
│
│   on appgateway.tf line 185, in resource "azurerm_network_interface_application_gateway_backend_address_pool_association" "vm":
  185:   backend_address_pool_id = azurerm_application_gateway.network.backend_address_pool[0].id
│
│ Block type "backend_address_pool" is represented by a set of objects, and set elements do not have addressable keys. To find elements matching specific criteria, use a "for" expression with an "if" clause.

Expected Behaviour

Application Gateway backend pool association should be made with the virtual machine nic.

Actual Behaviour

States that backend_address_pool does not have addressable keys.

Steps to Reproduce

Terraform plan

Important Factoids

This worked as expected in Azure Provider 2.99.0

References

https://github.com/MicrosoftDocs/azure-dev-docs/issues/770
https://github.com/MicrosoftDocs/azure-dev-docs/issues/752

@github-actions github-actions bot removed the bug label May 18, 2022
@Iduoad

This comment was marked as duplicate.

@Loth4r
Copy link

Loth4r commented Jun 1, 2022

Managed to bypass this issue by below 'hack' that is exploiting the fact that backend_address_pool id (as many other azure resources) is constructed/consists backend's pool name:

resource "azurerm_network_interface_application_gateway_backend_address_pool_association" "example" {
  network_interface_id    = azurerm_network_interface.example.id
  ip_configuration_name   = "testconfiguration1"
  backend_address_pool_id = [for value in tolist(azurerm_application_gateway.network.backend_address_pool.*.id) : value if length(regexall(lower(local.backend_address_pool_name), value)) > 0][0]
}

Above code uses conditional for expression that iterates through list of backend_addres_pool id's (created with usage of splat operator) and assigns value of the only element that contains backend_addres_pool_name (used lenght(regexall(...)) to check that)

Not ideal, not clean, but working for me...

@kutscherma
Copy link

Same here.

The solution above works but it takes a long time to create.

@Loth4r do you have the same problem?

@Loth4r
Copy link

Loth4r commented Jun 6, 2022

Same here.

The solution above works but it takes a long time to create.

@Loth4r do you have the same problem?

No such issue on my end.

@stimms
Copy link

stimms commented Jun 14, 2022

Replicated the Cannot index a set value issue both 3.3.0 and 3.10.0 of hashicorp/azurerm. Workaround appears to work but I don't know about the speed yet

@AokigaharaX
Copy link

AokigaharaX commented Jun 24, 2022

In 3.11.0 they updated the documentation as stated below:

resource "azurerm_network_interface_application_gateway_backend_address_pool_association" "example" {
  network_interface_id    = azurerm_network_interface.example.id
  ip_configuration_name   = "testconfiguration1"
  backend_address_pool_id = tolist(azurerm_application_gateway.network.backend_address_pool).0.id
}

@Loth4r
Copy link

Loth4r commented Jun 28, 2022

In 3.11.0 they updated the documentation as stated below:

resource "azurerm_network_interface_application_gateway_backend_address_pool_association" "example" {
  network_interface_id    = azurerm_network_interface.example.id
  ip_configuration_name   = "testconfiguration1"
  backend_address_pool_id = tolist(azurerm_application_gateway.network.backend_address_pool).0.id
}

Above will most likely work, but in scenario where you have only one backend_address_pool defined on your app gateway. If you have more then in my opinion it can lead to some random results as tolist() function on a set does not guarantee order:

Pass a set value to tolist to convert it to a list. Since set elements are not ordered, the resulting list will have an undefined order that will be consistent within a particular run of Terraform.

see (https://www.terraform.io/language/functions/tolist)

What could improve setting up backend_addres_pool association here would be reconsidering how azurerm_application_gateway component should be exporting backend_address_pool block. Currently it is exporting list of backend_address_pool as follows:

A backend_address_pool block exports the following:

id - The ID of the Backend Address Pool.

Maybe changing type to map that has a name of backend address pool as a key would do the trick? Then it could look more like below:

resource "azurerm_network_interface_application_gateway_backend_address_pool_association" "example" {
  network_interface_id    = azurerm_network_interface.example.id
  ip_configuration_name   = "testconfiguration1"
  backend_address_pool_id = azurerm_application_gateway.network.backend_address_pool[<backend_pool_name>].id
}

@skinlayers
Copy link

skinlayers commented Oct 19, 2022

Neither solutions is working for me:

│ Error: Incorrect attribute value type
│
│   on vmss.tf line 58, in resource "azurerm_linux_virtual_machine_scale_set" "vmss":
│   58:       application_gateway_backend_address_pool_ids = [for value in tolist(azurerm_application_gateway.network.backend_address_pool.*.id) : value if length(regexall(lower(local.backend_address_pool_name), value)) > 0][0]
│     ├────────────────
│     │ azurerm_application_gateway.network.backend_address_pool is set of object with 1 element
│     │ local.backend_address_pool_name is "vmss-vnet-beap"
│
│ Inappropriate value for attribute "application_gateway_backend_address_pool_ids": set of string required.
│ Error: Incorrect attribute value type
│
│   on vmss.tf line 58, in resource "azurerm_linux_virtual_machine_scale_set" "vmss":
│   58:       application_gateway_backend_address_pool_ids = tolist(azurerm_application_gateway.network.backend_address_pool).0.id
│     ├────────────────
│     │ azurerm_application_gateway.network.backend_address_pool is set of object with 1 element
│
│ Inappropriate value for attribute "application_gateway_backend_address_pool_ids": set of string required.

However, it works if I use:

      application_gateway_backend_address_pool_ids = azurerm_application_gateway.network.backend_address_pool.*.id

@GeoffCraigVRU
Copy link

GeoffCraigVRU commented Oct 27, 2022

We ran into the ordering issue with tolist(). In order to get around it we created a local variable. backend_nics was the output of the VM NICs we wanted in or backend pool.

locals { be_to_nic = flatten([for k in tolist(azurerm_application_gateway.app_gateway.backend_address_pool).*.id : [ for l, w in var.backend_nics : { backend_pool_id = k nic_id = w.id nic_ipconfig_name = w.ip_configuration[0].name } ] ]) }

Then in the terraform we did this.

resource "azurerm_network_interface_application_gateway_backend_address_pool_association" "nic_app_be_association" { for_each = tomap({ for k in local.be_to_nic : "${k.backend_pool_id}${k.nic_id}" => k }) network_interface_id = each.value.nic_id ip_configuration_name = each.value.nic_ipconfig_name backend_address_pool_id = each.value.backend_pool_id }

There may be a better way, but this worked for us.

@jajera
Copy link

jajera commented Nov 11, 2022

encountered this too. this workaround suggested above worked.

tolist(azurerm_application_gateway.network.backend_address_pool).0.id

@devanshujoshi139
Copy link

You can use one function from terraform as below:

resource "azurerm_network_interface_application_gateway_backend_address_pool_association" "nic-assoc" {
backend_address_pool_id = one(azurerm_application_gateway.aggateway.backend_address_pool).id
ip_configuration_name = "web-linuxvm-ipconfig"
network_interface_id = azurerm_network_interface.web_linuxvm_nic.id
}

@djryanj
Copy link
Contributor

djryanj commented Apr 4, 2024

@devanshujoshi139 that only works if there's a single backend address pool. As soon as there are more, that will fail.

@GeoffCraigVRU it's probably relevant that the backend address pool ID's are easy to predict. In my case, it was a lot easier to just do this:

resource "azurerm_network_interface_application_gateway_backend_address_pool_association" "nic1" {
  backend_address_pool_id = "${azurerm_application_gateway.this.id}/backendAddressPools/bapName"
  ip_configuration_name   = "ipConfigName"
  network_interface_id    = azurerm_network_interface.vm1nic1.id
}

Ideally, even though the Azure API returns the data in an unordered list (which is why the backend_address_pools attribute is a set) the AzureRM provider would be able to intelligently make it findable by name since it stores it as a hash (apparently) which won't change no matter what order things come out of the API in and it would be easy to parse the name off the end of those identifiers. I'm sure there's a reason they haven't done this, but a little sprinkle of syntactic sugar might be nice.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests