hashicorp / terraform-provider-azurerm

Terraform provider for Azure Resource Manager
https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs
Mozilla Public License 2.0
4.6k stars 4.65k forks source link

azurerm_application_gateway: Unable to create http and https listeners in application gateway #25645

Open vikas027 opened 7 months ago

vikas027 commented 7 months ago

Is there an existing issue for this?

Community Note

Terraform Version

1.7.4

AzureRM Provider Version

3.99.0

Affected Resource(s)/Data Source(s)

azurerm_application_gateway

Terraform Configuration Files

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

  request_routing_rule {
    name                        = local.http_request_routing_rule_name
    priority                    = 9
    rule_type                   = "Basic"
    http_listener_name          = local.http_listener_name
  }

  http_listener {
    name                           = local.https_listener_name
    frontend_ip_configuration_name = local.frontend_ip_configuration_name
    frontend_port_name             = local.https_frontend_port_name
    protocol                       = "Https"
    ssl_certificate_name           = data.azurerm_key_vault_certificate.wildcard.name
  }

  request_routing_rule {
    name                       = local.https_request_routing_rule_name
    priority                   = 10
    rule_type                  = "Basic"
    http_listener_name         = local.https_listener_name
    backend_address_pool_name  = local.backend_address_pool_name
    backend_http_settings_name = local.http_setting_name
  }

Debug Output/Panic Output

Due to my organization's security policies, I can't paste a `DEBUG` log.

If I only have an HTTP listener and a corresponding rule, the code works fine. 

When I add the code to add the HTTPS listener, then it tries to replace the HTTP listener rather than adding it

  # module.gateway.azurerm_application_gateway.network will be updated in-place
  ~ resource "azurerm_application_gateway" "network" {
        id                                = "/subscriptions/<my_sub_id>/resourceGroups/<my_rg>/providers/Microsoft.Network/applicationGateways/<my_app_gw>"
        name                              = "<my_app_gw>"
        tags                              = {}
        # (7 unchanged attributes hidden)

      - http_listener {
          - frontend_ip_configuration_id   = "/subscriptions/<my_sub_id>/resourceGroups/<my_rg>/providers/Microsoft.Network/applicationGateways/<my_app_gw>/frontendIPConfigurations/<my_app_gw>-feip" -> null
          - frontend_ip_configuration_name = "<my_app_gw>-feip" -> null
          - frontend_port_id               = "/subscriptions/<my_sub_id>/resourceGroups/<my_rg>/providers/Microsoft.Network/applicationGateways/<my_app_gw>/frontendPorts/<my_app_gw>-httpfeport" -> null
          - frontend_port_name             = "<my_app_gw>-httpfeport" -> null
          - host_names                     = [] -> null
          - id                             = "/subscriptions/<my_sub_id>/resourceGroups/<my_rg>/providers/Microsoft.Network/applicationGateways/<my_app_gw>/httpListeners/<my_app_gw>-httplstn" -> null
          - name                           = "<my_app_gw>-httplstn" -> null
          - protocol                       = "Http" -> null
          - require_sni                    = false -> null
        }
      + http_listener {
          + frontend_ip_configuration_id   = (known after apply)
          + frontend_ip_configuration_name = "<my_app_gw>-feip"
          + frontend_port_id               = (known after apply)
          + frontend_port_name             = "<my_app_gw>-httpsfeport"
          + host_names                     = []
          + id                             = (known after apply)
          + name                           = "<my_app_gw>-httpslstn"
          + protocol                       = "Https"
          + ssl_certificate_id             = (known after apply)
          + ssl_certificate_name           = "<my_ssl_cert>"
          + ssl_profile_id                 = (known after apply)
        }
      + http_listener {
          + frontend_ip_configuration_id   = "/subscriptions/<my_sub_id>/resourceGroups/<my_rg>/providers/Microsoft.Network/applicationGateways/<my_app_gw>/frontendIPConfigurations/<my_app_gw>-feip"
          + frontend_ip_configuration_name = "<my_app_gw>-feip"
          + frontend_port_id               = "/subscriptions/<my_sub_id>/resourceGroups/<my_rg>/providers/Microsoft.Network/applicationGateways/<my_app_gw>/frontendPorts/<my_app_gw>-httpfeport"
          + frontend_port_name             = "<my_app_gw>-httpfeport"
          + host_names                     = []
          + id                             = "/subscriptions/<my_sub_id>/resourceGroups/<my_rg>/providers/Microsoft.Network/applicationGateways/<my_app_gw>/httpListeners/<my_app_gw>-httplstn"
          + name                           = "<my_app_gw>-httplstn"
          + protocol                       = "Http"
        }

        # (13 unchanged blocks hidden)
    }

Expected Behaviour

Terraform should create two listeners, one for HTTP and another for HTTPS.

Actual Behaviour

Terraform tries to recreate the existing HTTP listener

Steps to Reproduce

No response

Important Factoids

No response

References

No response

teowa commented 6 months ago

Hi @vikas027 , there is a message from the provider doc, in conclusion, if we are adding a listener, the provider will only send the two listeners to API, the remove is only a display issue in Terraform side, the real http-listener will not be removed or recreated, only new one will be added :

The backend_address_pool, backend_http_settings, http_listener, private_link_configuration, request_routing_rule, redirect_configuration, probe, ssl_certificate, and frontend_port properties are Sets as the service API returns these lists of objects in a different order from how the provider sends them. As Sets are stored using a hash, if one value is added or removed from the Set, Terraform considers the entire list of objects changed and the plan shows that it is removing every value in the list and re-adding it with the new information. Though Terraform is showing all the values being removed and re-added, we are not actually removing anything unless the user specifies a removal in the configfile.

Hope this may help, thanks.

vikas027 commented 6 months ago

Hello @teowa , Please try it out, in real Terraform fails and throws an error.