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.47k stars 4.56k forks source link

Application Gateway with multiple request_routing_rule behaviour #13878

Open mne-unitn opened 2 years ago

mne-unitn commented 2 years ago

Community Note

Terraform (and AzureRM Provider) Version

Terraform v1.0.8 provider registry.terraform.io/hashicorp/azurerm v2.82.0

Affected Resource(s)

Terraform Configuration Files

resource "azurerm_resource_group" "rg" {
  name      = "rg-appgw-test"
  location  = "westeurope"
}

resource "azurerm_virtual_network" "myvnet" {
  name                = "test-vnet"
  resource_group_name = azurerm_resource_group.rg.name
  location            = "westeurope"
  address_space       = [ "10.255.0.0/23" ] 
}

resource "azurerm_subnet" "mysubnet" {
  name                 = "mysubnet-test-appgw"
  virtual_network_name = azurerm_virtual_network.myvnet.name
  resource_group_name  = azurerm_resource_group.rg.name

  address_prefixes = [ "10.255.0.0/24" ]
}

resource "azurerm_public_ip" "pip-appgw" {
  name                = "pip-myappgw-test"
  resource_group_name = azurerm_resource_group.rg.name
  location            = "westeurope"
  allocation_method   = "Static"
  sku                 = "Standard"
}

resource "azurerm_application_gateway" "myappgw" {
    location            = "westeurope"
    name                = "myappgw-test"
    resource_group_name = azurerm_resource_group.rg.name
    enable_http2        = true

    sku {
        name = "Standard_v2"
        tier = "Standard_v2"
        capacity = 1
    }
    frontend_ip_configuration {
        name                          = "MyAppGW-IP-Config"
        private_ip_address_allocation = "Dynamic"
        public_ip_address_id          = azurerm_public_ip.pip-appgw.id
    }
    frontend_port {
        name = "port_80"
        port = 80
    }
    frontend_port {
        name = "port_443"
        port = 443
    }
    gateway_ip_configuration {
        name = "myappgw-ip"
        subnet_id = azurerm_subnet.mysubnet.id
    }

    backend_address_pool {
        name = "TestPool1"
        ip_addresses = [ "1.2.3.4", "1.2.3.5" ]    
    }
    backend_address_pool {
        name ="TestPool2"
        ip_addresses = [ "2.3.4.5", "2.3.4.6" ]
    }
    backend_address_pool {
        name ="TestPool3"
        ip_addresses = [ "3.4.5.6", "3.4.5.7" ]
    }

    backend_http_settings {
        name = "Test-http-setting"
        affinity_cookie_name = "Test-affinity-1"
        cookie_based_affinity = "Enabled"
        port = 80
        protocol = "HTTP"
        request_timeout = 120
    }
    http_listener {
        name = "HttpListener1"
        frontend_ip_configuration_name = "MyAppGW-IP-Config"
        frontend_port_name = "port_80"
        protocol = "Http"
        host_name = "test1.com"
    }
    http_listener {
        name = "HttpListener2"
        frontend_ip_configuration_name = "MyAppGW-IP-Config"
        frontend_port_name = "port_80"
        protocol = "Http"
        host_name = "test2.com"
    }
    http_listener {
        name = "HttpListener3"
        frontend_ip_configuration_name = "MyAppGW-IP-Config"
        frontend_port_name = "port_80"
        protocol = "Http"
        host_name = "test3.com"
    }

    request_routing_rule {
        name = "RoutingRule1"
        rule_type = "Basic"
        http_listener_name = "HttpListener1"
        backend_address_pool_name = "TestPool1"
        backend_http_settings_name = "Test-http-setting"
    }
#    request_routing_rule {
#        name = "RoutingRule2"
#        rule_type = "Basic"
#        http_listener_name = "HttpListener2"
#        backend_address_pool_name = "TestPool2"
#        backend_http_settings_name = "Test-http-setting"
#    }
}

Debug Output

Panic Output

Expected Behaviour

When I enable the second request_routing_rule (the one commented out), I would expect terraform to just add that specific rule.

Actual Behaviour

When I enable the second request_routing_rule (the one commented out), terraform destroys all the request_routing_rules and recreates them.

Steps to Reproduce

  1. terraform apply
  2. uncomment the last rows with the second request_routing_rule
  3. terraform apply

    Important Factoids

References

aristosvo commented 2 years ago

Hi @mne-unitn, thanks for this issue. Do you experience this on a functional level as well?

To be honest, I think this might be a technical issue with the plan construction rather than that it's impacting the request_routing_rule itself (which already existed on Azure) and its behaviour. When the resource is updated, all rules are expanded for the Azure API at once, and send to the Azure API combined with all other settings. Azure takes care of the updates on the resource, and I expect that only the second rule is added and the first remains functional during that period.

To fix the plan, we'd have to make sure that the items are stored in state with an index value calculated by the hash of the attributes of the set which are retrieved upon a plan. I'm unsure whether and how we can make this work, but wanted to give you already a heads-up that it might not influence the behaviour with Azure.

@tombuildsstuff Do you think we'd be able to fix this, or are we limited by the Terraform core? I'm not familiar enough with the TypeSet to know on first sight if this is possible or not for a complicated schema like this:

"request_routing_rule": {
    Type:     pluginsdk.TypeSet,

    Required: true,
    MinItems: 1,
    Elem: &pluginsdk.Resource{
        Schema: map[string]*pluginsdk.Schema{
            "name": {
                Type:     pluginsdk.TypeString,
                Required: true,
            },

            "rule_type": {
                Type:     pluginsdk.TypeString,
                Required: true,
                ValidateFunc: validation.StringInSlice([]string{
                    string(network.ApplicationGatewayRequestRoutingRuleTypeBasic),
                    string(network.ApplicationGatewayRequestRoutingRuleTypePathBasedRouting),
                }, false),
            },

            "http_listener_name": {
                Type:     pluginsdk.TypeString,
                Required: true,
            },

            "backend_address_pool_name": {
                Type:     pluginsdk.TypeString,
                Optional: true,
            },

            "backend_http_settings_name": {
                Type:     pluginsdk.TypeString,
                Optional: true,
            },

            "url_path_map_name": {
                Type:     pluginsdk.TypeString,
                Optional: true,
            },

            "redirect_configuration_name": {
                Type:         pluginsdk.TypeString,
                Optional:     true,
                ValidateFunc: validation.StringIsNotEmpty,
            },

            "rewrite_rule_set_name": {
                Type:         pluginsdk.TypeString,
                Optional:     true,
                ValidateFunc: validation.StringIsNotEmpty,
            },

            "backend_address_pool_id": {
                Type:     pluginsdk.TypeString,
                Computed: true,
            },

            "backend_http_settings_id": {
                Type:     pluginsdk.TypeString,
                Computed: true,
            },

            "http_listener_id": {
                Type:     pluginsdk.TypeString,
                Computed: true,
            },

            "id": {
                Type:     pluginsdk.TypeString,
                Computed: true,
            },

            "url_path_map_id": {
                Type:     pluginsdk.TypeString,
                Computed: true,
            },

            "redirect_configuration_id": {
                Type:     pluginsdk.TypeString,
                Computed: true,
            },

            "rewrite_rule_set_id": {
                Type:     pluginsdk.TypeString,
                Computed: true,
            },
        },
    },
},
mne-unitn commented 2 years ago

Hi @mne-unitn, thanks for this issue. Do you experience this on a functional level as well?

I think you are right. Looking at the logs on the Azure side, it seems the api recognizes the correct diff and applies only the different configuration parts.

thank you

eissko commented 2 years ago

Hello @mne-unitn, @aristosvo please any update on this?

I know there are related issues and some statements there promised this being fixed with coming 3.x release which apparently didn't happen. The problem still persists with even newest AzureRM provider and terraform core.

It behaves as described here https://github.com/hashicorp/terraform-provider-azurerm/issues/16136

Type result backend_address_pool ✔ works, only one change detected backend_http_settings ❌ does NOT work, all settings deleted and readded http_listener ❌ does NOT work, all settings deleted and readded probe ✔ works, only one change detected redirect_configuration ❌ does NOT work, all settings deleted and readded request_routing_rule ❌ does NOT work, all settings deleted and readded url_path_map ❌ does NOT work, all settings deleted and readded

Also related - https://github.com/hashicorp/terraform-provider-azurerm/issues/6896#issuecomment-1083586519

Thank you for any answer...